関口宏司のLuceneブログ

OSS検索ライブラリのLuceneおよびそのサブプロジェクト(Solr/Tika/Mahoutなど)について
<< deprecatedとなったQueryFilter | main | WildcardTermEnumを使う >>
NGramTokenizerとEdgeNGramTokenFilter
Lucene 2.2のcontribにN-gramで単語を切り出すNGramTokenizerとEdgeNGramTokenFilterが追加された(同時にEdgeNGramTokenizerとNGramTokenFilterも追加されたが、これらはあまり使われない気がする)。

これまでLuceneのN-gram Analyzerといえば、CJKAnalyzerであった。これはCJK文字のときにだけ2文字単位で切り出すもので、bi-gramとも呼ばれるものである。

CJKAnalyzerのサンプルプログラムを以下に示す:



public class TestNgramAnalyzer {

private static Analyzer analyzer = new CJKAnalyzer();
private static final String TEXT = "メガネは顔の一部です。";

public static void main(String[] args) throws IOException {
TokenStream stream = analyzer.tokenStream( "F", new StringReader( TEXT ) );
StringBuffer sb = new StringBuffer();
for( Token token = stream.next(); token != null; token = stream.next() ){
//System.out.println( token.toString() );
sb.append( '[' ).append( token.termText() ).append( "] " );
}
stream.close();
System.out.println( TEXT + " => " + sb.toString() );
}
}



このプログラムを実行すると、次のようになる:



メガネは顔の一部です。 => [メガ] [ガネ] [ネは] [は顔] [顔の] [の一] [一部]
[部で] [です]



CJKAnalyzerは上記のように日本語の文字を2文字単位に切り出す。このとき、となりどうしのトークンの文字が互いに重なるように切り出すのがN-gramの特徴である。たとえば、「メガネ」は「メガ」と「ガネ」に分割される。こうすることで後に「メガネ」で検索するときにも「(メガ)(ガネ)」という成句で検索されるために文章中の「メガネ」がうまい具合に検索できるのだ。

CJKAnalyzerを使う動機としては、(形態素解析の)JapaneseAnalyzerと比較して辞書のメンテナンスが不要で流行語に強い、などが理由にあげられる。

一方、CJKAnalyzerを敬遠する理由としては、(Lucene本にも書いた例だが)「京都」で引いたときに「東京都」が引っかかってしまうとか(これはGoogleでもみられる現象だ)、1文字の単語が検索できない、などがあげられる。「京都」で「東京都」が検索できてしまうのは目をつぶれるとしても、後者は特に困った問題である。たとえば、先のサンプルの例文はCJKAnalyzerを使っているときは、「顔」という検索語では検索できない。

NGramTokenizer

NGramTokenizerはコンストラクタで指定した大きさのトークンを文章から切り出すTokenizerである。たとえば、次のように指定すると、bi-gramとして動作する:



new NGramTokenizer( reader, 2, 2 );



また次のようにすれば、3文字ずつ切り出すtri-gramとして働くようになる:



new NGramTokenizer( reader, 3, 3 );



これだけだとただ単にCJKAnalyzerがちょっと発展したくらいにしか思えないが、次のようにすることで1〜3文字を切り出すように動作するのがNGramTokenizerの便利なところだ:



new NGramTokenizer( reader, 1, 3 );



これをCJKAnalyzerの代わりに使用すれば、先ほどの「顔」で検索できない、という問題も解消できる。

具体的なプログラムを示すと、まずNGramTokenizerはAnalyzerではないので、使用するにはAnalyzerを作成する必要がある。簡単なAnalyzerは次のようなプログラムになるだろう:




static class MyAnalyzer extends Analyzer {
public TokenStream tokenStream(String fieldName, Reader reader) {
return new NGramTokenizer( reader, 1, 3 );
}
}



上記のMyAnalyzerを最初のプログラム例のCJKAnalyzerと入れ替えて使用する。そして実行すると、次のようになる:



メガネは顔の一部です。 => [メ] [ガ] [ネ] [は] [顔] [の] [一] [部] [で] [す] [。]
[メガ] [ガネ] [ネは] [は顔] [顔の] [の一] [一部] [部で] [です] [す。] [メガネ]
[ガネは] [ネは顔] [は顔の] [顔の一] [の一部] [一部で] [部です] [です。]



EdgeNGramTokenFilter

EdgeNGramTokenFilterの用途としてはおそらく、形態素解析で切り出された単語をさらにN-gramで分割するときに使用するものと考えられる。

先ほどのMyAnalyzerのプログラムをWhitespaceAnalyzerとEdgeNGramTokenFilterを使うように、次のように変更してみる:



static class MyAnalyzer extends Analyzer {
public TokenStream tokenStream(String fieldName, Reader reader) {
TokenStream stream = new WhitespaceTokenizer( reader );
return new EdgeNGramTokenFilter(stream, Side.FRONT, 1, 4 );
}
}



そして(WhitespaceAnalyzerなので)適当な英文を選んで最初のプログラムのTEXTに代入して実行すると、次のようになる:



The iPhone results sent A&T stock down slightly. => [T] [Th] [The] [i] [iP] [iPh
] [iPho] [r] [re] [res] [resu] [s] [se] [sen] [sent] [A] [A&] [A&T] [s] [st] [st
o] [stoc] [d] [do] [dow] [down] [s] [sl] [sli] [slig]



WhitespaceAnalyzerの代わりにJapaneseAnalyzerを使用すれば、日本語を形態素解析した後にそれぞれの単語をさらにN-gramで分割する、ということができるはずなので、興味のある人はやってみていただきたい。
| 関口宏司 | Lucene自由自在 | 01:15 | comments(0) | trackbacks(1) |









http://lucene.jugem.jp/trackback/138
[Java]スペルミス修正プログラムを作ろう Ver. Java
「第11回 Kansai.pm / スペルミス修正プログラムを作ろう - naoyaのはてなダイアリー」を読んで、面白そうだし、なんだか作れそうな気がした。 処理の概要はこんな感じ。 入力されたキーワードに対して、正しいスペルの候補を返す。 正しいスペルの候補ははてなキーワ
| techlog | 2009/03/29 11:12 PM |
+ Solrによるブログ内検索
+ PROFILE
  12345
6789101112
13141516171819
20212223242526
2728293031  
<< August 2017 >>
+ 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