関口宏司のLuceneブログ

OSS検索ライブラリのLuceneおよびそのサブプロジェクト(Solr/Tika/Mahoutなど)について
スポンサーサイト

一定期間更新がないため広告を表示しています

| スポンサードリンク | - | | - | - |
独自QueryParserの作成(2)
JavaCCのインストール

MyQueryParserにはLucene付属のQueryParser(以下単にQueryParserと記す)と同様、検索質問文字列の解析にJavaCCを用いるので、まずJavaCCをインストールする。

JavaCCはhttps://javacc.dev.java.net/からダウンロードして入手する。現在のバージョンは4.0である。javacc-4.0.zipまたはjavacc-4.0.tar.gzファイルをダウンロードして適当なディレクトリ上に解凍すればインストールは完了だ。

Lucene+JavaCCの開発環境の準備

JavaCCは字句解析(文字列からトークンを切り出す)と構文解析(トークンの並びを解析する)を行うJavaのソースコードを、.jjというファイル拡張子を持つJavaCCプログラムから生成するコンパイラ・コンパイラである。MyQueryParserの開発では、MyQueryParser.jjをまず作成し、これをJavaCCにかけて字句解析・構文解析を行うJavaのソースコードを生成し、そしてそのコードをjavacコンパイラにかけてクラスファイルを得ることになる。

この「JavaCCコンパイル」=>「Javaコンパイル」(そして=>「実行」)一連の流れをスムーズに行うために、Antの開発環境を整備する。

まず、以下の記事を参考にしてLuceneプログラムのAntを用いた開発環境を用意する:

Luceneアプリケーションの開発環境の紹介

次に、build.xmlファイルをエディタで開き、コンパイルを行っている次の部分を探す:



<target name="compile" description="全サンプルソースコードのコンパイル">
<mkdir dir="${cls.dir}"/>
<javac srcdir="${src.dir}"
destdir="${cls.dir}"
encoding="${compile.encoding}"
deprecation="${compile.deprecation}"
debug="${compile.debug}">
<classpath refid="id.path.lucene"/>
</javac>
</target>



そしてこの部分を次のように書き換える(赤字部分を追記):



<target name="compile" depends="javacc" description="全サンプルソースコードのコンパイル">
<mkdir dir="${cls.dir}"/>
<javac srcdir="${src.dir}"
destdir="${cls.dir}"
encoding="${compile.encoding}"
deprecation="${compile.deprecation}"
debug="${compile.debug}">
<classpath refid="id.path.lucene"/>
</javac>
</target>



このdepends="javacc"というのは「compileターゲット(<target>のname属性で指定されている)はjavaccターゲットに依存している」ということを宣言している。こうすることで、compileが実行される前にjavaccターゲットが実行されるようにするのだ。

そして、javaccターゲットを次のようにbuild.xmlに追記する(位置はどこでもよい):



<target name="javacc">
<javacc target="${src.dir}/queryParser/simple/MyQueryParser.jj" javacchome="${cc.dir}"/>
</target>



上記のようにJavaCCコンパイル用にAntでは<javacc>タスクが用意されている。このタスクは<javac>タスクなどと異なりファイルセットなどでコンパイル対象を指定するのではなくtarget属性を使って直接.jjソースファイルを指定する(したがって、プロジェクトに複数の.jjファイルがある場合は<javacc/>を複数書いていく)。

そして、javacchome属性にJavaCCのインストールディレクトリを指定する。ここではcc.dirというプロパティが使われているが、これはbuild.propertiesファイルで次のように設定されている:



src.dir = src
cls.dir = classes
lucene.dir = ${LUCENE_HOME}
lucene-ja.dir = ${LUCENE_JA_HOME}
lucene-ja.lib.dir = ${lucene-ja.dir}/lib
sen.dir = ${SEN_HOME}
luke.dir = ${LUKE_HOME}
luke.lib.dir = ${luke.dir}/build
cc.dir = ${JAVACC_HOME}



cc.dirプロパティはさらにJAVACC_HOMEというプロパティを参照しているが、これはmyenv.propertiesというプロパティファイルで次のように設定されている:



