2017.12.15 Friday
スポンサーサイト
一定期間更新がないため広告を表示しています
| スポンサードリンク | - | | - | - |
関口宏司のLuceneブログOSS検索ライブラリのLuceneおよびそのサブプロジェクト(Solr/Tika/Mahoutなど)について
2010.11.10 Wednesday
(メモ)LuceneはApache Harmony上で動作
LuceneはApache Harmony(Apacheで開発されているオープンソースのJava SE)上で動作する:
http://wiki.apache.org/harmony/Apache_Lucene 2008.07.27 Sunday
柔軟なインデックス構造を目指して進化するLucene
先日、ドキュメントをセグメントファイルに書き出すクラスであるDocumentsWriterのリファクタリングをしよう、というチケットがコミットされた。インデックスへの書き込みのプロセスをよりモジュール化して、将来の新しいインデクシング関連の機能追加はプラグインの追加で対応できるようにしよう、というのが狙いである:
https://issues.apache.org/jira/browse/LUCENE-1301 これはまた、フレキシブルインデクシングと呼ばれる新機能に対応するための第一歩でもある。 現在、Luceneのインデックスファイルの構造は公開されているとおり、固定的なものである(それでもTermVectorやPayloadのオプションがON/OFFできたり、Field値の文字列の登録をON/OFFできたり、圧縮する/しないを選択することができたり、FieldのlengthNormをON/OFFできたりと、他の多くのOSS検索エンジンよりも相当に柔軟ではある)。 これを将来はpositionやfrequencyを省略したり、逆にpositionに対して付加情報を追加できるようにしたり、圧縮アルゴリズムを自由に選択できるようにしたり・・・という具合にインデックスへの登録内容の自由度をさらに高められるようにする。 アプリケーションの要件によって、インデックスに文書の関連情報を登録するのにも使えるほか、余分な情報を登録しないことでインデクシングや検索の性能向上にも貢献すると考えられる。 たとえば早速、term frequency情報を省略できるようにする、というパッチが提案されている: https://issues.apache.org/jira/browse/LUCENE-1340 frequencyを省略すればスコアにも影響が出るだろうが、スコアによる順位よりもフィールド値によるソートを多用するアプリケーションであれば気にならない。またフィールド単位でfrequency情報を省略するかどうか選べるので、frequencyがそもそも不要なフィルタ系のフィールド(県名や性別、ユーザ権限など)であればこれを導入するメリットは大きい。そのようなフィールドでfrequency情報の登録を行わないようにすれば、インデクシング時間を短くしたり、ディスクI/Oが減ることで検索性能を向上させたり、メモリ消費量を少なくしたり、ディスク消費量を減らせたり・・・と、少し考えただけでも相当な効果が望めるものである。 2008.02.05 Tuesday
IndexDeletionPolicyとSnapshotDeletionPolicy
Luceneのインデックスファイルはマージのタイミングで新しいセグメントファイルが作成されていく。ファイル名はxxx.cfsやsegments_yyyとなりxxxやyyyの部分はインクリメントされていくのでインデックスへの文書の登録中や最適化中であっても以前の(オープン時の)インデックスの内容で検索が可能となっている。
しかし古いインデックスのセグメントファイルはいつかのタイミングで消さなければならない。 Lucene 2.1以前はreaderがオープンしていないときに古いセグメントファイルを消していたが、Lucene 2.2からこのタイミングをコントロールできるようにIndexDeletionPolicyというインタフェースが導入された。デフォルトではKeepOnlyLastCommitDeletionPolicyが使われるようになっており、セグメントのコミットが完了したときに次のメソッドonCommit()が実行されるようになっている:
消されないまま残っているセグメントはコミットのListとして渡されるので、最新を残してdelete()しているのがわかる。 仮に次のような「何もしない」NullDeletionPolicyというものを定義してIndexWriterのコンストラクタに指定して使うようにすれば、インデックス内のファイルは消されずに増え続けることが観察できるだろう:
このようなIndexDeletionPolicyを使って、インデックスのある時点のスナップショットを取得できるSnapshotDeletionPolicyクラスがLucene 2.3に導入された。このクラスはインデックスのスナップショットを取得するsnapshot()メソッドと、取得したスナップショットを開放するrelease()メソッドを持つクラスである。snapshot()とrelease()呼び出しの間で取得したスナップショットのバックアップを取るような応用が考えられる。 具体的なコードは次のようになる:
「ここでバックアップを作成」の部分にバックアップのコードを挿入すれば、インデックスの更新を止めることなく検索で使用している最新のインデックスのバックアップを取ることができるようになる。 2008.02.02 Saturday
TermVectorMapper
Lucene 2.3から導入されたTermVectorMapperにより、term vectorによりアクセスしやすくなった。
Lucene 2.2以前はTermFreqVectorクラスを使うしかなかったが、TermFreqVectorは次のようなインタフェースであり、あまり使い勝手がよいものではなかった:
上記のように、単語と出現回数はString[]、int[]という具合に配列で戻ってくる。よって出現回数の多いもの順に並べるというようなことをしたいときは、Comparatorを別途用意し、Collections.sort()などを使ってソートする必要があり面倒である。Lucene本でもそのようにしている(P282-283)。 これに対してTermVectorMapperは次のようなインタフェースを持つ:
このTermVectorMapperの実装クラスを用意して次のようにIndexReaderに渡すと、適宜上記のメソッドが呼び出される。これによりTermFreqVectorよりも扱いやすいオブジェクトでterm vectorが取得できるようになった:
TermVectorMapperは自分で書くこともできるが、Lucene 2.3にはSortedTermVectorMapper、FieldSortedTermVectorMapperおよびPositionBasedTermVectorMapperの3つのTermVectorMapperがすでに用意されている。このうちSortedTermVectorMapperはもっとも基本的なTermVectorMapperであり、コンストラクタに渡したComparatorによってソートされたTermVectorEntryのSetが次のメソッドで取得できるようになっている:
以下ではこのSortedTermVectorMapperを使ったプログラムを紹介する。 TermVectorMapperのサンプルプログラム 「サンプルプログラム」というと「Hello, world!」という文字列を表示したりするのがプログラマの間では常識のようになっている。Wikipediaでも「Hello world program」という項目で説明されているほどだ(Wikipediaによれば、この有名な文字列を広める元となったThe C Programming Languageのサンプルプログラムでは"hello, world"だそうだ): Hello world program http://en.wikipedia.org/wiki/Hello_world とりあえずこのような文字列が決まっているとサンプルを提示するほうとしてはいろいろ悩まなくていいので簡単だ。 ところが私はLuceneのサンプルプログラムを示すときに「Hello, world!」はあまり使わない。というか、これまで使ったことがない。なぜなら2語しかないのでつまらないからだ。 私の場合、Luceneのサンプルプログラムで使うデータは「サザエさん」「メガネは顔の一部です」「内閣総理大臣所信表明演説」と大体決まっている。 「サザエさん」のデータは転置索引の説明に使ったり、次のようにLucene入門用プログラムのデータに使ったりしている: はじめてのLucene全文検索プログラム http://lucene.jugem.jp/?eid=67 形態素解析やN-gramのAnalyzerの出力には「メガネは顔の一部です」をという文字列を使っている。 そしてこの中で最も長文な「内閣総理大臣所信表明演説」は、TermFreqVectorのサンプルで使用することが多い。Lucene本でもTermFreqVectorのサンプルでは執筆当時の小泉首相の所信表明演説を分析し、「改革」や「郵政」「民営」「化」が頻出語トップ10に現れて面白かった。 安倍首相のときは、(TermFreqVectorではなくPayloadであったが)「美しい国」を連呼していることが見て取れることがわかった: 記事から名詞だけを取り出す http://lucene.jugem.jp/?eid=133 そこで今回のTermVectorMapperは福田首相の所信表明演説をデータとして使用することにする。 第168回国会における福田内閣総理大臣所信表明演説 平成19年10月1日 http://www.kantei.go.jp/jp/hukudaspeech/2007/10/01syosin.html TermVectorMapperを使って頻出語トップ10を表示するプログラムは次のようになる:
TermFreqVectorを使って同様のことを行うLucene本のプログラムと比べると、だいぶシンプルなプログラムになっている。 実行するには、分析したいテキストデータを適当なファイル名のファイルで用意しておき、プログラムの第一引数でそのファイル名を渡してやると頻出単語とその出現回数の表が画面に表示される:
どうせなので小泉首相、安倍首相、福田首相で結果を比較してみたところ、次のようになった。
3人の演説で共通に現れる単語には薄く色付けしてある。 これを見ると、小泉首相はトップに「改革」がきており、同じ改革路線を継承した形の安倍首相も「改革」がトップに来ているのがわかる。なぜか3人とも「国民」が2番目にきている。 逆に他の2人に(トップ10に)出現しない単語のそれぞれのトップは、小泉首相が「郵政」、安倍首相が「皆様」、福田首相が「向ける」となっている。この中で「皆様」に興味が引かれた私は、どのような使われ方をしているのかを調べた。すると、「国民の皆様」「野党の皆様」「被災者の皆様」「地方の皆様」という使われ方をしているのがわかり、いまさらながら若い首相の苦労が偲ばれたのだった。 なおプログラムの実行にあたっては、StopFilterやPOSFilterに「ストップワード」や「ストップ品詞」を適切に設定する必要がある。 (参考データ) 第168回国会における安倍内閣総理大臣所信表明演説 平成19年9月10日 http://www.kantei.go.jp/jp/abespeech/2007/09/10syosin.html 第163回国会における小泉内閣総理大臣所信表明演説 平成17年9月26日 http://www.kantei.go.jp/jp/koizumispeech/2005/09/26syosin.html 2008.01.09 Wednesday
Lucene 2.3でエンティティ抽出
現在、Lucene 2.3 RC1が公開中である。前回のリリースLucene 2.2からあっという間だった。
Lucene 2.2のリリース時は2.2の新機能を紹介しようと思い、サンプルプログラムを書きながら紹介記事を書いたりしたものだが、全部紹介しきらないうちにやがて新機能は「新」機能ではなくなり、そして今回の2.3のリリースを迎えることとなってしまった。 いったい、コミッターたちは自分たちの仕事をいつやっているのだろう。 ところで、Lucene 2.2のときは単語にペイロードを登録できるようになったので、それを中心に次のような利用例を紹介した: 記事から名詞だけを取り出す http://lucene.jugem.jp/?eid=133 人名がヒットしたときはスコアを上げる http://lucene.jugem.jp/?eid=134 今回は似たような雰囲気のする「エンティティ抽出」を、Lucene 2.3で新しく追加されたSinkTokenizerとTeeTokenFilterを使って実装する方法を紹介しよう。 エンティティ抽出とは? エンティティ抽出(entity extraction)とは文書から人名・地名・会社名・日付などを(自動)抽出することをいう。特に情報検索では抽出された「エンティティ」で絞り込み検索用のリンクを自動的に生成するなどの応用が可能となる。 つい先ほどマイクロソフトによる買収の発表があった検索エンジン大手のFAST社の製品はエンティティ抽出の機能を持つらしい。そんなFAST社による「Entity Extraction」という用語の説明はこうだ: http://www.fastsearch.com/glossary.aspx?m=48&amid=291 また、多言語形態素解析器などで知られるベイシス・テクノロジはエンティティ抽出のための製品も持っている: Rosette固有表現抽出システム http://www.basistech.co.jp/entity-extraction/ SinkTokenizerとTeeTokenFilter 今回紹介するエンティティ抽出のサンプルは、上記製品のように本格的なものではなく、形態素解析器(SenTokenizer)が出力するトークンのタイプを単純に判断して行うものとする。 ところで、Lucene 2.3になる前からSenTokenizerはトークンのタイプで「人名」や「地名」などとして品詞情報を出力できたので、やろうと思えば今までもエンティティ抽出は可能だった。今回あえてLucene 2.3でエンティティ抽出を紹介するのは、Lucene 2.3で追加されたSinkTokenizerとTeeTokenFilterでエンティティ抽出のようなプログラムを書くのが楽になった、ということがあげられる。 SinkTokenizerとTeeTokenFilterは必ず組み合わせて使うことが前提である。SinkTokenizerはトークンを保持するバッファを内蔵する。そのトークンはTeeTokenFilterを通じて受信(sink)する。TeeTokenFilterは他の一般のTokenFilterと同様、上流のTokenizerからTokenizeされたトークンを受け取り、あたかもLinuxのteeコマンドのようにトークンをコピーして一方をSinkTokenizerに渡す。もともとのトークンは下流のTokenFilterに渡す。そうしておいて、SinkTokenizerに滞留したトークンを別のTokenFilterで処理してエンティティ抽出を行うのだ。 SinkTokenizerとTeeTokenFilterを使ってエンティティ抽出を行うサンプルプログラムを次に示す:
このプログラムを実行すると、次のようになる:
分析対象の記事は、橋下徹弁護士、熊谷貞俊元大阪大大学院教授、梅田章二弁護士らが立候補するという大阪府知事選に関するもので、次を拝借した: 自民、橋下氏推薦見送り 大阪府知事選10日告示 http://www.tokyo-np.co.jp/s/article/2008010801000867.html 「橋下」が認識されていないこと、「熊谷貞俊」が「熊谷」「貞」と抽出されている以外は、きれいにエンティティが抽出できているのがわかるだろう(辞書をメンテナンスすればこれらも拾うことができる)。 この出力結果を漫然と見ているだけでは形態素解析器が出力している品詞情報との違いがわかりにくく、ありがたみが感じられないだろう。 このプログラムで重要なのは、抽出されたエンティティがオリジナルの文書と関連付けられて索引付けされているところだ。したがって、検索システムと組み合わせて次のような絞り込み検索用のリンクが自動的に作れるようになるのである:
2007.10.31 Wednesday
Luceneでベイズ分類(experimental)
Luceneのインデックスをベイズ分類に応用しようという実験的なパッチが提案されている:
LUCENE-1039 こちらの理論には素人なのでアルゴリズムは軽くスルーして、プログラムと実行結果を示す。 これを使えば、文章を学習させたLuceneインデックスを使って、別の新しい文章の分類ができる。 たとえば、こんな具合に「関西弁」と「標準語」を自動分類してくれる:
完璧では当然ないので、次のように間違うこともある(2番目は「政治」ではなく「芸能」と分類して欲しい):
ただ、学習の量が足りないだけなのかもしれない。 プログラムは次のとおりである:
なかなか楽しいプログラムなので、試したい人がいるかもしれない。そこで、LUCENE-1039のパッチの当て方とビルドの方法を簡単に説明しよう。 <1> パッチは大抵の場合、その時点の最新trunkのソースに合わせて提出されるため、trunkのソースをSVNから取得する:
これ以降、上記のオペレーションでできたtrunkディレクトリを$LUCENE_HOMEとする。 <2> LUCENE-1039からパッチファイルLUCENE-1039.txtをダウンロードして$LUCENE_HOMEに置き、次のようにパッチを当てる:
<3> LUCENE-1039のパッチがJava 5.0前提になっているので、次のbuild.propertiesを作成して$LUCENE_HOMEに配置する:
<4> Lucene本体をビルドする:
<5> contribのAnalyzerをビルドする:
<6> contribのclassifierをビルドする。今回のパッチにはbuild.xmlが含まれないので、contrib/analyzers/build.xmlをコピーして次のように編集してcontrib/classifier/build.xmlとする:
そしてclassifierをビルドする:
以上のビルドで$LUCENE_HOME/build/以下にできた3つのJARファイルを使って前述のプログラムをコンパイル、実行できる。 2007.10.19 Friday
RailsアプリからSolrを使う全文検索のデモ
RailsアプリケーションからSolrを使う全文検索のデモを作成したので公開する。
http://www.rondhuit-demo.com/yademo/ デモシステムの全体構成は、次のようになっている。 デモシステムは、「フロントアプリサーバ」と「検索エンジンサーバ」の2つのサーバプロセスからなる。 「検索エンジンサーバ」はTomcatの上にSolrをデプロイして構成している。「フロントアプリサーバ」にはRailsで作られたアプリケーションが載っており、これがバックエンドの「検索エンジンサーバ」に検索のリクエストを送っている。そしてSolrから返ってきた検索結果をHTMLにしてブラウザに戻している。 上図の「フロントアプリサーバ」にはRailsという記述がないが、Flareと書いてあるのがRailsで構築されたSolrクライアントアプリケーションだ。このFlareがsolr-rubyを使ってSolrとの検索リクエスト/レスポンスの処理を行っている。 デモデータには「Yahoo!オークション」の商品データ約201万件を使用している。このデモデータはYahoo!のWebサービスAPIを使用して2007年7月から9月頃にかけてクロールして収集したものである。 検索の結果表示される商品説明はクロールしたHTMLをそのまま表示しているため、検索結果画面が多少乱れたり、画像抜けが起こったりする部分がある。また、本デモにはYahoo!オークションとしての機能は一切なく、単なる全文検索システムのデモであることをあらかじめお断りしておく。 このデモの使い方や特徴を以下で簡単に述べる。 検索キーワードサジェスチョン Flareのセールスポイントの一つが「検索キーワードのサジェスチョン」機能である。これはGoogle Suggestなどでおなじみのものだ。 「検索キーワードのサジェスチョン」は検索キーワードの最初の数文字を入力すると、ユーザが検索ボタンをクリックする前にシステムがバックグラウンドで検索を行い、検索ヒット数と共に検索キーワードの候補をユーザに提示してくれるものだ。 ユーザにとって「タイプ量が節約できる」「他人の検索キーワードからヒントが得られる」「検索ボタンをクリックする前にどのくらい絞り込めるのかがわかる」など、多くのメリットがあるのがこの機能の特徴である。Flareはこれを最初から提供している。しかもRailsプログラマの期待を裏切ることなく、簡単な「規約」にしたがうだけでこの強力な機能がUIについてくるので製作側にとってもメリットが大きい。 Flareのサジェスチョン機能はGoogleと異なり、あくまでもLuceneのインデックスを使ってサジェスチョンしているので、サジェスチョンの単位が「語」にとどまっている。また、その仕組み上から背後では膨大な計算が行われており、ドキュメント数やユーザ数が多い場合に応答速度の点で若干難がある。さらに上図のようにカタカナ1文字で「ソ」と入力する場面は(ローマ字変換入力の場合)日本語ではあまりないと考えられるので、日本語での利用を考えたときには別の仕組みが必要である。したがって、Flareの「検索キーワードのサジェスチョン」は使えるアプリケーションかどうかをよく考えて導入するのがよいだろう。なお、これらの問題点を解消した「検索キーワードのサジェスチョン」を弊社で開発中である。 絞り込み検索 FlareのデフォルトのUIでは、画面右側に自動的に絞り込み検索用のリンクが作成・表示される。Yahoo!オークションの商品データを使用したこのデモでは、Yahoo!オークションのカテゴリ(category)と出品者(seller_id)の上位20位までが表示されている。 絞り込み検索では、リンクをクリックするだけで簡単に検索結果を絞り込むことができるようになっているため、ユーザからの人気が高い機能の一つである。この機能もFlareの簡単な「規約」にしたがうだけで使うことができる。 検索条件の保存 Flareでは検索窓に入力した検索キーワードと、絞り込み検索でクリックしたリンクを「検索条件」としてCookieに保存している。その内容は画面左上のFlareのロゴ(このロゴ画像はいくつかあるベータ版のうちのひとつであり、将来変わる可能性がある)の下に表示されている。 検索のたびにこの条件は追加・保存されるので、新たな検索のときは[clear constraints]のリンクをクリックしてそれまでの検索条件を消去する。あるいは、各検索条件の右隣にある小さな[x]のアイコンをクリックして当該検索条件だけを削除することもできる。さらに、検索条件をクリックすると、検索条件をその場で変更して再検索もできる。 このUIはRailsプログラマにはおなじみのものだろう。 2007.08.27 Monday
クチコミの評判の悪い店のランキングを下げる
私はLuceneおよびSolr(最近はこちらの方がLuceneよりも多い)のコンサルティングやサポートを顧客に提供することを生業としている。
いろいろな顧客の話を聞いていると、ランキング(検索結果のドキュメントの表示順のこと)を意図的に操作して出力したい、という要望が予想以上に多いのに驚く。 たとえば、「自分の家から一番近いレストランを探す(地理検索、地図検索)」で書いたようなある場所(現在地や最寄り駅)から近い順にお店情報を表示する、などである。 あるいは、「FunctionQueryの実用的なサンプル」で紹介したように、検索語の出現位置でランキングを操作する、という要求もあった。 この他にもサイト運営者への「掲載料」の支払い額で企業がランクわけがされていて、掲載料をたくさん支払っている優良顧客の情報をtf*idfとは関係なく上位に持ってきてほしい、という要望も意外に多い。 このような、ランキングへの顧客の多様な要求に柔軟に対応できるのもLuceneの隠れた大きな特徴のひとつである。 今回はBoostingQueryを使って「クチコミの評判の悪い店」のランキングを意図的に下げる、ということを実装してみる。 BoostingQueryとは BoostingQueryは、オリジナルのQueryインスタンスorigQueryに、マイナス評価を与えるnegativeQueryを組み合わせ、さらにマイナス評価に該当したときに指定した降格係数(まったくの私の造語だが、1未満のboost値のこと)を掛けて最終的なスコアとするQueryである。BoostingQueryのインスタンスを得るには、降格係数をdemoteBoostとすると、次のようにプログラミングする:
あとは普通にqueryをIndexSearcherのsearch()に渡せばよい。 BoostingQueryのnegativeQueryは、仕様をちょっと聞くとBooleanQueryのMUST_NOTとなんか似ている。しかし、両者はまったく異なるものである。 BooleanQueryのMUST_NOTは、指定したQueryにヒットするドキュメントは検索結果には含まれない、まったくの「否定」となる。 一方、BoostingQueryのnegativeQueryはMUST_NOTのように「否定」ではないので、negativeQueryにヒットしたドキュメントが検索結果からはじかれる、ということはない。ただ、negativeQueryにヒットしたドキュメントのスコアはdemoteBoostの値が掛けられるのである。それにより、origQueryにヒットしたドキュメントのうち、さらにnegativeQueryに該当するドキュメントのスコアを下げることができる(あるいは、demoteBoostを1より大きくとることで、negativeQuery(この場合はpositiveQueryと呼ぶべきであろう)に該当するドキュメントのスコアを上げることができる)。 なお、BoostingQueryはLucene coreではなくcontrib/queriesにあるので、contrib/queriesよりlucene-queries-x.x.jarを持ってきてクラスパス上に配置する必要がある。 BoostingQueryのサンプルプログラム まず、次のようなサンプルドキュメントとサンプルの検索文字列を用意する:
これをBoostingQueryを使わずに普通に検索すると、次のような結果になるだろう:
スコア(検索結果の前に表示されている実数)はどちらの検索文字列でも1.0と等しくなるので、この場合のランキングはドキュメントの登録順に表示されている。そして、「まずい」や「おいしくない」というマイナス評価のドキュメントを先に登録しているので、「おいしい」や「お奨めです」より前に表示されてしまっている。 このプログラムを、demoteBoost=0.1にしたBoostingQueryを使って検索すると、次のようになる:
BoostingQueryを使った全体のプログラムは次のとおりである:
NEGATIVE_EVALSという文字列配列に「まずい」や「おいしくない」などのマイナス評価を示す文言を登録してあり、それをもとにnegativeQueryのインスタンスを作成している。当然のことながら、これらに合致しない文言は評判が悪いとは認識されない。 2007.08.11 Saturday
WildcardTermEnumを使う
Luceneのインデックスにはフィールドごとに整理された単語帳がある。単語帳の単語はソートされた状態で格納されており、TermEnumを使ってその中の単語を列挙することができる。
次のプログラムは「通」という単語から開始してTermを列挙する例である:
TermEnumはTerm(=フィールド名+フィールド値)を列挙するものであるから、ループをまわしていくとTermがいつの間にか目的外のフィールドを指していることがありえるので、赤字の判定行が必要となる。 このプログラムをあるインデックスに対して実行すると、次のような出力が得られる:
上記のように「通」から始まり、単語帳の指定フィールドの単語が尽きるまでTermが列挙されるのがわかる。 ここでTermEnumの代わりにWildcardTermEnumを使うと「通」で開始する単語だけを列挙することが可能となる。 WildcardTermEnumは、次のように使う:
このときの出力は、次のようになる:
「前方一致」だけでなく、「後方一致」も指定可能だ:
このときの出力は、次のようになる:
2007.07.25 Wednesday
NGramTokenizerとEdgeNGramTokenFilter
Lucene 2.2のcontribにN-gramで単語を切り出すNGramTokenizerとEdgeNGramTokenFilterが追加された(同時にEdgeNGramTokenizerとNGramTokenFilterも追加されたが、これらはあまり使われない気がする)。
これまでLuceneのN-gram Analyzerといえば、CJKAnalyzerであった。これはCJK文字のときにだけ2文字単位で切り出すもので、bi-gramとも呼ばれるものである。 CJKAnalyzerのサンプルプログラムを以下に示す:
このプログラムを実行すると、次のようになる:
CJKAnalyzerは上記のように日本語の文字を2文字単位に切り出す。このとき、となりどうしのトークンの文字が互いに重なるように切り出すのがN-gramの特徴である。たとえば、「メガネ」は「メガ」と「ガネ」に分割される。こうすることで後に「メガネ」で検索するときにも「(メガ)(ガネ)」という成句で検索されるために文章中の「メガネ」がうまい具合に検索できるのだ。 CJKAnalyzerを使う動機としては、(形態素解析の)JapaneseAnalyzerと比較して辞書のメンテナンスが不要で流行語に強い、などが理由にあげられる。 一方、CJKAnalyzerを敬遠する理由としては、(Lucene本にも書いた例だが)「京都」で引いたときに「東京都」が引っかかってしまうとか(これはGoogleでもみられる現象だ)、1文字の単語が検索できない、などがあげられる。「京都」で「東京都」が検索できてしまうのは目をつぶれるとしても、後者は特に困った問題である。たとえば、先のサンプルの例文はCJKAnalyzerを使っているときは、「顔」という検索語では検索できない。 NGramTokenizer NGramTokenizerはコンストラクタで指定した大きさのトークンを文章から切り出すTokenizerである。たとえば、次のように指定すると、bi-gramとして動作する:
また次のようにすれば、3文字ずつ切り出すtri-gramとして働くようになる:
これだけだとただ単にCJKAnalyzerがちょっと発展したくらいにしか思えないが、次のようにすることで1〜3文字を切り出すように動作するのがNGramTokenizerの便利なところだ:
これをCJKAnalyzerの代わりに使用すれば、先ほどの「顔」で検索できない、という問題も解消できる。 具体的なプログラムを示すと、まずNGramTokenizerはAnalyzerではないので、使用するにはAnalyzerを作成する必要がある。簡単なAnalyzerは次のようなプログラムになるだろう:
上記のMyAnalyzerを最初のプログラム例のCJKAnalyzerと入れ替えて使用する。そして実行すると、次のようになる:
EdgeNGramTokenFilter EdgeNGramTokenFilterの用途としてはおそらく、形態素解析で切り出された単語をさらにN-gramで分割するときに使用するものと考えられる。 先ほどのMyAnalyzerのプログラムをWhitespaceAnalyzerとEdgeNGramTokenFilterを使うように、次のように変更してみる:
そして(WhitespaceAnalyzerなので)適当な英文を選んで最初のプログラムのTEXTに代入して実行すると、次のようになる:
WhitespaceAnalyzerの代わりにJapaneseAnalyzerを使用すれば、日本語を形態素解析した後にそれぞれの単語をさらにN-gramで分割する、ということができるはずなので、興味のある人はやってみていただきたい。 |
+ 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 |