orangain flavor

じっくりコトコト煮込んだみかん2。知らないことを知りたい。

Groongaで複数のトークナイザを使い分ける方法

はじめに

全文検索エンジン Groonga を使っていると、トークナイザによる検索結果の違いを比較したくなる時があります。

しかし、検索時に利用するインデックスを明示的に指定する方法は、現時点ではドキュメント化されていないようです。

4.7.2. インデックス名を指定した全文検索

執筆中です。

いろいろと試した結果、同じテーブルに対して複数のトークナイザによるインデックスを作成し、select時に使い分ける方法がわかったのでまとめておきます。なお、対象のバージョンは執筆時点で最新の 3.0.7 です。

利用するスキーマ

Blogテーブルの検索結果を、TokenBigramTokenMecabの2種類のトークナイザで比較するケースを考えます。

検索対象のテーブル「Blog」

titlebodyカラムを持ちます。

table_create  --name Blog --flags TABLE_HASH_KEY \
              --key_type ShortText
column_create --table Blog --name title --type ShortText
column_create --table Blog --name body --type ShortText

 Bigramによる索引テーブル「BigramTerms」

Blogtitlebodyに対して、TokenBigramで索引blog_indexを作ります。

table_create  --name BigramTerms \
              --flags TABLE_PAT_KEY|KEY_NORMALIZE \
              --key_type ShortText --default_tokenizer TokenBigram
column_create --table BigramTerms --name blog_index \
              --flags COLUMN_INDEX|WITH_POSITION|WITH_SECTION \
              --type Blog --source title,body

 Mecabによる索引テーブル「MecabTerms」

Blogtitlebodyに対して、TokenMecabで索引blog_indexを作ります。

table_create  --name MecabTerms \
              --flags TABLE_PAT_KEY|KEY_NORMALIZE \
              --key_type ShortText --default_tokenizer TokenMecab
column_create --table MecabTerms --name blog_index \
               --flags COLUMN_INDEX|WITH_POSITION|WITH_SECTION \
               --type Blog --source title,body

検索時にインデックスを指定する方法

以下のように--match_columnsにインデックス名を指定することで、インデックスを使い分けることができます。

BigramTermsで検索したい場合:

select --table Blog --match_columns BigramTerms.blog_index \
       --query foo

MecabTermsで検索したい場合:

select --table Blog --match_columns MecabTerms.blog_index \
       --query foo

なお、以下のようにカラム名だけを指定した場合は、どちらかのインデックスが使われるようですが、そのルールは不明です。

select --table Blog --match_columns 'title || body' --query foo

重み付けしたい場合

このようにしてインデックスを使い分けることができますが、カラムによって重み付けしたい場合があります。通常であれば、--match_columns 'title * 5 || body'のようにしてtitleを重視するといったことができますが、インデックスを明示したい場合はそうはいきません。

最初は --match_columns 'BigramTerms.blog_index.title * 5 || BigramTerms.blog_index.body' としたらできるかと思いましたが、これは --match_columns 'title * 5 || body' と同じ意味になりうまくいきません。

解決策としては、以下のようにカラムごとに別々のインデックスを作成します。

table_create  --name BigramTerms \
              --flags TABLE_PAT_KEY|KEY_NORMALIZE \
              --key_type ShortText --default_tokenizer TokenBigram
column_create --table BigramTerms --name blog_title \
              --flags COLUMN_INDEX|WITH_POSITION|WITH_SECTION \
              --type Blog --source title
column_create --table BigramTerms --name blog_body \
              --flags COLUMN_INDEX|WITH_POSITION|WITH_SECTION \
              --type Blog --source body

そして、 --match_columns 'BigramTerms.blog_title * 5 || BigramTerms.blog_body'  とすることで、インデックスを明示し、かつ重み付けした検索が可能になります。

参考

11.1. 同じ検索キーワードなのに全文検索結果が異なる — groonga v3.0.7ドキュメント