# groonga - オープンソースのカラムストア機能付き全文検索エンジン

- English

# 7.20.2. 補完

このセクションでは以下の補完機能について説明します。:

- どのように動作するか
- 使い方
- 学習方法

## 7.20.2.1. どのように動作するか

補完機能は補完される語を計算するために3種類の検索を使います。

> 1. 登録されている語を前方一致RK検索。
> 2. 学習したデータを共起検索。
> 3. 登録されている語を前方一致検索。（実行しないこともある）

### 7.20.2.1.1. 前方一致RK検索

前方一致RK検索については 前方一致RK検索 を見てください。

groonga-suggest-create-dataset 実行ファイルで `query` という名前のデータセットを作ったとします。前方一致RK検索で使うために `item_query` テーブルの `_key` と `kana` カラムに登録済みの単語と読みのペアを指定することで更新できます。

### 7.20.2.1.2. 共起検索

共起検索は入力途中のユーザのクエリから登録されている語を見つけます。共起検索では検索データベースとしてユーザの入力シーケンスを使います。これはクエリログやアクセスログなどから学習します。

例えば、以下のようなユーザの入力シーケンスがあるとします。

入力 | 検索実行
--- | ---
s | していない
se | していない
sea | していない
sear | していない
searc | していない
search | した
e | していない
en | していない
eng | していない
engi | していない
engin | していない
engine | していない
enginen | していない（入力ミス！）
engine | した

Groongaは以下のような補完ペアを作ります。:

入力 | 補完語
--- | ---
s | search
se | search
sea | search
sear | search
searc | search
e | engine
en | engine
eng | engine
engi | engine
engin | engine
engine | engine
enginen | engine

ユーザが検索を実行する前のすべての入力（例では"s"、"se"など）を検索を実行した語（例では"search"）に対応付けます。

厳密に言うとこの説明は正しくありません。なぜならタイムスタンプに関することを省略しているからです。groongaは本当は「ユーザが検索を実行する前のすべての入力を」使いません。厳密には「ユーザが検索を実行する前の1分以内の入力のみ」を使います。検索実行時から1分より前の入力は使われません。

ユーザが"sea"と入力したら、共起検索は"search"を返します。なぜなら、「入力」カラムには"sea"という値があり、対応する「補完語」カラムには"search"という値が入っているからです。

### 7.20.2.1.3. 前方一致検索

前方一致検索はユーザが入力した文字列から始まる登録済みの語を検索します。この検索は前方一致RK検索とは違ってローマ字、カタカナ、ひらがなを特別扱いしません。

この検索はいつも実行されるわけではありません。この検索は明示的に実行するように指示するか、前方一致RK検索と共起検索の両方がなにもヒットしないときのみ実行されます。

例えば、"search"が登録されているとします。ユーザは"s"、"se"、"sea"、"sear"、"searc"、"search"のどれでも"search"を補完候補として利用できます。

## 7.20.2.2. 使い方

Groongaは補完機能を使うために suggest コマンドを用意しています。 `--type complete` オプションを使うと補完機能を利用できます。

例えば、"en"と入力したときの補完結果を取得するコマンドは以下のようになります。:

実行例:

    suggest --table item_query --column kana --types complete --frequency_threshold 1 --query en
    # [
    #   [
    #     0,
    #     1337566253.89858,
    #     0.000355720520019531
    #   ],
    #   {
    #     "complete": [
    #       [
    #         1
    #       ],
    #       [
    #         [
    #           "_key",
    #           "ShortText"
    #         ],
    #         [
    #           "_score",
    #           "Int32"
    #         ]
    #       ],
    #       [
    #         "engine",
    #         1
    #       ]
    #     ]
    #   }
    # ]

## 7.20.2.3. 学習方法

共起検索は学習データを使います。学習データはクエリログやアクセスログなどを元に作成します。学習データを作成するには、タイムスタンプ付きの入力シーケンスと、タイムスタンプ付きの検索実行時の入力内容が必要です。

例えば、ユーザが"engine"で検索したいとします。ユーザが以下のようなシーケンスで検索クエリを入力したとします。:

> 1. 2011-08-10T13:33:23+09:00: e
> 2. 2011-08-10T13:33:23+09:00: en
> 3. 2011-08-10T13:33:24+09:00: eng
> 4. 2011-08-10T13:33:24+09:00: engi
> 5. 2011-08-10T13:33:24+09:00: engin
> 6. 2011-08-10T13:33:25+09:00: engine （検索実行！）

以下のコマンドでこの入力シーケンスから学習できます。:

    load --table event_query --each 'suggest_preparer(_id, type, item, sequence, time, pair_query)'
    [
    {"sequence": "1", "time": 1312950803.86057, "item": "e"},
    {"sequence": "1", "time": 1312950803.96857, "item": "en"},
    {"sequence": "1", "time": 1312950804.26057, "item": "eng"},
    {"sequence": "1", "time": 1312950804.56057, "item": "engi"},
    {"sequence": "1", "time": 1312950804.76057, "item": "engin"},
    {"sequence": "1", "time": 1312950805.86057, "item": "engine", "type": "submit"}
    ]

