関口宏司のLuceneブログ

OSS検索ライブラリのLuceneおよびそのサブプロジェクト(Solr/Tika/Mahoutなど)について
<< Lucene 2.3のリリース | main | IndexDeletionPolicyとSnapshotDeletionPolicy >>
TermVectorMapper
Lucene 2.3から導入されたTermVectorMapperにより、term vectorによりアクセスしやすくなった。

Lucene 2.2以前はTermFreqVectorクラスを使うしかなかったが、TermFreqVectorは次のようなインタフェースであり、あまり使い勝手がよいものではなかった:



public interface TermFreqVector {
public String getField();
public int size();
public String[] getTerms();
public int[] getTermFrequencies();
:
}



上記のように、単語と出現回数はString[]、int[]という具合に配列で戻ってくる。よって出現回数の多いもの順に並べるというようなことをしたいときは、Comparatorを別途用意し、Collections.sort()などを使ってソートする必要があり面倒である。Lucene本でもそのようにしている(P282-283)。

これに対してTermVectorMapperは次のようなインタフェースを持つ:



public abstract class TermVectorMapper {
:
public abstract void setExpectations(String field, int numTerms,
boolean storeOffsets, boolean storePositions);
public abstract void map(String term, int frequency,
TermVectorOffsetInfo [] offsets, int [] positions);
:
}



このTermVectorMapperの実装クラスを用意して次のようにIndexReaderに渡すと、適宜上記のメソッドが呼び出される。これによりTermFreqVectorよりも扱いやすいオブジェクトでterm vectorが取得できるようになった:



public void getTermFreqVector(int docNumber, String field, TermVectorMapper mapper);



TermVectorMapperは自分で書くこともできるが、Lucene 2.3にはSortedTermVectorMapper、FieldSortedTermVectorMapperおよびPositionBasedTermVectorMapperの3つのTermVectorMapperがすでに用意されている。このうちSortedTermVectorMapperはもっとも基本的なTermVectorMapperであり、コンストラクタに渡したComparatorによってソートされたTermVectorEntryのSetが次のメソッドで取得できるようになっている:



public SortedSet getTermVectorEntrySet();



以下ではこの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を表示するプログラムは次のようになる:



public class FileTermVector {

static Directory dir = new RAMDirectory();
static Analyzer analyzer = new JapaneseAnalyzer();
static final String F = "F";
static final int MAX = 10;

public static void main(String[] args) throws IOException {
makeIndex( args[0] );
printSortedTVM();
}

static void makeIndex( String file ) throws IOException {
BufferedReader br = new BufferedReader( new FileReader( file ) );
IndexWriter writer = new IndexWriter( dir, analyzer, MaxFieldLength.LIMITED );
Document doc = new Document();
for( String line = br.readLine(); line != null; line = br.readLine() ){
doc.add( new Field( F, line, Store.YES, Index.TOKENIZED, TermVector.YES ) );
}
writer.addDocument( doc );
writer.close();
br.close();
}

static void printSortedTVM() throws IOException {
IndexReader reader = IndexReader.open( dir );
SortedTermVectorMapper mapper = new SortedTermVectorMapper( new TermVectorEntryFreqSortedComparator() );
reader.getTermFreqVector( 0, F, mapper );
SortedSet ss = mapper.getTermVectorEntrySet();
int count = 0;
for( Iterator i = ss.iterator(); i.hasNext() && count < MAX; count++ ){
TermVectorEntry entry = (TermVectorEntry)i.next();
System.out.println( entry.getTerm() + " : " + entry.getFrequency() + " 回" );
}
reader.close();
}
}



TermFreqVectorを使って同様のことを行うLucene本のプログラムと比べると、だいぶシンプルなプログラムになっている。

実行するには、分析したいテキストデータを適当なファイル名のファイルで用意しておき、プログラムの第一引数でそのファイル名を渡してやると頻出単語とその出現回数の表が画面に表示される:



社会 : 26 回
国民 : 24 回
的 : 24 回
改革 : 19 回
向ける : 18 回
問題 : 18 回
進める : 15 回
行政 : 14 回
取り組む : 13 回
地方 : 13 回



どうせなので小泉首相、安倍首相、福田首相で結果を比較してみたところ、次のようになった。

小泉安倍福田
改革23改革18社会26
国民22国民16国民24
171424
郵政14皆様12改革19
民営1311向ける18
10取り組む11問題18
民間8地方11進める15
社会8地域9行政14
地方7日本9取り組む13
公務員6環境9地方13


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

