全文検索エンジンGroongaでドリルダウンを高速に実行するためのヒント

> もっとGroongaを知ってもらおう!ということで週刊Groongaをはじめました。毎週木曜にGroongaやMroonga、Rroongaのトピックを投稿予定です。

今年も11/29に[全文検索エンジンGroongaを囲む夕べ4](http://atnd.org/events/43461)を開催しました。[発表資料](http://atnd.org/events/43461#document)へのリンクもまとめています。[隔週連載Groonga](http://gihyo.jp/dev/clip/01/groonga)も参考になりますよ。

# はじめに

オープンソースの[カラムストア機能付き全文検索エンジンGroonga](http://groonga.org/ja/)を公開しています。最新のバージョンは2013年11月29日にリリースした[3.1.0](http://groonga.org/ja/docs/news.html#release-3-1-0)です。

今回は、グループ化した検索結果を取得するドリルダウンを高速に実行するためのヒントを紹介します。

# ドリルダウンとは

全文検索エンジンであるGroongaでは、指定したカラムの値でグループ化してその値を含む結果が何件あるかを取得することができるようになっています。その機能をドリルダウンと呼んでいます。

ドリルダウンの例を次に示します。
たとえば、 ``domain`` カラムに次のようなデータが登録されている状態で、全件を対象にドリルダウンしてみるとどうなるでしょうか。


|id |domain|
|---|------|
| 1 |org  |
| 2 |net  |
| 3 |com  |
| 4 |org  |
| 5 |org  |
| 6 |com  |

結果は次のようになります。

|domainでドリルダウン|件数|
|----------------|--------|
|net| 1 |
|com| 2 |
|org| 3 |


# ドリルダウンを高速に実行するためのヒント

このドリルダウンという機能ですが、注意事項がひとつあります。
[ドリルダウンのチュートリアル](http://groonga.org/ja/docs/tutorial/drilldown.html)の最後にも記載してあるのですが、文字列型のカラムに対するドリルダウンは他の型のドリルダウンの実行に比べて低速だということです。

では、どれくらい違いがあるのかを実際に確認してみましょう。

# サンプルのスキーマ

今回使うサンプルのスキーマは次の通りです。

```
table_create Users TABLE_HASH_KEY UInt32
table_create HowToEatCurry TABLE_HASH_KEY ShortText
column_create Users how_to_eat_curry COLUMN_SCALAR ShortText
column_create Users how_to_eat_curry2 COLUMN_SCALAR HowToEatCurry
```

カレーの食べかたを格納するカラムを2つ用意しています。ひとつは文字列型(ShortText)のカラムである``how_to_eat_curry``です。
もうひとつはテーブル型(HowToEatCurry)のカラムである``how_to_eat_curry2``です。
``HowToEatCurry``テーブルは主キーが文字列型になっています。

## 文字列型でのドリルダウン

まずは、遅いと言われている文字列型での結果を試してみましょう。
元は5000件のデータを水増しして、10万件、100万件、1000万件と登録件数を増やしてみました。

1000万件まで水増ししたときの偏り具合はこんな感じです。

```
> select Users --drilldown how_to_eat_curry
[[0,1387420567.65289,1.46287107467651],[[[10000000],[["_id","UInt32"],["_key","UInt32"],["how_to_eat_curry","ShortText"],["how_to_eat_curry2","HowToEatCurry"]],[1,1,"左ルー・ナン派","左ルー・ナン派"],[2,2,"右ルー・混ぜ混ぜ派","右ルー・混ぜ混ぜ派"],[3,3,"左ルー・混ぜ混ぜ派","左ルー・混ぜ混ぜ派"],[4,4,"左ルー・ルー攻め派","左ルー・ルー攻め派"],[5,5,"別盛り・せき止め派","別盛り・せき止め派"],[6,6,"右ルー・ルー攻め派","右ルー・ルー攻め派"],[7,7,"左ルー・別口派","左ルー・別口派"],[8,8,"ぶっかけ・ナン派","ぶっかけ・ナン派"],[9,9,"ぶっかけ・ルー攻め派","ぶっかけ・ルー攻め派"],[10,10,"右ルー・別口派","右ルー・別口派"]],[[30],[["_key","ShortText"],["_nsubrecs","Int32"]],["左ルー・ナン派",236000],["右ルー・混ぜ混ぜ派",304000],["左ルー・混ぜ混ぜ派",626000],["左ルー・ルー攻め派",860000],["別盛り・せき止め派",162000],["右ルー・ルー攻め派",362000],["左ルー・別口派",466000],["ぶっかけ・ナン派",188000],["ぶっかけ・ルー攻め派",738000],["右ルー・別口派",208000]]]]
```

|登録レコード数(単位:万)|文字列型で全件を対象にドリルダウン(単位:ミリ秒)|
|----------------|--------|
|10| 21 |
|100| 162 |
|1000| 1462 |

## テーブル型でのドリルダウン

今度はチュートリアルに記載されているような、テーブル型での全件ドリルダウンを試してみます。


|登録レコード数(単位:万)|テーブル型で全件を対象にドリルダウン(単位:ミリ秒)|
|----------------|--------|
|10| 13 |
|100| 88 |
|1000| 671 |

これをグラフにしてみるとこんな感じになります。

![型の違いによるドリルダウン速度](http://packages.groonga.org/qiita/grn-drilldown-performance.png)

カラムの型が文字列型かテーブル型かの違いで速度に2倍程度差が出ていることがわかりました。
カラムの全件ドリルダウンというシンプルな例であることに注意が必要ですが、有意な差がありますね。

なぜこのような速度差が発生するかというと、文字列型の場合は型からわかるようにドリルダウンの際にカラムの値の比較が文字列の比較となりますが、テーブル型だとドリルダウンするときにカラムの値の比較が数値(別テーブルに格納されている要素のID)で行えるためです。

# まとめ

今回は、ドリルダウンを高速に実行するためのヒントを紹介しました。

Groongaに興味を持ったなら、まずは[インストール](http://groonga.org/ja/docs/install.html)して試してみてください。

Groongaの基本的な動作を知るための[チュートリアル](http://groonga.org/ja/docs/tutorial.html)もあります。インストールしたら試してみてください。