## 7.20.2.4. 読みデータの更新方法

前方一致RK検索をするために単語とその読みが必要になります。このセクションではどのように単語と読みを登録するかを説明します。

以下は「日本」を登録する例です:

実行例:

    load --table event_query --each 'suggest_preparer(_id, type, item, sequence, time, pair_query)'
    [
    {"sequence": "1", "time": 1312950805.86058, "item": "日本", "type": "submit"}
    ]
    # [[0, 1337566253.89858, 0.000355720520019531], 1]

以下は「日本」を補完するために読みデータを登録する例です:

実行例:

    load --table item_query
    [
    {"_key":"日本", "kana":["ニホン", "ニッポン"]}
    ]
    # [[0, 1337566253.89858, 0.000355720520019531], 1]

これで「nihon」というローマ字で登録済みの「日本」という単語を補完できます。

実行例:

    suggest --table item_query --column kana --types complete --frequency_threshold 1 --query nihon
    # [
    #   [
    #     0,
    #     1337566253.89858,
    #     0.000355720520019531
    #   ],
    #   {
    #     "complete": [
    #       [
    #         1
    #       ],
    #       [
    #         [
    #           "_key",
    #           "ShortText"
    #         ],
    #         [
    #           "_score",
    #           "Int32"
    #         ]
    #       ],
    #       [
    #         "日本",
    #         2
    #       ]
    #     ]
    #   }
    # ]

この読みデータがないと登録済みの「日本」という単語を「nihon」というクエリーで補完できません。

`item_query` テーブルの `kana` カラムは ベクターカラム なので、複数の読みを登録できます。

これが「nippon」でも「日本」を補完できる理由です。

実行例:

    suggest --table item_query --column kana --types complete --frequency_threshold 1 --query nippon
    # [
    #   [
    #     0,
    #     1337566253.89858,
    #     0.000355720520019531
    #   ],
    #   {
    #     "complete": [
    #       [
    #         1
    #       ],
    #       [
    #         [
    #           "_key",
    #           "ShortText"
    #         ],
    #         [
    #           "_score",
    #           "Int32"
    #         ]
    #       ],
    #       [
    #         "日本",
    #         2
    #       ]
    #     ]
    #   }
    # ]

日本語入力システムが無効になっている状態でも登録済みの単語を検索できるのでこの機能はとても便利です。

補完候補が複数ある場合、 `item_query` テーブルの `boost` カラムに値を設定することで優先度をカスタマイズすることができます。

以下は前方一致RK検索での優先度をカスタマイズする例です:

実行例:

    load --table event_query --each 'suggest_preparer(_id, type, item, sequence, time, pair_query)'
    [
    {"sequence": "1", "time": 1312950805.86059, "item": "日本語", "type": "submit"}
    {"sequence": "1", "time": 1312950805.86060, "item": "日本人", "type": "submit"}
    ]
    # [[0, 1337566253.89858, 0.000355720520019531], 2]
    load --table item_query
    [
    {"_key":"日本語", "kana":"ニホンゴ"}
    {"_key":"日本人", "kana":"ニホンジン"}
    ]
    # [[0, 1337566253.89858, 0.000355720520019531], 2]
    suggest --table item_query --column kana --types complete --frequency_threshold 1 --query nihon
    # [
    #   [
    #     0,
    #     1337566253.89858,
    #     0.000355720520019531
    #   ],
    #   {
    #     "complete": [
    #       [
    #         3
    #       ],
    #       [
    #         [
    #           "_key",
    #           "ShortText"
    #         ],
    #         [
    #           "_score",
    #           "Int32"
    #         ]
    #       ],
    #       [
    #         "日本",
    #         2
    #       ],
    #       [
    #         "日本人",
    #         2
    #       ],
    #       [
    #         "日本語",
    #         2
    #       ]
    #     ]
    #   }
    # ]
    load --table item_query
    [
    {"_key":"日本人", "boost": 100},
    ]
    # [[0, 1337566253.89858, 0.000355720520019531], 1]
    suggest --table item_query --column kana --types complete --frequency_threshold 1 --query nihon
    # [
    #   [
    #     0,
    #     1337566253.89858,
    #     0.000355720520019531
    #   ],
    #   {
    #     "complete": [
    #       [
    #         3
    #       ],
    #       [
    #         [
    #           "_key",
    #           "ShortText"
    #         ],
    #         [
    #           "_score",
    #           "Int32"
    #         ]
    #       ],
    #       [
    #         "日本人",
    #         102
    #       ],
    #       [
    #         "日本",
    #         2
    #       ],
    #       [
    #         "日本語",
    #         2
    #       ]
    #     ]
    #   }
    # ]