2017.12.15 Friday
スポンサーサイト
一定期間更新がないため広告を表示しています
| スポンサードリンク | - | | - | - |
関口宏司のLuceneブログOSS検索ライブラリのLuceneおよびそのサブプロジェクト(Solr/Tika/Mahoutなど)について
2007.01.31 Wednesday
スコア計算の様子がわかるデモ公開
Luceneのスコア計算の様子を簡単に見られるようにしたデモを作成したので、公開する:
Apache Lucene Score DEMO http://demo.rondhuit-search.com/etcscoredemo/ スコアとは、検索結果を表示するときに文書の表示順位を決めるための数値のことである。 スコア計算については(笑点の話などムリヤリ感も多少あるが)Lucene本にやさしく解説してあるのでここでは触れないが、このデモについて簡単に説明する。 以下はデモで使用している検索対象となる文書である:
ソース文書は英語であるが、その意図は単語の切れ目がはっきりしていてわかりやすく、スコア計算の学習に適していると判断したためである。ちなみにインデクシング時と検索時にはStandardAnalyzerを使用しており、デフォルトのストップワードがそのまま適用される。 文書はtitleとcontentフィールドからなっており、どちらもTOKENIZEDである。 使い方は、デモページの下半分に並んでいるボタンをクリックして検索を実行するだけの簡単操作だ。結果はページの上部に表示される。 たとえば、[tfの効果を見る]ボタンをクリックすると、tf項の効果が(割と)出やすい検索を発行して結果を表示する。ここでは"java"という単語をcontentフィールドに対して検索するので、2件の文書がヒットする。そのとき、"java"を数多く含んでいる方がtfが高くなり、スコア計算の結果、「Java Programming」が「Java Book」より上位にランクされる様子がわかる、という具合だ。 最後のボタン以外のテキスト入力領域はREAD ONLYになっており、ボタンをクリックしてそれぞれの項目の効果を簡単に見られるようになっている。 最後のフォームの部分は検索窓に自由に検索語を入力し、検索を実行できるようになっている。ここでは検索質問文字列をQueryに変換するのにQueryParserを使用しているので、QueryParserのコマンド(重みづけ、あいまい検索、ワイルドカード検索、・・・)がそのまま使用できる。 デモのソースコードはロンウイットのページで公開する予定だが、現在ホームページを整備中なので、今しばらくお待ちいただきたい。 2007.01.27 Saturday
IndexWriterの新しいコンストラクタ
世の中、Web2.0が花盛りである。
何を隠そう、弊社もWeb2.0企業へ変身しようと社内改革に真剣に取り組んでいる。そのためにまず、Web2.0とは何かを調べる必要がある。Web2.0の日本語のバイブル的取り上げ方をされる「ウェブ進化論」は少し前に読んだが、最近立て続けに次のような関連本を読んだ: どれも面白くためになった。どうやらWeb2.0のための7つの原則とかいうものがあるらしく、それは次のようなものである:
しかしどうもよくわからない。Web2.0企業になるためには何をすればいいのだろう。 そこで思いついたのは、これらの本で必ず取り上げられているWeb2.0企業の最先端、Googleのまねをすることである。Googleのまねをするというと人は「検索エンジンの開発でもするのか」と想像するであろう。そうではない。私が開発したわけではないが、当社は既に検索エンジンを持っていてそれで商売をしている。ここはもっと意表をつくやり方でやってみたい。たとえばこういうのはどうだろう。 私の昔の同僚でGoogleに移籍した者がおり、彼と飲んだときのことである。Googleについて彼が熱く語ったいくつかの逸話のうち、ひどく私の印象に残った話は「Googleは社員に無料で食事を振舞う」というものであった。これは今でこそ広く知れ渡っているGoogleの福利厚生のひとつであるが、当時は驚きと感心をもって聞いたものである。さすがGoogleだ。無料サービスがこんなところでも行われているのだった。まずはこれを取り入れさせてもらうことにする。 しかし、ただまねするだけではだめだ。Googleの上を行くために、うちは3食すべて会社で払うことにする。そうなると3食すべて外食にしなければならない(社員食堂がまだないので)。これはなかなか大変なことだが、Web2.0のためには乗り越えなければならない壁である。そして領収書を受け取り、申告にあたってはきちんと残らず添付する。3食すべて領収書があるので、その分量といったら大変な枚数になるだろう。毎月の領収書の糊付けの作業だけで一日費やすことになってしまうかもしれない。しかし、Web2.0のためなので文句は言えない。すると税務署は大量の食費の領収書を見てあきれ、こういうだろう。 「この領収書は認められません」 「いえ、問題ないはずです」 「どうしてですか」 「当社はWeb2.0企業ですから」 税務署はとまどうばかりだ。 しかし、税金を取るために執念を燃やす彼らは、署に戻りWeb2.0に関する勉強会を開いて対策を立てて出直すだろう。そして彼らはまたもこう指摘するのだった。 「これは認められません」 「どうしてですか」 「この領収書は1.0ですから」 なんと、いつの間にか税務署も2.0化しているのだった。 2.0の前で人は無力である。 2.0といえば、Luceneのバージョンも今2.0である。 次のバージョンとされている2.1は残Issueの数だけで見ればもうすぐ出そうな気配である。バグフィックスだけでなく、パフォーマンスについても前回書いたとおり改善されている。そのほかの改善点でひとつのわかりやすい例をあげると、IndexWriterのコンストラクタの追加がある。 IndexWriterの現在のコンストラクタは、3つの引数を取り、3番目の引数のboolean createの扱いがやっかいなものであった。この引数をtrueにすると、1番目の引数で指定したインデックスを作成するのであるが、インデックスがあってもなくても新規作成してしまう。逆にfalseにするとインデックスがないときはFileNotFoundExceptionをスローする。わかりやすく表にすると、次のようになる:
この表で、赤字にしたところがやっかいな動作の部分だ。Lucene本でもこの部分については数ページを割き、最終的にIndexReader.indexExists()メソッドを使うことを提案している。 やはりこのフラグは多くの人を戸惑わせていたようで改善提案がなされた。オリジナルの提案では、3番目の引数をcreateではなくclearと改名し、clear=falseのときでインデックスがないときはFileNotFoundExceptionではなく新規作成するようにして欲しい、というものであった。こうすればエンドユーザには影響がないであろう、という主旨のようだが、これでは既存のプログラムが影響を受けるのでこの案は受け入れられなかったが、その代わり新しいコンストラクタが導入されることになった。この新しいコンストラクタでは、3番目の引数がはぶかれている。そして動作としては上記の表の黒字部分のようになる。つまりインデックスがあれば追加し、なければ新規作成する、というコンストラクタである。 これはおそらく今後最も使われるIndexWriterのコンストラクタになると私は予想している。 2007.01.21 Sunday
BooleanQueryのパフォーマンス
前回に引き続きパフォーマンスについての話題。
少し前のメーリングリストの投稿で、Lucene 1.4.3に比べてLucene 1.9/2.0の検索のパフォーマンスが落ちている、というものがあった。 原因は、1.9rc1からBooleanScorer2が提供され、それ以前のBooleanScorerに置き換えられたためで、AND/NOTのBooleanQueryが以前よりもおそらく速くなっているが、ORのBooleanQueryは遅くなる可能性がある、ということであった。staticメソッドのBooleanQuery.setUseScorer14(true)を呼ぶと昔のBooleanScorerを使うように動作する、という回答を得た質問者の結果報告には「BooleanQuery.setUseScorer14(true)をしたら1.4.3と同等の性能が得られた」とあった。 そこで本当にそうなるか試してみた。 プログラムは次の通りである:
結果は次のようになった(数字の単位はミリ秒):
期待に反し、いずれもsetUseScorer14(true)にしたときが速い、という結果になった。インデックスには昔収集してそのままになっている100万件の特許情報を使用したが、データによってはこれとは異なる結果になる可能性はある。 もうひとつ、同じプログラムをtrunkから持ってきてビルドしたJARを使って試すと、結果は次のようになった:
すべての組み合わせで性能が向上しているのがわかる。メーリングリストを眺めているとたまにパフォーマンス改善の話題が出てくるが、こちらは期待通りの結果となった。 以上、まとめると: 1.BooleanQuery.setUseScorer14(true)は簡単・安全なので試してみるとよい。特に、LuceneのQueryParserをデフォルト状態で使っている場合は性能向上が期待できる(ただし採用に当たっては、いろいろなQueryできちんと性能を測ること)。 2.さらなる性能を追求する場合はtrunkやnightly buildも一考の価値あり。 ちなみに、Subversionのtrunkブランチからソースを取得してビルドするには、以下のようにする:
これでbuildディレクトリの下にlucene-core-2.1-dev.jarというJARファイルができるので、これをCLASSPATHに通せばよい。 2007.01.05 Friday
IndexSearcherのパフォーマンス
新年あけましておめでとうございます。本年もどうぞよろしくお願いいたします。
正月料理にも飽きてきた頃のことである。私は一人、歩いて20分くらいのところにあるファミレスに出向いてランチを食べることにした。 そこは普段から割りとよく利用するファミレスで、大抵の場合日替わりランチを注文する。 その日は同じように考える人々が多いのか、かなり混んでいた。しかしタイミングがよかったせいかすぐ席に案内された。私は少し迷い、しかし結局いつもの日替わりランチを注文して、いそいそとセルフサービスのお替り自由のスープを取りに立ち上がった。注文のランチが来るまでスープを2杯くらい飲みつつ持参した文庫本を読むのが楽しみなのであった。 その日は混んでいたので多少待たされるだろうと思いながらスープを席まで運んだそのとき、10代の男子学生風のウエイターが日替わりランチを私の席まで運んできた。 早すぎる。 遅いのも困りものだが早いのはそれ以上に困る。不気味でさえあるといえる。大抵の人間が勘ぐるように私も疑わずにはいられなかった。 間違って調理した他の人のオーダーをこちらに再利用したのではないか。 口には出さなかったがウエイターをしばし見つめてしまった。おそらく冬休みの期間限定でのアルバイトであろう彼は年上の男の鋭い視線に耐え切れず、こう口にした。 「お待たせしました」 そうじゃないだろう。待っていないよおじさんは。 ファミレスで日替わりランチが早くきすぎるのは考えものだ。読書しながらランチスープを飲みランチの到着を待つ。その理想の時間はだいたい5分とされている。 Luceneで「速さ」を求められる部分といえば、インデックスの作成時間もあるが、やはり検索の時間をまず気にする人が多い。 Luceneでの検索部分のプログラミングの鉄則はIndexSearcherのインスタンスを使いまわすことである。また、インデックスの更新が並行して走るときは本でも紹介したDelayCloseIndexSearcherを用いることを検討する。 今回は簡単なプログラムを使ってIndexSearcher周りのパフォーマンスを見てみることにする。 以下が使用するプログラムである:
このプログラムは、search()メソッドの中でIndexSearcher.search()を使って「実施」「説明」「特徴」という単語を検索し、IndexSearcherの取得時間と3つの単語の検索時間を計測・表示している。そしてsearch()メソッドの最後でIndexSearcherをclose()している。 このsearch()メソッドをmain()から2回(2セット)呼び出している。 これを実行すると次のようになった:
まず目に付くのは「1回目」に比較して「2回目」の時間がすべてにおいて劇的に速くなっている点で、特にIndexSearcherの取得は2回目は非常に短い。この結果を見ると「IndexSearcherは検索のたびに取得して使い終わったらclose()していいんだ」と捉えられなくもない(が、しかしやはり必要でなければ一度取得したインスタンスはそのまま使い続けるべきである)。 検索時間についても2回目の方は一桁程度1回目よりも速くなっている。これはOSのファイルシステムのキャッシュが効いていると考えられが、もう少し掘り下げてみる。 少し前のLuceneのメーリングリストで、ファイルシステムがインデックスをキャッシュするようddコマンドを次のように使うことができる、というものがあった:
ddコマンドでインデックスファイルをnullデバイスにコピーすることでファイルシステムがインデックスファイルをキャッシュすることを期待している。 このddコマンドを実行してから同じプログラムを起動すると、次のように1回目も少し速くなる:
しかしながら、これでもまだ2回目に比べると遅い。この差はOSのファイルシステムキャッシュだけではなく、JVMのキャッシュの効き具合も差になって現れていると考えられる(ちなみに2回のJavaプログラムの実行は、両方ともシステムの再起動直後に行った)。 これらの結果から、IndexSearcherは一度取得したら(インデックスが変更にならないうちは)close()せずに使いまわし、ユーザから検索リクエストを受けて実行する前に、ウォームアップのために検索を実行しておくのがよい(*)、ということがわかる。 (*)Solrはフレームワークでウォームアップ済みのIndexSearcherをアプリケーションに渡すしくみが備えられている。 ところでファミレスの話に戻ると、早く来た日替わりランチは誤った調理の再利用ではなく、定番料理の作りおきだった可能性もある。しかしランチの作りおきはあまり感心できないのであった。キャッシュやプールするのはコンピュータの中だけにしてもらいたいものである。そして料理は注文してから5分で出てくるのが理想である。 |
+ 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 |