SennaによるN-gramインデックスで注意すべき挙動

追記:以下の文書について

現在リリースされているSenna 1.0.7では、
N-gramで1文字の日本語を検索する場合は
直接部分一致検索を動作させるようにしました。

というわけで、以下で説明している挙動は今現在当てはまりません。

1文字の単語について

uchiuchiyamaさんのブログにあった、Sennaのクエリ書式に対する質問
http://d.hatena.ne.jp/uchiuchiyama/20070317/senna_query_problem


この問題ですが、
おそらくN-gramでインデックスを作成している場合に起こっていると考えられます。


SennaN-gramインデックスはbi-gram、
すなわち2文字を1つのトークンとみなし、
インデックスへの登録を行っています。


ということは、文書の末尾を除いて、
すべてのトークンは2文字となり、
1文字のトークンで検索をしても検索結果が存在しません。


そこで、Sennaは内部的に単語の部分一致検索を行い、
ある1文字を含むトークンすべてについての検索結果を併せて返します。
この「部分一致検索を行うかどうか」の判定は、
「クエリ全体を評価した検索結果件数がn件以下かどうか」を見て判断しています。
デフォルトでn=0です。


さて、「壺」というクエリは1文字ですので、
このまま検索を行うと、
文書末に「壺」という文字を持つ文書しかひっかかりません。
通常はそのような文書はないので、
クエリ全体を評価した検索結果件数が0件となり、
部分一致検索を行います。


「これ OR 壺」といったクエリを実行した場合を考えます。
まず、「これ」というトークンを含む文書を検索します。
2文字のトークンなので、検索結果が存在します。
次に、「壺」というトークンを含む文書を検索します。
1文字のトークンなので、検索結果が通常は存在しません。
そして、2つの検索結果をORでつなぐと、
結局「これ」というトークンを含む文書セットが結果となってしまいます。
その検索結果件数は0ではないので、部分一致検索が行われることがなく、
そのまま検索結果を出力してしまいます。


よって、uchiuchiyamaさんのところのような現象が起きてしまうのです。
この問題については、
1文字のクエリを実行する場合には最初から部分一致検索を動かしてしまうことによって
対処したいと考えております。

英単語、数値、記号について

SennaN-gramインデックスは、字種によってトークンの長さが変わります。
具体的には、英文字、数字、記号の場合は、
連続する同じ種類の文字を1つのトークンとして切り出します。


また、N-gramでもMeCabでも英単語、数字、記号は
後方一致検索ができないように設定してあります。


これは技術的な問題ではなく、
インデックスサイズが膨れ上がるコストに対して、
検索結果の精度があがるベネフィットが少ないためです。


英単語の場合は、語尾が変化することがあるので
前方一致検索が必要なケースは多いと思いますが、
後方一致検索が必要なケースがそれほど多いとは思わないからです。


ただし、型番検索などで、
英単語、数字、記号の検索で漏れをなくしたい!!!
といった用途も考えられます。


そこでSennaでは、
sen_index_create関数にて
sen_split_alpha/sen_split_digit/sen_split_symbol
のそれぞれのフラグを指定することによって、
それぞれの字種のトークンを2文字で区切るように設定することができます。
上記フラグを活用すれば、型番を漏れなく検索することが実現できるでしょう。


しかし、上記のフラグ指定は
現行のTritonn/Ludiaではまだ対応がなされていません。
[追記]
Ludiaでは対応しているそうです!!!

今後に期待しましょう!!!