Groongaにおけるmatch_columns周りの話

１２月１１日のGroonga読書会で学んだ内容をまとめます

今回は[4.7. match_columnsパラメータ]("4.7. match_columnsパラメータ" http://groonga.org/ja/docs/tutorial/match_columns.html)の章を輪読しました。
match_columsの話、というよりもインデックス周りの話が多かった気がします。


### 何故インデックスを貼るのか
全文検索を高速に行うためにインデックスを貼ります。
その他については他に詳しく解説されている方がいるので特に言及はしません。

### Groongaにおけるインデックスカラムの引数について
例えば、以下のようなDDLがあった場合、

```ddl:sample.ddl
table_create --name Index --flags TABLE_PAT_KEY|KEY_NORMALIZE --key_type ShortText --default_tokenizer TokenBigram
column_create --table Index --name index_bigram --flags COLUMN_INDEX|WITH_POSITION|WITH_SECTION --type test --source title,text
```

以下の設定がおのおの何を意味をしているのか、

> --flags COLUMN_INDEX|WITH_POSITION|WITH_SECTION

あまり正しく理解していなかったので、勉強がてらまとめ直すことにします。
ちなみに[マニュアル](http://groonga.org/ja/docs/reference/commands/column_create.html "マニュアル")のこちらで軽ーく触れられています。


##### WITH_POSION
ワードの出現の位置をインデックスに保有します。
よって、フレーズ検索などをおこなう時にも有効です。
日本語のデータでトークナイザーをNgramに指定した場合は必須になります。

##### WITH_SECTION
文章全体ではなく、ブロッキングされているという前提でインデックスを作ります。
上記のsample.ddlの場合はあるワードが"title"もしくは"text"で出現したのかという情報を保有します。
なので、単一のカラムに対しては意味をなさないです。

##### WITH_WEIGHT
本件とは関係がないので、解説しません。


### 複数カラムへのインデックス
あとで記述


### インデックス名を指定した検索
match_columns関数においてインデックス名を指定して検索することができる機能です。
この機能を用いると、同じカラムに対して異なるトークナイザーのインデックスを指定するなどが出来ます。

例えば、以下の例ですと
Blogテーブルのtitleカラムに対して、トークナイザーをMecabとBigramで指定します。

```ddl:sample2.ddl
table_create --name Blog --flags TABLE_HASH_KEY --key_type ShortText
column_create --table Blog --name title --flags COLUMN_SCALAR --type ShortText

table_create --name IndexBigram --flags TABLE_PAT_KEY|KEY_NORMALIZE --key_type ShortText --default_tokenizer TokenBigram
column_create --table IndexBigram --name index_blog --flags COLUMN_INDEX|WITH_POSITION|WITH_SECTION --type Blog --source title

table_create --name IndexMecab --flags TABLE_PAT_KEY|KEY_NORMALIZE --key_type ShortText --default_tokenizer TokenMecab
column_create --table IndexMecab --name index_blog --flags COLUMN_INDEX|WITH_POSITION|WITH_SECTION --type Blog --source title
```

```sample_data.json
load --table Blog
[
{"_key":"grn1","title":"東京都"},
{"_key":"grn2","title":"京都府"},
{"_key":"grn3","title":"京都大学"}
]
```

Blogテーブルのtitleカラムに対して「京都」をいうワードで全文検索を行いますが、指定したインデックスによって異なる結果を返却することが分かります。

```Mecabのインデックスを指定
select --table Blog --query "京都" --match_columns IndexMecab.index_blog
[[0,1418640224.95989,0.0626418590545654],[[[1],[["_id","UInt32"],["_key","ShortText"],["title","ShortText"]],[2,"grn2","京都府"]]]]
```

```Bigramのインデックスを指定 
select --table Blog --query "京都" --match_columns IndexBigram.index_blog
[[0,1418640246.23825,0.056649923324585],[[[3],[["_id","UInt32"],["_key","ShortText"],["title","ShortText"]],[1,"grn1","東京都"],[2,"grn2","京都府"],[3,"grn3","京都大学"]]]]
```


### インデックスに対して重みを付けて検索する
インデックスを指定して検索が出来るのと同時に、インデックスに対して重みを付けて検索が出来ます。

上記で作成したBlogテーブルを用いて解説します。
まず、新たに[_scoreというスコア値を保有するカラム]("http://groonga.org/ja/docs/reference/columns/pseudo.html?highlight=_score")を出力してみます。

```
select --table Blog --query "京都" --match_columns IndexMecab.index_blog --output_columns *,_score
[[0,1418641006.92207,0.000437021255493164],[[[1],[["title","ShortText"],["_score","Int32"]],["京都府",1]]]]
 ```
 
```
select --table Blog --query "京都" --match_columns IndexBigram.index_blog --output_columns *,_score
[[0,1418641022.63525,0.000339031219482422],[[[3],[["title","ShortText"],["_score","Int32"]],["東京都",1],["京都府",1],["京都大学",1]]]]
```

Mecab、Bigramともにスコアが１です。
これらに重み付けをして検索してみます。
ここでは、MecabでHITしたカラムを優先させたいため、Mecabのインデックスのスコアを１０倍にします。

```
select --table Blog --query "京都" --match_columns IndexMecab.index_blog*10||IndexBigram.index_blog*1 --output_columns *,_score
[[0,1418641101.76831,0.000390052795410156],[[[3],[["title","ShortText"],["_score","Int32"]],["京都府",11],["東京都",1],["京都大学",1]]]]
```

「京都府」というカラムのスコアが１１になっていることが分かります。
Mecabのスコア１が１０倍となって１０、それにBigramの１が加算されてスコアが１１となるためです。



以上、１２月１１日のGroonga読書会で学んだことのうち、マニュアルに記載がない部分を中心にまとめました。
随時加筆修正していく予定です。