LUCENE_HOME = c:/lucene-2.0.0
LUCENE_JA_HOME = c:/lucene-ja
SEN_HOME = c:/sen-1.2.2.1
LUKE_HOME = c:/Project/luke
JAVACC_HOME = c:/javacc-4.0



上記のmyenv.propertiesに指定する各ツールのディレクトリはそれぞれのインストールディレクトリであり、それぞれの開発環境に合わせて適切に設定する。

以上でLucene+JavaCCアプリケーションの開発環境が整ったので、次回は検索質問文字列を解析してQueryオブジェクトを作成する簡単なMyQueryParser.jjプログラムを試作する。
| 関口宏司 | Lucene自由自在 | 10:55 | comments(0) | trackbacks(0) |
独自QueryParserの作成
ある客先での話である。全文検索アプリケーションで「検索禁止語を設定したい」という要件が出された。どういうことかというと、あらかじめ「検索禁止」として辞書などに設定された単語が、Webサイト訪問者によって検索窓に入力されて検索されようとした場合、検索結果に関わらず「ヒット0件」で返したい、というものである。

なぜこんなことをしたいかというと、サービスしているコンテンツにふさわしくない検索語(特に性的な単語)が投入されて万が一コンテンツがヒットしてしまい表示されると、サイトのイメージダウンにつながるなどいろいろな不都合がある、という要求があるからであった。

もともとコンテンツにそのような単語が含まれていなければそもそもこのような機能は不要なのであるが、コンテンツに不安があるのであろうか・・・と思ったのだがそうではなかった。

この顧客のサイトでは、ユーザからの書き込み(評価やフィードバック情報など)を受け付けており、一定時間後にその書き込みも検索対象になるという仕様になっていた。そのため、サイト運営者がふさわしくないと判断する単語がコンテンツに含まれる可能性があるのだ。

そういうわけで、検索窓に入力された単語を検閲するというのは納得のいく仕様であった。

幸いこの機能の実装は簡単だ。検索禁止語のリストがbannedWords[]というString配列に入っているとしたとき、検索窓に入力されたqueryという文字列に対して次のようにチェックすればよい:



for( String bannedWord : bannedWords ){
if( query.indexOf( bannedWord ) >= 0 ){
// 検索禁止語が見つかった場合の処理
}
}



だいたい上記のようなコードをQueryParserに渡す前に実行すればよい。

頭の中で0.1秒でコーディングを終えた私は「できます」と回答した。ほどなく手渡されたCSVファイルにはここでは書けないエッチな単語が満載であった。「こんな単語のリストがforループで回されるのか・・・」と複雑な気持ちでXMLに書き移したものである。




ところで検索禁止語の判定を実現する方法で、もうひとつ試したいことがあった。それは独自のQueryParserを実装し直し、その中で検索禁止語を判定する、というものである。

「検索禁止語」のような要件がないアプリケーションでも、QueryParserを書き直したいという要求は少なくないだろう。それというのも、Lucene付属のQueryParserは汎用的に書かれているために、Webサイト訪問者が検索窓に入力した検索質問語をそのままparse()メソッドに与えるには少々FATというか、高機能すぎるように感じるからだ。

Lucene付属のQueryParserは範囲検索が指定できたり、検索フィールドを指定できたり、重み付け検索の重みを指定できたり、ワイルドカード検索を指定できたりするが、これらの文法は一般ユーザには難しすぎる(別の言葉で言えば、オーバースペックである)。こういった機能はUIを工夫して検索窓以外の部分から情報を取得し、プログラムがQueryオブジェクトを構築するのがよいだろう。

特に昨今の流行である「絞り込み検索」では、UIを工夫してシステム側が範囲検索の範囲をあらかじめ設定・提供するようにし、ユーザには検索窓でこれらの範囲を指定させるようなことはしない傾向となっている。

ではLucene付属のQueryParserはどんなときに使えばいいかというと、それは管理画面のようにサイト運営者が使う画面で検索を実行するときに適用するのがよい。

QueryParserはまた、高機能であるせいか複雑すぎ、次のような問題があることが指摘されてもいる:

http://wiki.apache.org/jakarta-lucene/BooleanQuerySyntax

