2017.12.15 Friday
スポンサーサイト
一定期間更新がないため広告を表示しています
| スポンサードリンク | - | | - | - |
関口宏司のLuceneブログOSS検索ライブラリのLuceneおよびそのサブプロジェクト(Solr/Tika/Mahoutなど)について
2007.06.26 Tuesday
人名がヒットしたときはスコアを上げる
前回紹介したペイロードのプログラムではSenの出力である品詞情報をペイロード領域に登録し、TermEnumとTermPositionsで全Termのペイロードを取得するというものであった。これにより、名詞など指定した品詞の単語をカウントして多く出現する単語上位10個を表示した。
これはこれで今までのLuceneでは実現が面倒なプログラムが比較的簡単に書けて面白いが、「品詞(ペイロード情報)で検索できないのか」という疑問が当然のことながら湧くだろう。 ペイロードに関する計画には将来はペイロードで検索できるようなことが書かれている。しかしながら現在は、ペイロードで検索はできない。 それは、Luceneのファイルフォーマット情報を見れば、ペイロードは.prxファイルに格納されており(そのためTermPositionsインタフェースでアクセスできるようになっている)、転置索引に登録されている単語とは異なるため、検索に適した状態になっていないことからもうなずける。 ただし、ペイロード情報をスコア計算に使用することは可能である。今回はそのためのQueryクラスであるBoostingTermQueryを使って、検索語が人名のときは他の単語よりもスコアを上げる、というプログラムを作成してみる。 検索に使用するデータは次のとおりである:
これに対し、検索語に次の2つを使用する:
さて、これらの検索語のうち人名である「安倍」がヒットしたときだけ、そのドキュメントのスコアが他のドキュメントのスコアよりも上がるようにする、というのが今回作成するプログラムだが、その前にまずは通常のBooleanQueryでOR検索をしてみよう。プログラムは次のようになる:
実行結果は次のようになり、同点スコアなので登録順にドキュメントが表示される:
BoostingTermQueryを使う では上記のQueryにBoostingTermQueryの項を加えて品詞が「人名」のとき(品詞は名詞だが、Senの品詞情報に「人名」が含まれる)にスコアが上がるようにする。BoostingTermQueryの項を加えると、次のようになる:
BoostingTermQueryとしてはコードは以上だが、この状態ではまだ「人名のときにスコアを上げる」というコードがどこにも入っていない。ではどうするかというと、Lucene 2.2からBoostingTermQueryがペイロードからスコアを計算するためのSimilarityの新しいメソッドscorePayload()というのが追加された。DefaultSimilarityではこのメソッドが常に1を返すようになっているが、BoostingTermQueryをきちんと動作させるには、ペイロードの値を見て適当なfloat値を返すscorePayload()を実装する必要があるのだ。 Similarityを実装する ではSimilarityを実装しよう。オーバーライドするのはscorePayload()だけなので、DefaultSimilarityを継承して次のようにすればよい:
そして実装したPayloadSimilarityクラスを検索する前にIndexSearcherに次のように設定する:
これでプログラムを再度実行してみると、次のように「安倍」が含まれているほうが「政調」を含むドキュメントよりも高いスコアを獲得し、上位に表示される:
最終的なプログラムは次のようになる:
Senからは品詞情報の他にも単語の読みがなも出力されるので、ペイロードの使い道として検討してみても面白いかもしれない。 2007.06.23 Saturday
記事から名詞だけを取り出す
Lucene本の6章では、TermFreqVectorを使って、ブッシュ大統領の就任演説や小泉純一郎首相(当時)の所信表明演説の単語の出現頻度分析を行うプログラムを紹介した。そのプログラムでは「ごみ」を取り除くために「3文字以下のひらがな」を一律に切り捨てていた。
今回は、Lucene 2.2でサポートされたペイロード機能を使って同様のことをもう少しエレガントにやってみたい。 ペイロードは、インデックスに登録する単語ごとに記録できるバイトストリームのことである。登録するときは、Tokenに対してsetPayload()メソッドを呼び出す。そのときにPayloadのオブジェクトを引数に渡せばよい。 ペイロードはTokenにセットするので、TokenizerやTokenFilterで設定するのがよいだろう。そこでSenTokenizerを変更して、形態素解析器Senが出力する品詞情報をペイロードに設定することにする。そして単語出現頻度分析時に名詞だけを出力するようにプログラミングする。 SenPayloadTokenizerクラス まずTokenにSenの品詞情報をペイロードとしてセットするSenPayloadTokenizerを作成する。SenPayloadTokenizerはSenTokenizerを拡張して実装する。SenTokenizerのほとんどの部分を再利用できるので、プログラムは次のようにとても簡単なものとなる:
名詞だけを取り出すプログラム 記録したPayloadはTermPositionsから取り出せるようになっている。TermPositionsインタフェースのPayload関連のメソッドだけを示すと、次のとおりである:
各メソッドの働きはメソッド名称そのままなので特に説明は必要ないだろう。 TermPositionsを使うには、インデックスにどのようなTermがあるかをあらかじめ知っておく必要がある。ここではセオリーどおり、TermEnumを使ってインデックス内の全Termを調べる。次のプログラムはTermEnumで全Termを調べるようにループし、TermPositionsからPayloadを取得してTermとPayload(品詞情報)を表示するプログラムである:
今回のプログラムの目標は名詞だけを取り出すので、Payloadが名詞かどうかを判定する次のようなメソッドを用意する:
今回はサンプルなので、品詞情報はSenが出力する品詞情報文字列をそのままPayloadに登録しているが、本稼動のプログラムでは符号化ルールを定めて品詞情報文字列ではなく、1バイトのPayloadに収まるようにするのがよいだろう。そうでないとそれこそ品詞情報がインデックスのお荷物(荷重;Payload)となってしまう。 プログラムは出現頻度の高い上位10位の名詞のリストを表示するようにするためComparatorなどの実装がさらに必要となり、最終的なプログラムは次のようになる:
上記のプログラムのXXXXXXXXXXで示した場所に適当な文章(長文)をセットし、コンパイルして実行してみる。 実行に当たっては、JapaneseAnalyzerがSenPayloadTokenizerを使用するように、XML設定ファイルを用意し、システムプロパティを 指定して実行する(詳しくはLucene本P.40〜41参照)。 次は、XXXXXXXXXXの部分に安倍首相の所信表明演説を貼り付けて実行したときの出力結果である:
小泉首相のときは「郵政」「民営」「化」というのがはっきり現れてそれなりに面白かったが、安倍さんの場合は名詞だけを取り出しているせいか例の「美しい国」が見えてこないのでつまらない(「国」だけは出現回数32回あるが・・・)。 そこでためしにプログラムの「名詞」の部分を「形容詞」に変えて実行してみる。すると、期待通り(!)「美しい」を連呼していることがわかった:
楽しくなってきたので、さらに、取り出す品詞を「名詞-固有名詞-地域-国」に変えてやってみると次のようになった:
「日」や「米」は果たして本当に国なのかは怪しいがなかなか面白い(中国には言及していないんですね)。 きりがないのでこの辺で止めるが、Lucene 2.2のペイロードを使ってインデックスにSenが出力する品詞を埋め込むと、いろいろ面白そうなことができることがわかった。 2007.06.22 Friday
Luke 0.7.1のリリース
Lucene 2.2の新しいインデックスフォーマットに対応したLuke 0.7.1がリリースされた:
Luke http://www.getopt.org/luke/ 今回のLukeリリースについては新しいLuceneのバージョンに対応した、という以外に特に書くことはないが、以前書いたこちらの記事の私の提案が受け入れられ、リリース番号が小刻みになったことにひそかな喜びを感じているのは、世界中でも私だけだろう。 作者のAndrzej Bialecki氏はこのブログを読んでいるに違いない。 2007.06.21 Thursday
Lucene 2.2のリリース
昨日、Lucene 2.2のリリースがアナウンスされた。
"point-in-time"検索(日本語での適当な訳語がすぐに思い浮かばない)やペイロードのサポートなどがあり、前回の2.1に引き続き、インデックスフォーマットが変更になった。このため、古いインデックスをLucene 2.2のプログラムでオープンしてマージ処理が走ると、そのインデックスはLucene 2.1以前のプログラムではオープンできなくなるのでこの点は注意が必要だ。 Lucene 2.2の新機能については順次このブログで説明していきたい。 2007.06.18 Monday
2つの単語間の距離をスコアに反映する
次のような5つのドキュメントから単語"AAA"と"BBB"を含むドキュメントを検索したいとする:
プログラムは簡単で、次のようになる:
この実行結果は次のようになり、単語"AAA"と"BBB"両方を含むドキュメントがどちらかひとつだけを含むドキュメントよりも高いスコアを獲得していることがわかる:
このプログラムでは、単語"AAA"と"BBB"両方を含む3つのドキュメントがすべて同じスコアとなっている。 ここで単語"AAA"と"BBB"が検索ユーザから見て相互に関連性の高い単語の場合を考えてみる。たとえば、「Tomcat上でHibernateを使ったサンプルプログラム」をインターネットから探すときに、プログラマが検索窓に「Tomcat Hibernate」と入力して2つの単語が登場する1つの記事を探す、というような場面である。 そしてその検索結果一覧をクリックして記述された記事(仮にブログとする)を読んだときに、TomcatとHibernateが同一ページに現れているものの、実は全然関係ない2つの記事にTomcatとHibernateが別々に書かれていてがっかりした、という経験は誰しも一度はあるだろう。 このようなとき、2つの単語間の距離をスコアに反映し、近いものほど高いスコアになるようにできれば、ある程度このようなガッカリ感は防ぐことができると考えられる。 Luceneでは2つ(以上)の単語の距離をスコアに反映して近いものほど高いスコアを獲得させるようにすることが簡単にできる。これにはPhraseQueryとslopを使用する。 slopはPhraseQueryで使用される成句とみなせる2つの単語間の最大距離を示すパラメータである(詳しくはLucene本190ページを参照)。 このslop値を適当な範囲までとってスコアに加算するようにプログラムを修正する。上記のサンプルプログラムを次のように書き換えれば、単語"AAA"と"BBB"の距離が近いものほどスコアが上がるようになる:
実行結果は次のとおりとなる:
Solrではこの機能を使って、「ユーザが入力した検索式の全体をPhraseQueryに変換し、単語間相互の距離が近いドキュメントほどスコアを高くする」ということをDisMaxRequestHandlerにて行っている。 |
+ 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 |