Lucene8:Tokenizerの選択が元文書のオフセット位置取得を左右する
ここで取り上げるのはLucene 8.2.0だ。
さんざんLuceneを使ってきて、今回初めてHighlighterの機能を試そうとしてうまく行かず、重要な事実に初めて気がついた。全く知らなかったのだが、表題の通りだ。
Luceneでは元文書を一つのTokenizer、複数のフィルターで処理してTermを取得するのだが、このTokenizerの選択が元文書のオフセット位置に影響してしまう。
次の二つのテストを見てみる。両者ともに入力は「吾輩は猫である」だ。
前者では、NGramTokenizerのみを使用している。後者ではWhitespaceTokenizerの後にNGramFilterを使用している。これだけの違いだ。
@Test
public void tokenizer1() throws Exception {
try (Analyzer an = new Analyzer() {
protected TokenStreamComponents createComponents(String fieldName) {
NGramTokenizer tokenizer = new NGramTokenizer(1, 2);
return new TokenStreamComponents(tokenizer, tokenizer);
}
}) {
TokenStream stream = an.tokenStream(null, "吾輩は猫である");
stream.reset();
CharTermAttribute t = stream.getAttribute(CharTermAttribute.class);
OffsetAttribute o = stream.getAttribute(OffsetAttribute.class);
System.out.println("\nNGramTokenizer");
while (stream.incrementToken()) {
System.out.println(t + ",offset " + o.startOffset() + ":" + o.endOffset());
}
}
}
@Test
public void tokenizer2() throws Exception {
try (Analyzer an = new Analyzer() {
protected TokenStreamComponents createComponents(String fieldName) {
Tokenizer tokenizer = new WhitespaceTokenizer();
NGramTokenFilter filter = new NGramTokenFilter(tokenizer, 1, 2, false);
return new TokenStreamComponents(tokenizer, filter);
}
}) {
TokenStream stream = an.tokenStream(null, "吾輩は猫である");
stream.reset();
CharTermAttribute t = stream.getAttribute(CharTermAttribute.class);
OffsetAttribute o = stream.getAttribute(OffsetAttribute.class);
System.out.println("\nWhitespaceTokenizer");
while (stream.incrementToken()) {
System.out.println(t + ",offset " + o.startOffset() + ":" + o.endOffset());
}
}
}
入力文には空白が無いので、どちらも同じ結果かと思いきや、結果は以下だ。
NGramTokenizer
吾,offset 0:1
吾輩,offset 0:2
輩,offset 1:2
輩は,offset 1:3
は,offset 2:3
は猫,offset 2:4
猫,offset 3:4
猫で,offset 3:5
で,offset 4:5
であ,offset 4:6
あ,offset 5:6
ある,offset 5:7
る,offset 6:7
WhitespaceTokenizer
吾,offset 0:7
吾輩,offset 0:7
輩,offset 0:7
輩は,offset 0:7
は,offset 0:7
は猫,offset 0:7
猫,offset 0:7
猫で,offset 0:7
で,offset 0:7
であ,offset 0:7
あ,offset 0:7
ある,offset 0:7
る,offset 0:7
後者では、常に取得位置が0,7になってしまっている。WhitespaceTokenizerが0,7位置しか返していないせいだ。この状態でHighlighterを使うと、当然ながら常に0.7の範囲をハイライトしてしまう。
TokenizerとTokenFilterの違いがなぜあるのか理解できなかったのだが、ここに来て重大な違いのあることがわかった。
ディスカッション
コメント一覧
まだ、コメントがありません