ここで書かれている問題は・・・QueryParserのsetDefaultOperator()でANDを指定しているとき、"A AND B OR C"という検索質問をQueryParserで解析し、得られたQueryオブジェクトで検索すると、"A"とだけ検索質問語を指定した場合と結果が変わらない(!)。さらに、"A OR B AND C"とすると、"B AND C"という検索質問をした場合と結果が同じだ・・・というものである。前者の場合は"B"や"C"の指定が、後者の場合は"A"の指定がまったく無視されてしまっているのだ。がーん。

いくら高機能でもこの問題をそのままに、一般ユーザの検索質問語を解析するのに使用するにはやはり無理があるだろう。こういった観点からも、「独自QueryParserを作る」という要求が出てくる。

そこでこれから何回かに記事を分けて、独自QueryParserを設計・実装する方法を紹介しよう。

ここで試作する独自QueryParserは前述の「検索禁止語判定機能」のほか、Lucene付属のQueryParserが対応していない「全角スペース区切り検出機能」や「NOTのみ検索機能」を持たせることにする。ここで「全角スペース区切り検出機能」とは、検索窓に入力される複数の検索質問語の区切り文字が「全角スペース」でも「半角スペース」と同様の区切り文字として判定されるということ、また、「NOTのみ検索機能」とは検索窓に"NOT A"という入力を許可するというものである。この場合読んで字のごとく、「"A"を含まない全文書を検索せよ」という意味になる。Lucene付属の現在のQueryParserはこれを正しく展開できないが、この際これも実装しよう。

上記のような機能を持つ一方で、独自QueryParser(以降MyQueryParserと呼ぶことにする・・・安易な命名だー)は一般ユーザ向けにLucene付属のQueryParserが持つ「範囲指定」や「重み付け指定」などは省いて、シンプル・軽量なものとする。

まとめると、MyQueryParserの仕様は次の通りとする:

(1) AND、OR、NOT「演算子」を使える。「演算子」を指定しないときのデフォルトはANDとし、変更できないものとする。
(2) ()が使える。()内は優先して処理をする。ネストも可能。
(3) ""が使える。""内はフレーズとみなす。
(4) 全角スペースが半角スペースと同じように検索質問語の区切り文字と判定される。
(5) "NOT 検索質問語"という検索指定を正しくQueryオブジェクトに変換できる。
(6) 検索禁止語を判定し、見つかったときにParseExceptionをスローする。

となる。特に(1)は重要で、これらの演算子を処理するときに「優先順位」をきちんと決めて解析する。こうすることで前述のBooleanQuerySyntaxで指摘されたようなおかしな結果も回避することが可能である。

実際、LuceneのQueryParserでデフォルトオペレータをANDとして"A AND B OR C"という検索質問をparse()するとQueryオブジェクトは"+A B C"となり、このQueryオブジェクトを使った検索結果は前述の通りの珍妙な結果となる。これをMyQueryParserでは「ORよりANDを優先」と決めて、"(+A +B) C"というQueryオブジェクトを生成し、期待した結果(仕様に沿っていて説明ができる結果)を得よう、という企みである。
| 関口宏司 | Lucene自由自在 | 19:39 | comments(0) | trackbacks(1) |
+ Solrによるブログ内検索
+ PROFILE
1234567
891011121314
15161718192021
22232425262728
293031    
<< October 2006 >>
+ LINKS
検索エンジン製品 - 比較のポイント
商用検索エンジンを購入した企業担当者は読まないでください。ショックを受けますから・・・
>>製品比較 10のポイント
+ Lucene&Solrデモ
+ ThinkIT記事
+ RECOMMEND
Apache Solr入門 ―オープンソース全文検索エンジン
Apache Solr入門 ―オープンソース全文検索エンジン (JUGEMレビュー »)
関口 宏司,三部 靖夫,武田 光平,中野 猛,大谷 純
+ RECOMMEND
Lucene in Action
Lucene in Action (JUGEMレビュー »)
Erik Hatcher,Otis Gospodnetic,Mike McCandless
FastVectorHighlighterについて解説記事を寄稿しました。
+ RECOMMEND
+ SELECTED ENTRIES
+ RECENT COMMENTS
+ RECENT TRACKBACK
+ CATEGORIES
+ ARCHIVES
+ MOBILE
qrcode
+ SPONSORED LINKS