トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索   ヘルプ   最終更新のRSS

ブログ検索システム の変更点

Top / ブログ検索システム

#freeze
#access
#analog

※ 以下は限定公開のドキュメントが多いです。ご不便おかけします。

&pgid(,RSSを使ったブログ・Wikiの解析);

*ブログ検索システム [#yea1dc2a]
-&pgid(,RSSを使ったブログ・Wikiの解析); の応用編として、http://shower.human.waseda.ac.jp/~m-kouki/ 以下のコンテンツを対象とした検索エンジンを作ってみます。

-目次
#contents

**URLデータベース設計 [#ffb208ee]
-MySQL のデータベース mkouki を使います。
 mysql -u root -p
 (パスワード)
 use mkouki;
***RSSテーブル [#z8aa5229]
|BGCOLOR(white):RSSのアドレスのID |BGCOLOR(white):RSSのアドレス |
|rss_id|rss_url|

-テーブルを作る
 CREATE TABLE mysearch_rss( rss_id int auto_increment, 
  rss_url text character set utf8, index(rss_id) );
 show tables;
--ここでは、カラム rss_id は[[オートインクリメント:http://www.dbonline.jp/mysql/table/index6.html]] の設定になっています(自動的にエントリのIDをふります)。
-データを追加
 INSERT INTO mysearch_rss (rss_url)
 VALUE('http://shower.human.waseda.ac.jp/~m-kouki/blog/atom.xml');
 INSERT INTO mysearch_rss (rss_url)
 VALUE('http://shower.human.waseda.ac.jp/~m-kouki/pukiwiki/index.php?cmd=rss&ver=1.0');
 select * from mysearch_rss limit 30;
--ここでは、手動でブログとwikiのRSSのアドレスを入れました。オートインクリメントで、rss_id は自動的に番号がつきます。

***エントリーテーブル [#o7205775]
|BGCOLOR(white):エントリーのID |BGCOLOR(white):エントリーのタイトル |BGCOLOR(white):エントリーのアドレス |BGCOLOR(white):エントリーの属性 |BGCOLOR(white):エントリーがインデクシング済みかどうか |
|entry_id|entry_title|entry_url|entry_type|entry_indexing|
--エントリーの属性は、とりあえず「記事0、書類1、プログラム2」と決めます。
--インデクシングがまだなら0、済みなら1、とりあえず今回のシステムでは全文検索をするので、以下は全て0を代入します。
-テーブルを作る
 CREATE TABLE mysearch_entry( entry_id int auto_increment,
  entry_title text character set utf8,
  entry_url text character set utf8,
  entry_type int, entry_indexing int, index(entry_id) );
-RSSでは取得できない、トップページ以下のURLを、とりあえず手動で追加します。 → [[コマンド:http://shower.human.waseda.ac.jp/~m-kouki/texts/mysearch_entry.txt]]
 select entry_id, entry_title, entry_type from mysearch_entry limit 30;


**クローリング [#ca832b97]
***URLデータ更新 [#q535836e]
-RSSのURLを参考に、各エントリーのタイトルとURLを取得して、テーブル mysearch_entry に格納します。
--'''[[クラスパスを通して:http://shower.human.waseda.ac.jp/~m-kouki/pg/mysearch_classpath.txt]]'''、'''[[CrawlRSS.java:http://shower.human.waseda.ac.jp/~m-kouki/pg/mysearch/CrawlRSS.java.txt]]''' を実行
-プログラムの格納場所は、shower の mysearch/ とします。
-&color(red){entry_url カラムの設定を「[[重複禁止:http://q.hatena.ne.jp/1183719569]]」にしておけば、重複のチェックは不要};のようです。

***本文データ更新 [#lb5b5b0d]
-エントリーのURLを参考に、本文(とりあえずソースコード全て)を取得して、テキストファイルとして保存します。
--テキストファイル置き場を作って
 mkdir /home/m-kouki/mysearch/filelog
--'''[[CrawlEntry.java:http://shower.human.waseda.ac.jp/~m-kouki/pg/mysearch/CrawlEntry.java.txt]]''' を実行
 chmod 755 /home/m-kouki/mysearch/filelog/*

**検索 [#h996c7dc]
***検索窓 [#cfe3dbbc]
-[[ここ:http://shower.human.waseda.ac.jp/~m-kouki/]] のHTMLを参照。
-検索窓に入力したクエリは '''[[mysearch.cgi:http://shower.human.waseda.ac.jp/~m-kouki/pg/mysearch/mysearch.txt]]''' が受け取り、プログラムから'''[[mysearch.sh:http://shower.human.waseda.ac.jp/~m-kouki/pg/mysearch/mysearch.sh.txt]]''' を呼び出します。
--プログラムの格納場所は、shower の public_html/cgi-bin/ とします。
--[[パーミッションの設定:http://www7.big.or.jp/~jawa/tips/access.html]]に注意してください。
--[[perl から シェルスクリプトを呼び出す危険性:http://www.ipa.go.jp/security/awareness/vendor/programming/a04_02_main.html]]
---検索窓の入力内容を、そのままシェルに引数で渡すのは危険です。ここではperlプログラムがクエリファイルを書き出し、Javaプログラムが同名ファイルを読み込むようにしています(大規模な検索システムでは使えない方法です)。
-CGIではなく、Java サーブレットで実装する方法もあります('''[[tomcat導入メモ:http://shower.human.waseda.ac.jp/~m-kouki/pukiwiki/index.php?tomcat%E5%B0%8E%E5%85%A5%E3%83%A1%E3%83%A2]]''')。試してみてください。

***キーワードマッチング [#k534f139]
-上のシェルスクリプトから、'''[[WordSearch.java:http://shower.human.waseda.ac.jp/~m-kouki/pg/mysearch/WordSearch.java.txt]]''' を呼び出し、キーワードマッチングをして、'''[[SearchResult.html:http://shower.human.waseda.ac.jp/~m-kouki/pg/mysearch/SearchResult.html]]'''を書き出します。
--プログラムの格納場所は、shower の public_html/cgi-bin/ とします。
--パブリックな領域においたプログラムの中にパスワードを直書きするのはよくないので、&color(red){public ディレクトリ以外においたパスワードファイルを参照する};ようにします。
--文字化け対処として、文字コードを指定可能なファイル入出力ストリームを使います。
---[[@IT:Javaの文字化け対策FAQ(3) DBや入力フォームで文字化けする場合の対処方法:http://www.atmarkit.co.jp/fjava/rensai3/mojibake03/mojibake03.html]]

-ここまでの実行が終わったら、処理は再び '''[[mysearch.cgi:http://shower.human.waseda.ac.jp/~m-kouki/pg/mysearch/mysearch.txt]]''' に戻り、'''[[SearchResult.html:http://shower.human.waseda.ac.jp/~m-kouki/pg/mysearch/SearchResult.html]]''' を読み込んで、ブラウザに表示します。

***課題 [#f72d1cf2]
-&color(red){スペースで区切った複数のクエリに対して、AND検索ができるようにしましょう。};
-''&color(red){テキスト解析技術を使って、独自のサービスを提供してみましょう。};''


**HTMLパース [#db98246a]
-[[HTMP Parser:http://www.mlab.im.dendai.ac.jp/~yamada/ir/HTMLParser/]] を参考に、パーサをインストールします。
--[[ここ:http://htmlparser.sourceforge.net/]] の Downloads -> Older の  htmlparser1_6_20060610.zip をダウンロードしました。解凍するときに avast! が警告するファイルは、全てその場で削除しました。
--lib フォルダ内の htmlparser.jar のみ使用します(クラスパスを通しておきます)。
 CLASSPATH=$CLASSPATH:/home/m-kouki/mysearch/htmlparser.jar
 export CLASSPATH
-[[SimpleParser3.java:http://www.mlab.im.dendai.ac.jp/~yamada/ir/HTMLParser/SimpleParser3.html]] (東京電機大 山田先生)を試してみます。
--タイトルを取得するには
 java SimpleParser3 http://shower.human.waseda.ac.jp/~m-kouki/ TITLE
--本文を取得するには
 java SimpleParser3 http://shower.human.waseda.ac.jp/~m-kouki/
---76行目 System.out.println("text: \"" + text.getText() + "\""); だけを出力するようにすればOK。

**URL追跡 [#cf956488]
-[[lynx:http://2php.jp/install/lynx.html]] を使って、トップページから順番に、URLを辿って全てのコンテンツを取得してみます。
--RSS のない、[[トップページ:http://shower.human.waseda.ac.jp/~m-kouki/]] 以下のページや [[各資料:http://shower.human.waseda.ac.jp/~m-kouki/pukiwiki/index.php?%E8%B3%87%E6%96%99%E3%81%BE%E3%81%A8%E3%82%81]] のアドレスを取得することが目的です。
--「m-kouki」が含まれているアドレスのみを取得対象とします。
***lynx [#e857ded8]
-lynx でウェブページにアクセスするには、
 lynx -dump http://shower.human.waseda.ac.jp/~m-kouki/
-
   .
   .
   k-lab_wiki [23] 兇wiki
     _________________________________________________________________
   Copyright(C) [24]MIYAZAWA Kouki All Rights Reserved.
 
 繚
   1. http://shower.human.waseda.ac.jp/~m-kouki/blog/
   2. http://shower.human.waseda.ac.jp/~m-kouki/pukiwiki/index.php?FrontPage
   3. http://shower.human.waseda.ac.jp/~m-kouki/reference/index.html
   4. http://shower.human.waseda.ac.jp/~m-kouki/kensyu/index.html
   5. http://shower.human.waseda.ac.jp/~m-kouki/collaboration/index.html
   .
   .

--指定したウェブサイトの文字コードが、[[lynx の設定ファイルの文字コード:http://tontokaimo-lab.cocolog-nifty.com/strayinglynx/2005/05/lynx_8689.html]] と異なる場合、本文が文字化けします。
---とりあえず今回は、最後のリンク情報が取得できればいいので、lynx の設定ファイルは変更しません。

-Basic認証付きのページにアクセスするには、
 lynx -dump -auth=(ID):(パスワード) (URL)

-lynx に xml ファイルのアドレス(RSSなど)を指定すると、正しくURLを取得することができません。以下では、取得した URL を再度 lynx にかけ、出力が得られるかどうかで、URL が正しいかどうかを判定しています。

***java から呼び出す [#w6eacb0a]
-[[javafaq 外部コマンド呼出し:http://javafaq.jp/S103.html]] を参考にして、
--CrawlLynxTest1.java
 import java.io.*;
 
 public class CrawlLynxTest1 {
     public static void main(String[] args) {
         try {
             Process process = Runtime.getRuntime().exec
              ("lynx -dump http://shower.human.waseda.ac.jp/~m-kouki/");
             InputStream is = process.getInputStream();
             BufferedReader br = new BufferedReader(new InputStreamReader(is));
             String line;
             while ((line = br.readLine()) != null) {
                 System.out.println(line);
             }
             is.close();
             br.close();
         } catch (Exception err) {
             System.out.println(err);
         }
     }
 }

***実装 [#hee9d6ae]
-lynx で指定したページのリンクを取得 → 取得したURLが存在するかどうかを確認 → HTML パーサでリンク先のタイトルを取得 → リンク先のファイルの拡張子から属性を判定 → データベースに格納 の流れを再帰的に繰り返します。

-トップページのURLを引数として、各エントリーのタイトル(ファイル名)とURLを取得して、テーブル mysearch_entry に格納します。 
--クラスパスを通して、'''[[CrawlLynx.java:http://shower.human.waseda.ac.jp/~m-kouki/pg/mysearch/CrawlLynx.java.txt]]''' を実行
 CLASSPATH=$CLASSPATH:/home/m-kouki/mysearch/
        mysql-connector-java-5.1.6/mysql-connector-java-5.1.6-bin.jar
 export CLASSPATH
 java CrawlLynx m-kouki http://shower.human.waseda.ac.jp/~m-kouki/ 10
---引数の意味 : http://shower.human.waseda.ac.jp/~m-kouki/ から検索開始、m-kouki の含まれるアドレスのみ、第10階層までクロール
---CrawlRSS.java の実行後に行ってください。CrawlRSS.java ですでに取得済みの、ブログとwikiの記事は、重複URLとなり格納されません。
---タイトルの取得には、[[SimpleParser3.java:http://www.mlab.im.dendai.ac.jp/~yamada/ir/HTMLParser/SimpleParser3.html]] を外部クラスから実行できるようにした、SimpleParser3_2.java を使用しています。
---エントリーの属性は、「書類(txt)1、プログラム(java, m, perl)2、PDF 3、 WORD文書 4、動画(wmv) 5、パワーポイント 6、圧縮ファイル(zip, lzh) 7、その他 0」と決めます。 
--プログラムの格納場所は、shower の mysearch/ とします。 

***改良すべき点 [#odcdd9fc]
-&color(red){lynx の代わりに HTML Parser で A タグのテキストと URL を解析すれば、リンク先のファイルが HTML でなくても正確なタイトルを取得できそうです。};
-&color(red){時間がかかりすぎる。一度検索したリンクは検索しないなど、ループを防ぐ工夫が要るかも。};

**リンク切れを削除 [#m4bd3ba3]
-mysearch_entry テーブルの entry_url カラムを順番に取得して、リンク先が生きているかを確認(lynx が null もしくは Not Found を返さないことを確認) します。
-ついでに、上の追跡検索でヒットしてしまう、検索対象にしたくないページ(wikiのバックアップやBlogのインデックス等)を削除します。
--'''[[deletelinks_title.txt:http://shower.human.waseda.ac.jp/~m-kouki/pg/mysearch/deletelinks_title.txt]]'''
--'''[[deletelinks_url.txt:http://shower.human.waseda.ac.jp/~m-kouki/pg/mysearch/deletelinks_url.txt]]'''
-'''[[DeleteLinks.java:http://shower.human.waseda.ac.jp/~m-kouki/pg/mysearch/DeleteLinks.java.txt]]''' を実行
--上のプログラム中で読み込む deletelinks_url.txt と deletelinks_title.txt は、削除したい URL や タイトルの一部を列挙したファイルです。

**インデックスをつける [#c92c9a5f]
-&pgid(,Lucene導入メモ);

**HTML以外のファイルを取得する [#e3bc3957]
-'''[[CrawlEntry.java:http://shower.human.waseda.ac.jp/~m-kouki/pg/mysearch/CrawlEntry.java.txt]]''' の改良案です('''[[CrawlEntry2.java:http://shower.human.waseda.ac.jp/~m-kouki/pg/mysearch/CrawlEntry2.java.txt]]''')。
-以下は HTMLパーサでは「WARNING: URL ~~ does not contain text」エラーが出ます。そのため、これまでの手法では内容をログファイルにできないため、検索することができません。

***PDFファイルを取得 [#c43b2106]
-[[PDFビューア:http://shower.human.waseda.ac.jp/~m-kouki/pukiwiki/index.php?Linux%E3%82%B5%E3%83%BC%E3%83%90%E9%96%A2%E4%BF%82#t987a734]]
--エントリーの属性が「3」だったときは、wget でダウンロード → Xpdf でPDFファイルをテキストファイルに変換

***PPTとWORDファイルを取得 [#jde4a6fc]
-[[たぽブログ » Word の .doc を .pdf に変換:http://www.farine.mine.nu/~tapo/blog/index.php?itemid=486]]

***ZIPファイルを取得 [#jde4a6fc]

**検索 [#qe305258]
-'''[[WordSearch.java:http://shower.human.waseda.ac.jp/~m-kouki/pg/mysearch/WordSearch.java.txt]]''' の改良案です。

***検索窓でファイルの属性を指定する [#o80492f5]

***表記ゆれ対処 [#f34b8041]
-大文字・小文字など。

**定期クロール [#e6d9c592]
-RSS検索
 cd /home/m-kouki/mysearch/
 CLASSPATH=$CLASSPATH:informa.jar
 CLASSPATH=$CLASSPATH:lib/commons-logging.jar
 CLASSPATH=$CLASSPATH:lib/jdom.jar
 CLASSPATH=$CLASSPATH:htmlparser.jar
 CLASSPATH=$CLASSPATH:mysql-connector-java-5.1.6/mysql-connector-java-5.1.6-bin.jar
 export CLASSPATH
 java CrawlRSS
-追跡検索
 java CrawlLynx m-kouki http://shower.human.waseda.ac.jp/~m-kouki/ 3
 java CrawlLynx m-kouki http://shower.human.waseda.ac.jp/~m-kouki/blog/archives.html 2
-削除とファイルログ保存
 java DeleteLinks
 rm /home/m-kouki/mysearch/filelog/*
 java CrawlEntry2
 rm *.pdf*
 chmod 755 /home/m-kouki/mysearch/filelog/*

***cronで自動化 [#odf25724]
-[[参考:http://shower.human.waseda.ac.jp/~m-kouki/pukiwiki/index.php?Linux%E3%82%B5%E3%83%BC%E3%83%90%E9%96%A2%E4%BF%82#ed5365f2]]
-cron コマンドに関して [#c2aab7e5]
--[[crontabで定期的自動実行:http://www9.plala.or.jp/sasakiss/freebsd/freebsd_cron1.html]]
--/etc/cron は、shinzan には存在しない。
-ユーザ m-kouki のスケジュールを変更するには
 $ crontab -u m-kouki -e
--エディタで、
 # m h  dom mon dow   command
 * * 14 6 6 date > date.txt
などとして、Ctrl+O → 「File Name to Write: 」はそのままで、Enter → Ctrl+X で終了する。



//CLASSPATH=$CLASSPATH:/home/m-kouki/mysearch/informa.jar
//CLASSPATH=$CLASSPATH:/home/m-kouki/mysearch/lib/commons-logging.jar
//CLASSPATH=$CLASSPATH:/home/m-kouki/mysearch/lib/jdom.jar
//CLASSPATH=$CLASSPATH:/home/m-kouki/mysearch/htmlparser.jar
//CLASSPATH=$CLASSPATH:/home/m-kouki/mysearch/mysql-connector-java-5.1.6/mysql-connector-java-5.1.6-bin.jar
//CLASSPATH=$CLASSPATH:/home/m-kouki/mysearch/CrawlRSS
//export CLASSPATH
//
//java -cp /home/m-kouki/mysearch CrawlRSS
//
//java -cp /home/m-kouki/mysearch -jar /home/m-kouki/mysearch/informa.jar CrawlRSS
//Failed to load Main-Class manifest attribute from