| 関口宏司 | Lucene自由自在 | 20:37 | comments(13) | trackbacks(0) |
サンプルプログラムをeclipseでやってみたのですが、 MaxFieldLength.LIMITED で赤線になるのですが、これはどう処理すれば直りますか?
| moon | 2008/07/17 9:03 PM |
Luceneは2.3.xを使っていますか?赤線にカーソルを合わせると、どのようなエラーメッセージが表示されますか?
| 関口 | 2008/07/17 10:15 PM |
はい。lucene 2.3.2を使っています。APIみてもboolen型だったので、MaxFieldLength.LIMITEDをtrueに変えてやってみたら動きました。
| moon | 2008/07/19 9:29 PM |
おっと、ここでのサンプルプログラムはLucene 2.3と文章中では言いながら、Lucene 2.4のAPIがまじってしまっていますね。失礼しました。
| 関口 | 2008/07/19 10:14 PM |
ちなみに、ここでのIndexWriterのコンストラクタは以下の記事で説明しています:

http://lucene.jugem.jp/?eid=223
| 関口 | 2008/07/19 10:22 PM |
ありがとうございます。^^
なんかluceneって楽しいですね。現在、TermVectorMapperを使ってterm-document-matrixを作ってみて、それからtf-idfの重みをつけようと思っています。なかなかうまくいかにです。T.T
| moon | 2008/07/19 10:51 PM |
ある文書を索引付して、索引付づけ(tf-idfで重みづけ)した文書をQueryとしてベクトルモデルで検索を行ってみたいのですが、アドバイスお願いします。
| moon | 2008/07/20 2:42 PM |
いつもお世話になっています。後半のところのStopFilterやPOSFilterに「ストップワード」や「ストップ品詞」を適切に設定する必要であると書いているんですけどこのプラグラムで名詞だけを抽出するためには具体的にどのようにすればよいですか?
| katuya | 2008/08/15 10:58 PM |
> このプラグラムで名詞だけを抽出するためには具体的にどのようにすればよいですか?

このプログラムではJapaneseAnalyzerを使用していますが、このAnalyzerは内部にPOSFilterを含んでいます。そのPOSFilterの設定で名詞だけを通すようにします。具体的なやり方はLucene本等を参照してください。
| 関口 | 2008/08/16 2:10 AM |
ありがとうございます。本を読みながらやっているんですが(本p49の2.2.6)、analyzer-sen.xmlを別名のファイルにコピーしてそちらを編集し、システムプロパティorg,apache.kucene.ja.config.fileにそのファイル名を指定すればよいというところがよく理解できません。
eclipseで一応mainのところに
System.setProperty("sen.home", "C:¥¥sen-1.2.2.1");
のようにしてはできたのですが、自分が作成したanalyzerをどのようにeclipse上に書き込めばいいかそこが分かりません。javaの初心者なので^^;
| katuya | 2008/08/16 11:03 PM |
> analyzer-sen.xmlを別名のファイルにコピーしてそちらを編集し、システムプロパティorg,apache.kucene.ja.config.fileにそのファイル名を指定すればよいというところがよく理解できません。

Lucene本のまさにその次のところにやり方がそのまま書いてありますが。:-P
あるいは、

> System.setProperty("sen.home", "C:¥¥sen-1.2.2.1");

こちらができているのであれば、同じようにして:

System.setProperty("org.apache.lucene.ja.config.file","/path/to/your-analyzer-sen.xml");

とすればいいのではないでしょうか。
| 関口 | 2008/08/17 12:10 AM |
お世話になってます。前回のやつは解決しました。

まず、analyzerを自分なりに作成してそれをjarファイルに作ってbuiled pathに追加してからやったらできました。
jarファイルを作らずにやるとできないのでした。
ありがとうございました。

それと、このプログラムで出現回数が1回の単語だけを表示したいのですが、どのようにすればよいのでしょうか?
| katuya | 2008/08/28 9:28 PM |
1回の出現回数だけを表示するのはやはり簡単でした。
とにかくありがとうございます。
| katuya | 2008/08/28 9:36 PM |









http://lucene.jugem.jp/trackback/178
+ Solrによるブログ内検索
+ PROFILE
      1
2345678
9101112131415
16171819202122
23242526272829
30      
<< September 2018 >>
+ 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