2017.12.15 Friday
スポンサーサイト
一定期間更新がないため広告を表示しています
| スポンサードリンク | - | | - | - |
関口宏司のLuceneブログOSS検索ライブラリのLuceneおよびそのサブプロジェクト(Solr/Tika/Mahoutなど)について
2006.11.20 Monday
「コンプリート版」サンプル、ダウンロード開始
「Apache Lucene入門」の出版から半年が経ち、Luceneをはじめ同書のサンプルプログラムが使用している周辺ツールのバージョンがバージョンアップした関係で、本に書いてあるとおりのバージョンをそろえるのに手間がかかるようになって来た。そこで、サンプルをLucene 2.0対応にすると同時に必要ツールの大部分をZIPファイルに同梱した「コンプリート版」なるものを作成した。
以下よりダウンロードできる: http://www.rondhuit.com/publicity.html 書籍出版時はLucene 1.9がLuceneの最新バージョンであり、同書もLucene 1.9を想定して書かれている。しかし現在はLucene 2.0となっており、Lucene 2.0対応のJapaneseAnalyzerが出てきたりして、その関係でサンプルコードの一部がコンパイルできないものが出てきた。 Lucene 2.0になったときにLucene 1.9でdeprecatedであったAPIのほとんどが削除されたため、サンプルコードに同梱していたLucene-jaのデモがコンパイルできなくなった。出版時のLucene-jaのバージョンはLucene 1.4.3対応版だったため、Lucene 1.4.3当時に問題なかったAPIをそのデモの中で数多く呼び出していた。出版時はLucene 1.9でありdeprecatedになった程度であったので、Lucene-jaのデモはコンパイル時に警告メッセージが出るだけでコンパイルは通っていた。しかしLucene 2.0になったときにAPIそのものが別のものに置き換えるよう強制されてしまったため、コンパイルエラーが出るようになった。 また、Lucene-jaが出版当時のLucene 1.4.3対応版からLucene 2.0対応版に変わった際に、DigitFilterのコンストラクタがpublicからprotectedに変わってしまったので、DigitFilterを使用したサンプルプログラムのコンパイルが通らなくなってしまった。そのため、「コンプリート版」からはDigitFilterを使用したサンプルプログラムは削除してある。 「コンプリート版」にはlibディレクトリに多くの周辺ツール(JARファイル)を含んでいるのでサイズが大きい(約10MB)。 上記ダウンロードページからはこれまでの「旧版」もいまだダウンロード可能である。こちらはLucene 1.9を使い、本のAppendix Aに書いてあるバージョンに必要ツールのバージョンをきちんと合わせ、本の手順どおりにインストールと設定を行えば必ず動作するので、必要であればこちらも試していただきたい。 2006.11.17 Friday
独自QueryParserの作成(5)
アクションの記述
前回生成規則をコード化したものに、JavaCCのアクションを記述する。最初にqueryExpr()であるが、これは次のようであった:
「|」の前のdefaultExpr()を考える。defaultExpr()はqueryExpr()と同じくQueryオブジェクトを返すので、この場合はdefaultExpr()の戻り値をそのまま返せばよい。したがって、次のようになる:
次に、「NOT A」のように検索式の先頭にNOT演算子がついた場合の扱いであるが、これはdefaultExpr()から返されたQueryオブジェクトの全体の否定とすればよい。ただし、BooleanQueryで否定の単項は許されないので、Lucene 1.9から追加されたMatchAllDocsQueryとのANDをとるようにする。結局、queryExpr()は次のようになる:
次にdefaultExpr()を考える。defaultExpr()の生成規則は次のようであった:
したがって、これにアクションを加えると、次のようになる:
以下同様に、notExpr()、orExpr()、andExpr()のアクションを埋めていく。 次にphraseExpr()であるが、これはやや複雑で次のようであった:
ここで<WORD>は前々回のようにアクションを記述すると、次のようになるであろう:
しかしこのようにしてしまうと、<WORD>と認識された文字列がすべてLuceneのTermオブジェクトなってしまう。これではたとえば「機能定義書」というような文字列の場合具合が悪い。(JapaneseAnalyzerを使っている場合は)「機能定義書」は「機能」「定義」「書」のような3つのTermオブジェクトからなるPhraseQueryになるためである。 認識された文字列がどのように分割されるかはAnalyzerによって異なる。AnalyzerはMyQueryParserの場合は(QueryParserと同様)コンストラクタで渡される。MyQueryParserではこれをメンバ変数のanalyzerで保持しているので、これを用いて<WORD>の文字列を分解し、PhraseQueryに変換するようにしなければならない。 結局、phraseExpr()は次のようになる:
検索禁止語の対応 次に検索禁止語に対応するよう、プログラムに機能を追加する。 検索禁止語はStringの配列でMyQueryParserのコンストラクタに渡すことにする。ただし、アプリケーションによっては検索禁止語を判定する機能自体不要のものもあるので、検索禁止語のリストを渡さないバージョンのコンストラクタも用意する。Stringの配列で渡された検索禁止語は、HashSetで保持する。
検索式内にトークンとして認識された文字列と検索禁止語のリストを比較して検索禁止語の場合はParseExceptionをスローする次のようなメソッドを作成する:
このメソッドは前述のphraseExpr()にて<WORD>が認識されたときに呼び出すようにする。 MyQueryParserの全リスト 以上説明したMyQueryParserの全リストを以下に示す(実際にはロンウイットでも使用しているSimpleQueryParserという名前のクラスである。オープンソースソフトウェアで、自由に使っていただいてかまわない):
使い方 使い方は、Lucene付属のQueryParserと同様、コンストラクタにフィールド名とAnalyzerを渡してインスタンスを取得し、parse()メソッドを呼び出す。 SimpleQueryParserはQueryParserに加えてコンストラクタの第3引数に検索禁止語のリストをStringの配列にして渡すことができる。 LuceneのQueryParserのparse()に「要件定義書 AND テスト仕様書 OR 機能仕様書 NOT ユーザマニュアル」という文字列を渡すと、返されるQueryは次のようになる:
今回開発したSimpleQueryParserのparse()に同じ検索質問文字列を渡すと、返されるQueryは次のようになる:
上記のように、SimpleQueryParserでは正しくBooleanQueryを構築できており、AND/OR/NOTを組み合わせた検索を行った場合にLuceneのQueryParserよりも望ましい検索結果が得られる。 2006.11.13 Monday
独自QueryParserの作成(4)
検索式演算子の優先度
AND/OR/NOTの演算子を含む検索式を正しくBooleanQueryに展開するために、演算子の「結合規則」や「優先順位」を決める必要がある。MyQueryParserではこれを次の表のように定めることとする:
「結合規則」はすべて=>となっており、これは「左結合」を意味する。また演算子NOTは二項演算子なので「A NOT B」のように使用する場面に適用されるものであり、「NOT A」のようなNOTについてはのちほど考えることにする。また演算子を省略した場合は初回に決めたMyQueryParserの仕様どおりANDと解釈する。 生成規則を作成する 左結合の二項演算子の式を表現する生成規則は次のとおりである(前回紹介した「JavaCC - コンパイラ・コンパイラ for Java」などを参照):
また、被演算子の式を表現する生成規則は次のとおりである:
これらの生成規則を前出の表の優先順位に沿って組み合わせていく。 最初は被演算子の式を表現する生成規則を使ってphraseExpr()を作成する。これは次のようである:
次に、表の中でもっとも優先度の高いAND演算子の生成規則を作成する。これは左結合なのでleftExpr()を用いて次のようになる:
ここで、leftExpr()の右辺のhigherExpr()は優先順位が上位のphraseExpr()に置き換えられている。 次に、表の中で次に優先度の高いOR演算子の生成規則を作成すると、次のようになる:
以下同様にNOTと省略時の演算子の生成規則を作成する:
以上をまとめると、検索式の生成規則は全体で次のようになる:
""を認識する 次に「"(ダブルクオーテーション)」でくくられた検索質問語を認識するように修正を加える。""でくくられるものは、ひとつ以上の単語でフレーズとなることから、前出のphraseExpr()に追加して、次のようになる:
ここで、「"」は<QUOTE>という表現に置き換えている。 「NOT 検索質問語」をサポートする 次に「NOT A」というフォーマットの検索式をサポートするように修正を加える。 ここで使われるNOTは前出の二項演算子のNOTとは異なり単項演算子である。しかも、(数式の単項演算子"-"(マイナス)とは異なり)検索式の途中には出現せず、常に先頭にのみ使われる。ということは、検索式は「defaultExpr()」かあるいは「NOT defaultExpr()」であると考えてよい。結局、検索式queryExpr()の生成規則は、全体として次のようになる:
生成規則のコード化 生成規則を(読みやすさを考えて)順序を逆転し、JavaCCのコードに置き換えると次のようになる:
次回は上記JavaCCのコードにアクションを記述する。また、検索禁止語への対応は(JavaCCではなく)Javaのプログラムでおこなうため、アクションを記述したあとに考える。 2006.11.07 Tuesday
書籍に関する問い合わせフォームの設置
書籍「Apache Lucene入門」と「Apache Ant」の「お問い合わせフォーム」を設置したので、不明点・不具合・ご要望・ご質問などお知らせください。
なお、個別の質問に回答するというよりは、FAQなどを作成するのに利用しようと思っているので、あらかじめご了承ください。 書籍に関する問い合わせフォーム http://www.rondhuit.com/publicity.html 2006.11.02 Thursday
Amazonの読者評価・・・星ひとつ
先日、久しぶりにAmazonをチェックしたら「Apache Lucene入門」にはじめてのレビューの書き込みが!・・・と思ったらナント星がひとつ。。。がーん。
「いただきました、星ひとつですっ!」 この瞬間ほど堺正章の悲哀を感じたことはない。しかし堺シェフは毎週その痛みに耐えているのである。私も真摯に評価者の声に耳を傾けてみよう。 「4章までは理解しやすくGOOD」とのこと。ありがとうございます。 しかし、「サンプルがビルドできない」とご立腹のご様子。そうでしたか。私の周りではそのような声はないので、気がつかないビルド手順の説明の抜けがあったのかもしれません。申し訳ございませんでした。私やいつも一緒に仕事をしている人はビルドに使用しているAntを使いこなしているので「入門書」にしてはLucene以外の部分で難しかったかもしれません。 ・・・ということで周囲の声を聞いているだけではわからない・気がつかない点があるようなので、近々問い合わせページを開設し、可能な範囲で対応できるようにしようと思っている。しばらくお待ちいただきたい。 2006.11.01 Wednesday
独自QueryParserの作成(3)
構文ダイアグラム
今回は簡単な検索質問の文字列を解析するMyQueryParserを開発する手順を解説する。 このMyQueryParserはスペース(タブや全角スペースも含む)で区切られた単語からTermQueryを生成し、BooleanQueryで全体を接続する。AND/OR/NOTの演算子も認識し、省略された場合はANDと解釈する。 次の表は検索質問とMyQueryParserでの解析結果の例である。解析結果はQuery.toString()を示している(フィールド名を"f"とする):
このような検索質問入力の文法を「構文ダイアグラム」という図で表すと、以下のようになる。 この構文ダイアグラムはひとつの「生成規則」からなり、生成規則の名前は「検索式」である。図を見るとわかるとおり、検索式(検索質問)はひとつ以上の単語からなり、任意の回数繰り返して記述される。そしてその単語と単語の間に"AND"や"OR"や"NOT"などを記述してもよく、これらの演算子を省略してもよい。・・・とまあ、こういった文法が構文ダイアグラムで表すとわかりやすい。 MyQueryParser.jj MyQueryParser.jjのプログラムを以下に示す。
上記のプログラムを適当なブロックに分けて、以下で説明する。 optionsの指定 JavaCCコンパイル時にコマンドラインで指定できるオプションを、このように.jjファイルに埋め込むことができる。オプションには多数のプロパティがあるので、詳しくはhttps://javacc.dev.java.net/doc/javaccgrm.html#prod2を参照していただきたい。MyQueryParser.jjで指定しているものはJDK_VERSIONを除き、QueryParserで指定しているものをコピーした。 構文解析プログラム本体部分 構文解析プログラム本体の部分をPARSER_BEGINとPARSER_ENDの間に記述する。書き方は次のように.jjファイルのファイル名と括弧の中とクラス名をすべて同じ名前にする。
MyQueryParser.jjではPARSER_BEGINとPARSER_ENDの間にコンストラクタとparse()メソッドを定義しているが、このように生成規則以外のメソッド(後述)が必要な場合は、PARSER_BEGINとPARSER_ENDの間に記述する。 MyQueryParserのコンストラクタはQueryParserのコンストラクタと同じ使い方ができるよう、第一引数にフィールド名を、第二引数にAnalyzerを渡すようになっている。parse()メソッドも同様にQueryParserと同じインタフェースにしており、引数に検索質問語の文字列を受け取り、Queryオブジェクトを返すようになっている。また、ParseExceptionをスローするところも同じである。 また、MyQueryParserにはmain()メソッドを持たせているが、これはMyQueryParser単独でテストができるようにしたサンプルクライアントである。 FastCharStreamクラスの流用 MyQueryParserではLuceneのQueryParserのために実装されたFastCharStreamクラスをコピーして使用している。このクラスは前述のoptionsでUSER_CHAR_STREAMにtrueと指定したときに生成されるCharStreamインタフェースのLucene用の効率的な実装クラスである。 MyQueryParserではFastCharStream.javaをorg.apache.lucene.queryParserパッケージからコピーし、パッケージをqueryParser.simpleに変更して流用している。 SKIPの指定 SKIPでは、字句解析ルーチンが入力から読み飛ばす文字を指定する。MyQueryParser.jjでは次のように半角・全角スペース、復帰・改行およびタブをスキップしている:
TOKENの指定 字句解析ルーチンがトークンとして切り出す文字列をTOKENのブロックで次のように指定する:
トークンの定義は「<名前:パターン>」という具合に記述する。パターンは正規表現で記述するようになっており、上記の場合は「半角・全角スペース、タブ、復帰・改行、・・・を除く文字の1つ以上の繰り返し」をWORDというトークン名に指定している。 以下のように「IGNORE_CASE」を指定すると、アルファベットの大文字小文字が区別されなくなる:
したがって、「AND」でも「and」でも「And」でもOP_ANDというトークンとみなされる。 生成規則のコード化 最後に生成規則をJavaCCのプログラムコードにおとす。MyQueryParserの生成規則「検索式」は既に「構文ダイアグラム」で図示したが、BNF(Backus-Naur Form)という記述の仕方で書き表すと次のようになる:
ここでqueryExpr()は「検索式」と考えていただきたい。また、<WORD>は単語、<OP_AND>、<OP_OR>、<OP_NOT>はそれぞれAND、OR、NOTの演算子である。さらに"|"はOR(または)の意味で、()?はカッコ内が省略可能であること、()*はカッコ内の0回以上の繰り返しを表す(ここには出てこないが、()+で1回以上の繰り返しの意味になる)。上記のBNFと前述の構文ダイアグラムがまったく同じであることがわかるだろう。 このBNFの式を次のようにJavaCCの記述に合うように書き直す:
BNFをJavaCCのコードに書き直したときは、上記のように左辺(非終端記号とも呼ばれる)に戻り値のタイプ(上記ではQuery)を記述する。戻り値がないときはvoidとする。 次に、上記のコードに必要な「アクション」を書き足していくが、アクションの中でトークンが参照できるよう、次のようにToken変数に代入する:
TokenクラスはJavaCCが生成するクラスであってLuceneのTokenではないので注意していただきたい。上記のように最初の{}で囲まれた宣言部でToken変数を宣言する(こうするとqueryExpr()メソッドのローカル変数になる)。 アクションの記述 「アクション」はトークンなどの生成規則の右辺の構成要素が正しく認識できたときに実行されるJavaのコードであり、構成要素(トークンなど)の後に{}でくくって記述する。 たとえば、最初の単語(<WORD>)が認識された後にその単語からTermQueryオブジェクトを作成してBooleanQueryに追加するには、次のようになる:
ここで「t.image」はTokenクラスのimage属性でトークンの文字列(String)を表す。 同じように、2番目以降の<WORD>が認識されたときと、右辺の構成要素がすべて認識され終わったときに実行されるアクションを加えて、最終的に次のようなコードを得る:
MyQueryParserの実行 既に紹介した開発環境がある場合、次のようにAntを使ってMyQueryParserのmain()メソッドを実行できる:
今回はJavaCCの解説も兼ねたのでMyQueryParserは簡単な機能を持たせただけだったが、次回以降で当初の仕様を満たすMyQueryParserを作成する。 なお、この記事を書くにあたっては以下のJavaCCの解説書を参考にした。 JavaCC - コンパイラ・コンパイラ for Java 五月女 健治 (著) テクノプレス http://www.amazon.co.jp/exec/obidos/ASIN/4924998648/ |
+ Solrによるブログ内検索
+ PROFILE
+ LINKS
+ Lucene&Solrデモ
+ ThinkIT記事
+ RECOMMEND
+ RECOMMEND
Lucene in Action (JUGEMレビュー »)
Erik Hatcher,Otis Gospodnetic,Mike McCandless FastVectorHighlighterについて解説記事を寄稿しました。
+ RECOMMEND
+ SELECTED ENTRIES
+ RECENT COMMENTS
+ RECENT TRACKBACK
+ CATEGORIES
+ ARCHIVES
+ MOBILE
+ SPONSORED LINKS
|
(C) 2024 ブログ JUGEM Some Rights Reserved.
|
PAGE TOP |