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

- English

# 7.8. トークナイザー

## 7.8.1. 概要

Groongaにはテキストをトークナイズするトークナイザーモージュールがあります。次のケースのときにトークナイザーを使います。

> - テキストのインデックスを構築するとき

>   テキストのインデックスを構築するときにトークナイザーを使います。

> - クエリーで検索するとき

>   クエリーで検索するときにトークナイザーを使います。

全文検索ではトークナイザーは重要なモジュールです。トークナイザーを変えることで 適合率と再現率 のトレードオフを調整することができます。

一般的に TokenBigram が適切なトークナイザーです。トークナイザーについてよく知らない場合は TokenBigram を使うことをオススメします。

tokenize コマンドと table_tokenize コマンドを使うことでトークナイザーを試すことができます。 tokenize コマンドを使って TokenBigram トークナイザーを試す例を以下に示します。

実行例:

    tokenize TokenBigram "Hello World"
    # [
    #   [
    #     0,
    #     1337566253.89858,
    #     0.000355720520019531
    #   ],
    #   [
    #     {
    #       "position": 0,
    #       "force_prefix": false,
    #       "value": "He"
    #     },
    #     {
    #       "position": 1,
    #       "force_prefix": false,
    #       "value": "el"
    #     },
    #     {
    #       "position": 2,
    #       "force_prefix": false,
    #       "value": "ll"
    #     },
    #     {
    #       "position": 3,
    #       "force_prefix": false,
    #       "value": "lo"
    #     },
    #     {
    #       "position": 4,
    #       "force_prefix": false,
    #       "value": "o "
    #     },
    #     {
    #       "position": 5,
    #       "force_prefix": false,
    #       "value": " W"
    #     },
    #     {
    #       "position": 6,
    #       "force_prefix": false,
    #       "value": "Wo"
    #     },
    #     {
    #       "position": 7,
    #       "force_prefix": false,
    #       "value": "or"
    #     },
    #     {
    #       "position": 8,
    #       "force_prefix": false,
    #       "value": "rl"
    #     },
    #     {
    #       "position": 9,
    #       "force_prefix": false,
    #       "value": "ld"
    #     },
    #     {
    #       "position": 10,
    #       "force_prefix": false,
    #       "value": "d"
    #     }
    #   ]
    # ]

## 7.8.2. 「トークナイズ」とはなにか

「トークナイズ」はテキストから0個以上のトークンを抽出する処理です。「トークナイズ」する方法はいくつかあります。

例えば、バイグラムというトークナイズ方法では `Hello World` は次のトークンにトークナイズされます。

> - `He`
> - `el`
> - `ll`
> - `lo`
> - `o_` （ `_` は空白文字という意味）
> - `_W` （ `_` は空白文字という意味）
> - `Wo`
> - `or`
> - `rl`
> - `ld`

上記の例では、 `Hello World` から10個のトークンを抽出しました。

例えば、空白区切りのトークナイズ方法では `Hello World` は次のトークンにトークナイズされます。

> - `Hello`
> - `World`

上記の例では、`Hello World` から2つのトークンを抽出しました。

トークンは検索時のキーとして使われます。使用したトークナイズ方法で抽出したトークンでしかインデックス化されたドキュメントを探すことはできません。例えば、トークナイズ方法としてバイグラムを使った場合は `ll` で `Hello World` を見つけることができます。しかし、空白区切りのトークナイズ方法を使ったときは `ll` で `Hello World` を見つけることはできません。なぜなら、空白区切りのトークナイズ方法は `ll` というトークンを抽出していないからです。空白区切りのトークナイズ方法は `Hello` というトークンと `World` というトークンしか抽出していません。

一般的に、小さいトークンを生成するトークナイズ方法は再現率が高い代わりに適合率が低くなりがちです。一方、大きいトークンを生成するトークナイズ方法は適合率が高い代わりに再現率が低くなりがちです。

例えば、バイグラムというトークナイズ方法では `or` で `Hello World` と `A or B` を検索できます。しかし、「論理和」を検索したい人にとっては `Hello World` は不要な結果です。これは、適合率が下がったということです。しかし、再現率は上がっています。

空白区切りのトークナイズ方法を使った場合は `or` で `A or B` だけが見つかります。なぜなら、空白区切りのトークナイズ方法では `World` は `World` という1つのトークンだけにトークナイズされるからです。これは、「論理和」を探したい人にとっては適合率が挙がっています。しかし、 `Hello World` も `or` を含んでいるのに見つかっていないので再現率が下がっています。

## 7.8.3. 組み込みトークナイザー

以下は組み込みのトークナイザーのリストです。

> - `TokenBigram`
> - `TokenBigramSplitSymbol`
> - `TokenBigramSplitSymbolAlpha`
> - `TokenBigramSplitSymbolAlphaDigit`
> - `TokenBigramIgnoreBlank`
> - `TokenBigramIgnoreBlankSplitSymbol`
> - `TokenBigramIgnoreBlankSplitSymbolAlpha`
> - `TokenBigramIgnoreBlankSplitSymbolAlphaDigit`
> - `TokenUnigram`
> - `TokenTrigram`
> - `TokenDelimit`
> - `TokenDelimitNull`
> - `TokenMecab`
> - `TokenRegexp`

### 7.8.3.1. `TokenBigram`

`TokenBigram` はバイグラムベースのトークナイザーです。多くのケースでは、このトークナイザーを使うことをオススメします。

バイグラムというトークナイズ方法は、隣り合った2つの文字を1つのトークンとしてテキストをトークナイズします。例えば、 `Hello` は次のトークンにトークナイズします。

> - `He`
> - `el`
> - `ll`
> - `lo`

バイグラムというトークナイズ方法は再現性に優れています。なぜなら、2文字以上の文字のクエリーに対してはすべてのテキストを見つけることができるからです。

一般的に、1文字のクエリーではすべてのテキストを見つけることはできません。なぜなら、1つの文字のトークンが存在しないからです。しかし、Groongaでは1文字のクエリーでもすべてのテキストを見つけることができます。なぜなら、Groongaは前方一致検索によりクエリーで指定した文字で始まるトークンをすべて見つけることができるからです。例えば、Groongaは `l` というクエリーから `ll` というトークンと `lo` というトークンを見つけることができます。

バイグラムというトークナイズ方法は適合率はそれほど優れていません。なぜなら、単語の一部にクエリーが含まれていればすべてのテキストが見つかってしまうからです。例えば、 `or` で `world` が見つかります。これは非ASCIIを使う言語よりASCIIのみを使う言語で顕著です。以降の説明で触れる通り、 `TokenBigram` はこの問題を解決しています。

`TokenBigram` の挙動は ノーマライザー を使うかどうかで変わります。

ノーマライザーを使っていない場合は `TokenBigram` は純粋なバイグラム（最後のトークンをのぞいてすべてのトークンを2文字にする）のトークナイズ方法を使います。

実行例:

    tokenize TokenBigram "Hello World"
    # [
    #   [
    #     0,
    #     1337566253.89858,
    #     0.000355720520019531
    #   ],
    #   [
    #     {
    #       "position": 0,
    #       "force_prefix": false,
    #       "value": "He"
    #     },
    #     {
    #       "position": 1,
    #       "force_prefix": false,
    #       "value": "el"
    #     },
    #     {
    #       "position": 2,
    #       "force_prefix": false,
    #       "value": "ll"
    #     },
    #     {
    #       "position": 3,
    #       "force_prefix": false,
    #       "value": "lo"
    #     },
    #     {
    #       "position": 4,
    #       "force_prefix": false,
    #       "value": "o "
    #     },
    #     {
    #       "position": 5,
    #       "force_prefix": false,
    #       "value": " W"
    #     },
    #     {
    #       "position": 6,
    #       "force_prefix": false,
    #       "value": "Wo"
    #     },
    #     {
    #       "position": 7,
    #       "force_prefix": false,
    #       "value": "or"
    #     },
    #     {
    #       "position": 8,
    #       "force_prefix": false,
    #       "value": "rl"
    #     },
    #     {
    #       "position": 9,
    #       "force_prefix": false,
    #       "value": "ld"
    #     },
    #     {
    #       "position": 10,
    #       "force_prefix": false,
    #       "value": "d"
    #     }
    #   ]
    # ]

ノーマライザーを使っている場合は `TokenBigram` はASCIIの文字には空白区切りのようなトークナイズ方法を使います。非ASCII文字にはバイグラムのトークナイズ方法を使います。

もしかしたら、複数の方法が混ざったこの挙動はわかりにくいかもしれません。しかし、英語のテキスト（ASCII文字列のみ）や日本語テキスト（ASCII文字列と非ASCII文字列が混ざっている）ような多くのユースケースでは合理的な方法です。

ASCII文字しか使わない多くの言語は単語の区切りに空白文字を使っています。このようなケースに空白区切りのトークナイズ方法は適切です。

非ASCII文字を使う言語では単語の区切りに空白文字を使いません。このケースにはバイグラムなトークナイズ方法は適切です。

複数の言語が混ざっている場合は、複数の方法を組み合わせたトークナイズ方法が適切です。

ASCII文字にバイグラムなトークナイズ方法を使いたい場合は TokenBigramSplitSymbolAlpha のような `TokenBigramSplitXXX` というトークナイザーを参照してください。

例を使いながら `TokenBigram` の挙動を確認しましょう。

`TokenBigram` はASCII文字には1つ以上の空白文字をトークンの区切りとして使います。

実行例:

    tokenize TokenBigram "Hello World" NormalizerAuto
    # [
    #   [
    #     0,
    #     1337566253.89858,
    #     0.000355720520019531
    #   ],
    #   [
    #     {
    #       "position": 0,
    #       "force_prefix": false,
    #       "value": "hello"
    #     },
    #     {
    #       "position": 1,
    #       "force_prefix": false,
    #       "value": "world"
    #     }
    #   ]
    # ]

`TokenBigram` はASCII文字には文字の種類が変わったところをトークンの区切りとします。文字の種類は次のどれかです。

> - アルファベット
> - 数字
> - 記号（たとえば `(` 、 `)` 、 `!` など）
> - ひらがな
> - カタカナ
> - 漢字
> - その他

次の例は2つのトークン区切りを示しています。

> - `100` （数字）と `cents` （アルファベット）の間のところ
> - `cents` （アルファベット）と `!!!` （記号）の間のところ

実行例:

    tokenize TokenBigram "100cents!!!" NormalizerAuto
    # [
    #   [
    #     0,
    #     1337566253.89858,
    #     0.000355720520019531
    #   ],
    #   [
    #     {
    #       "position": 0,
    #       "force_prefix": false,
    #       "value": "100"
    #     },
    #     {
    #       "position": 1,
    #       "force_prefix": false,
    #       "value": "cents"
    #     },
    #     {
    #       "position": 2,
    #       "force_prefix": false,
    #       "value": "!!!"
    #     }
    #   ]
    # ]

以下は `TokenBigram` が非ASCII文字にはトークナイズ方法としてバイグラムを使う例です。

実行例:

    tokenize TokenBigram "日本語の勉強" NormalizerAuto
    # [
    #   [
    #     0,
    #     1337566253.89858,
    #     0.000355720520019531
    #   ],
    #   [
    #     {
    #       "position": 0,
    #       "force_prefix": false,
    #       "value": "日本"
    #     },
    #     {
    #       "position": 1,
    #       "force_prefix": false,
    #       "value": "本語"
    #     },
    #     {
    #       "position": 2,
    #       "force_prefix": false,
    #       "value": "語の"
    #     },
    #     {
    #       "position": 3,
    #       "force_prefix": false,
    #       "value": "の勉"
    #     },
    #     {
    #       "position": 4,
    #       "force_prefix": false,
    #       "value": "勉強"
    #     },
    #     {
    #       "position": 5,
    #       "force_prefix": false,
    #       "value": "強"
    #     }
    #   ]
    # ]

### 7.8.3.2. `TokenBigramSplitSymbol`

`TokenBigramSplitSymbol` は TokenBigram と似ています。違いは記号の扱いです。 `TokenBigramSplitSymbol` は記号のトークナイズ方法にバイグラムを使います。

実行例:

    tokenize TokenBigramSplitSymbol "100cents!!!" NormalizerAuto
    # [
    #   [
    #     0,
    #     1337566253.89858,
    #     0.000355720520019531
    #   ],
    #   [
    #     {
    #       "position": 0,
    #       "force_prefix": false,
    #       "value": "100"
    #     },
    #     {
    #       "position": 1,
    #       "force_prefix": false,
    #       "value": "cents"
    #     },
    #     {
    #       "position": 2,
    #       "force_prefix": false,
    #       "value": "!!"
    #     },
    #     {
    #       "position": 3,
    #       "force_prefix": false,
    #       "value": "!!"
    #     },
    #     {
    #       "position": 4,
    #       "force_prefix": false,
    #       "value": "!"
    #     }
    #   ]
    # ]

### 7.8.3.3. `TokenBigramSplitSymbolAlpha`

`TokenBigramSplitSymbolAlpha` は TokenBigram と似ています。違いは記号とアルファベットの扱いです。 `TokenBigramSplitSymbolAlpha` は記号とアルファベットのトークナイズ方法にバイグラムを使います。

実行例:

    tokenize TokenBigramSplitSymbolAlpha "100cents!!!" NormalizerAuto
    # [
    #   [
    #     0,
    #     1337566253.89858,
    #     0.000355720520019531
    #   ],
    #   [
    #     {
    #       "position": 0,
    #       "force_prefix": false,
    #       "value": "100"
    #     },
    #     {
    #       "position": 1,
    #       "force_prefix": false,
    #       "value": "ce"
    #     },
    #     {
    #       "position": 2,
    #       "force_prefix": false,
    #       "value": "en"
    #     },
    #     {
    #       "position": 3,
    #       "force_prefix": false,
    #       "value": "nt"
    #     },
    #     {
    #       "position": 4,
    #       "force_prefix": false,
    #       "value": "ts"
    #     },
    #     {
    #       "position": 5,
    #       "force_prefix": false,
    #       "value": "s!"
    #     },
    #     {
    #       "position": 6,
    #       "force_prefix": false,
    #       "value": "!!"
    #     },
    #     {
    #       "position": 7,
    #       "force_prefix": false,
    #       "value": "!!"
    #     },
    #     {
    #       "position": 8,
    #       "force_prefix": false,
    #       "value": "!"
    #     }
    #   ]
    # ]

### 7.8.3.4. `TokenBigramSplitSymbolAlphaDigit`

`TokenBigramSplitSymbolAlphaDigit` は TokenBigram と似ています。違いは記号とアルファベットと数字の扱いです。 `TokenBigramSplitSymbolAlphaDigit` は記号とアルファベット数字のトークナイズ方法にバイグラムを使います。つまり、すべての文字をバイグラムでトークナイズします。

実行例:

    tokenize TokenBigramSplitSymbolAlphaDigit "100cents!!!" NormalizerAuto
    # [
    #   [
    #     0,
    #     1337566253.89858,
    #     0.000355720520019531
    #   ],
    #   [
    #     {
    #       "position": 0,
    #       "force_prefix": false,
    #       "value": "10"
    #     },
    #     {
    #       "position": 1,
    #       "force_prefix": false,
    #       "value": "00"
    #     },
    #     {
    #       "position": 2,
    #       "force_prefix": false,
    #       "value": "0c"
    #     },
    #     {
    #       "position": 3,
    #       "force_prefix": false,
    #       "value": "ce"
    #     },
    #     {
    #       "position": 4,
    #       "force_prefix": false,
    #       "value": "en"
    #     },
    #     {
    #       "position": 5,
    #       "force_prefix": false,
    #       "value": "nt"
    #     },
    #     {
    #       "position": 6,
    #       "force_prefix": false,
    #       "value": "ts"
    #     },
    #     {
    #       "position": 7,
    #       "force_prefix": false,
    #       "value": "s!"
    #     },
    #     {
    #       "position": 8,
    #       "force_prefix": false,
    #       "value": "!!"
    #     },
    #     {
    #       "position": 9,
    #       "force_prefix": false,
    #       "value": "!!"
    #     },
    #     {
    #       "position": 10,
    #       "force_prefix": false,
    #       "value": "!"
    #     }
    #   ]
    # ]

### 7.8.3.5. `TokenBigramIgnoreBlank`

`TokenBigramIgnoreBlank` は TokenBigram と似ています。違いは空白文字の扱いです。 `TokenBigramIgnoreBlank` は連続する記号と非ASCII文字の間にある空白文字を無視します。

`日 本 語 ! ! !` というテキストを使うと違いがわかります。なぜならこのテキストは記号と非ASCII文字を両方含んでいるからです。

TokenBigram での実行結果です。

実行例:

    tokenize TokenBigram "日 本 語 ! ! !" NormalizerAuto
    # [
    #   [
    #     0,
    #     1337566253.89858,
    #     0.000355720520019531
    #   ],
    #   [
    #     {
    #       "position": 0,
    #       "force_prefix": false,
    #       "value": "日"
    #     },
    #     {
    #       "position": 1,
    #       "force_prefix": false,
    #       "value": "本"
    #     },
    #     {
    #       "position": 2,
    #       "force_prefix": false,
    #       "value": "語"
    #     },
    #     {
    #       "position": 3,
    #       "force_prefix": false,
    #       "value": "!"
    #     },
    #     {
    #       "position": 4,
    #       "force_prefix": false,
    #       "value": "!"
    #     },
    #     {
    #       "position": 5,
    #       "force_prefix": false,
    #       "value": "!"
    #     }
    #   ]
    # ]

`TokenBigramIgnoreBlank` での実行結果です。

実行例:

    tokenize TokenBigramIgnoreBlank "日 本 語 ! ! !" NormalizerAuto
    # [
    #   [
    #     0,
    #     1337566253.89858,
    #     0.000355720520019531
    #   ],
    #   [
    #     {
    #       "position": 0,
    #       "force_prefix": false,
    #       "value": "日本"
    #     },
    #     {
    #       "position": 1,
    #       "force_prefix": false,
    #       "value": "本語"
    #     },
    #     {
    #       "position": 2,
    #       "force_prefix": false,
    #       "value": "語"
    #     },
    #     {
    #       "position": 3,
    #       "force_prefix": false,
    #       "value": "!!!"
    #     }
    #   ]
    # ]

### 7.8.3.6. `TokenBigramIgnoreBlankSplitSymbol`

`TokenBigramIgnoreBlankSplitSymbol` は TokenBigram と似ています。違いは次の通りです。

> - 空白文字の扱い
> - 記号の扱い

`TokenBigramIgnoreBlankSplitSymbol` は連続した記号と非ASCII文字の間の空白文字を無視します。

`TokenBigramIgnoreBlankSplitSymbol` は記号をバイグラムでトークナイズします。

`日 本 語 ! ! !` というテキストを使うと違いがわかります。なぜならこのテキストは記号と非ASCII文字を両方含んでいるからです。

TokenBigram での実行結果です。

実行例:

    tokenize TokenBigram "日 本 語 ! ! !" NormalizerAuto
    # [
    #   [
    #     0,
    #     1337566253.89858,
    #     0.000355720520019531
    #   ],
    #   [
    #     {
    #       "position": 0,
    #       "force_prefix": false,
    #       "value": "日"
    #     },
    #     {
    #       "position": 1,
    #       "force_prefix": false,
    #       "value": "本"
    #     },
    #     {
    #       "position": 2,
    #       "force_prefix": false,
    #       "value": "語"
    #     },
    #     {
    #       "position": 3,
    #       "force_prefix": false,
    #       "value": "!"
    #     },
    #     {
    #       "position": 4,
    #       "force_prefix": false,
    #       "value": "!"
    #     },
    #     {
    #       "position": 5,
    #       "force_prefix": false,
    #       "value": "!"
    #     }
    #   ]
    # ]

`TokenBigramIgnoreBlankSplitSymbol` の実行結果です。

実行例:

    tokenize TokenBigramIgnoreBlankSplitSymbol "日 本 語 ! ! !" NormalizerAuto
    # [
    #   [
    #     0,
    #     1337566253.89858,
    #     0.000355720520019531
    #   ],
    #   [
    #     {
    #       "position": 0,
    #       "force_prefix": false,
    #       "value": "日本"
    #     },
    #     {
    #       "position": 1,
    #       "force_prefix": false,
    #       "value": "本語"
    #     },
    #     {
    #       "position": 2,
    #       "force_prefix": false,
    #       "value": "語!"
    #     },
    #     {
    #       "position": 3,
    #       "force_prefix": false,
    #       "value": "!!"
    #     },
    #     {
    #       "position": 4,
    #       "force_prefix": false,
    #       "value": "!!"
    #     },
    #     {
    #       "position": 5,
    #       "force_prefix": false,
    #       "value": "!"
    #     }
    #   ]
    # ]

### 7.8.3.7. `TokenBigramIgnoreBlankSplitSymbolAlpha`

`TokenBigramIgnoreBlankSplitSymbolAlpha` は TokenBigram と似ています。違いは次の通りです。

> - 空白文字の扱い
> - 記号とアルファベットの扱い

`TokenBigramIgnoreBlankSplitSymbolAlpha` は連続した記号と非ASCII文字の間の空白文字を無視します。

`TokenBigramIgnoreBlankSplitSymbolAlpha` は記号とアルファベットをバイグラムでトークナイズします。

`Hello 日 本 語 ! ! !` というテキストを使うと違いがわかります。なぜなら空白文字入りの記号と非ASCII文字だけでなく、アルファベットも含んでいるからです。

TokenBigram での実行結果です。

実行例:

    tokenize TokenBigram "Hello 日 本 語 ! ! !" NormalizerAuto
    # [
    #   [
    #     0,
    #     1337566253.89858,
    #     0.000355720520019531
    #   ],
    #   [
    #     {
    #       "position": 0,
    #       "force_prefix": false,
    #       "value": "hello"
    #     },
    #     {
    #       "position": 1,
    #       "force_prefix": false,
    #       "value": "日"
    #     },
    #     {
    #       "position": 2,
    #       "force_prefix": false,
    #       "value": "本"
    #     },
    #     {
    #       "position": 3,
    #       "force_prefix": false,
    #       "value": "語"
    #     },
    #     {
    #       "position": 4,
    #       "force_prefix": false,
    #       "value": "!"
    #     },
    #     {
    #       "position": 5,
    #       "force_prefix": false,
    #       "value": "!"
    #     },
    #     {
    #       "position": 6,
    #       "force_prefix": false,
    #       "value": "!"
    #     }
    #   ]
    # ]

`TokenBigramIgnoreBlankSplitSymbolAlpha` の実行結果です。

実行例:

    tokenize TokenBigramIgnoreBlankSplitSymbolAlpha "Hello 日 本 語 ! ! !" NormalizerAuto
    # [
    #   [
    #     0,
    #     1337566253.89858,
    #     0.000355720520019531
    #   ],
    #   [
    #     {
    #       "position": 0,
    #       "force_prefix": false,
    #       "value": "he"
    #     },
    #     {
    #       "position": 1,
    #       "force_prefix": false,
    #       "value": "el"
    #     },
    #     {
    #       "position": 2,
    #       "force_prefix": false,
    #       "value": "ll"
    #     },
    #     {
    #       "position": 3,
    #       "force_prefix": false,
    #       "value": "lo"
    #     },
    #     {
    #       "position": 4,
    #       "force_prefix": false,
    #       "value": "o日"
    #     },
    #     {
    #       "position": 5,
    #       "force_prefix": false,
    #       "value": "日本"
    #     },
    #     {
    #       "position": 6,
    #       "force_prefix": false,
    #       "value": "本語"
    #     },
    #     {
    #       "position": 7,
    #       "force_prefix": false,
    #       "value": "語!"
    #     },
    #     {
    #       "position": 8,
    #       "force_prefix": false,
    #       "value": "!!"
    #     },
    #     {
    #       "position": 9,
    #       "force_prefix": false,
    #       "value": "!!"
    #     },
    #     {
    #       "position": 10,
    #       "force_prefix": false,
    #       "value": "!"
    #     }
    #   ]
    # ]

### 7.8.3.8. `TokenBigramIgnoreBlankSplitSymbolAlphaDigit`

`TokenBigramIgnoreBlankSplitSymbolAlphaDigit` は TokenBigram と似ています。違いは次の通りです。

> - 空白文字の扱い
> - 記号とアルファベットと数字の扱い

`TokenBigramIgnoreBlankSplitSymbolAlphaDigit` は連続した記号と非ASCII文字の間の空白文字を無視します。

`TokenBigramIgnoreBlankSplitSymbolAlphaDigit` は記号、アルファベット、数字をバイグラムでトークナイズします。つまり、すべての文字をバイグラムでトークナイズします。

`Hello 日 本 語 ! ! ! 777` というテキストを使うと違いがわかります。なぜなら、このテキストは空白文字入りの記号と非ASCII文字だけでなく、アルファベットと数字も含んでいるからです。

TokenBigram での実行結果です。

実行例:

    tokenize TokenBigram "Hello 日 本 語 ! ! ! 777" NormalizerAuto
    # [
    #   [
    #     0,
    #     1337566253.89858,
    #     0.000355720520019531
    #   ],
    #   [
    #     {
    #       "position": 0,
    #       "force_prefix": false,
    #       "value": "hello"
    #     },
    #     {
    #       "position": 1,
    #       "force_prefix": false,
    #       "value": "日"
    #     },
    #     {
    #       "position": 2,
    #       "force_prefix": false,
    #       "value": "本"
    #     },
    #     {
    #       "position": 3,
    #       "force_prefix": false,
    #       "value": "語"
    #     },
    #     {
    #       "position": 4,
    #       "force_prefix": false,
    #       "value": "!"
    #     },
    #     {
    #       "position": 5,
    #       "force_prefix": false,
    #       "value": "!"
    #     },
    #     {
    #       "position": 6,
    #       "force_prefix": false,
    #       "value": "!"
    #     },
    #     {
    #       "position": 7,
    #       "force_prefix": false,
    #       "value": "777"
    #     }
    #   ]
    # ]

`TokenBigramIgnoreBlankSplitSymbolAlphaDigit` の実行結果です。

実行例:

    tokenize TokenBigramIgnoreBlankSplitSymbolAlphaDigit "Hello 日 本 語 ! ! ! 777" NormalizerAuto
    # [
    #   [
    #     0,
    #     1337566253.89858,
    #     0.000355720520019531
    #   ],
    #   [
    #     {
    #       "position": 0,
    #       "force_prefix": false,
    #       "value": "he"
    #     },
    #     {
    #       "position": 1,
    #       "force_prefix": false,
    #       "value": "el"
    #     },
    #     {
    #       "position": 2,
    #       "force_prefix": false,
    #       "value": "ll"
    #     },
    #     {
    #       "position": 3,
    #       "force_prefix": false,
    #       "value": "lo"
    #     },
    #     {
    #       "position": 4,
    #       "force_prefix": false,
    #       "value": "o日"
    #     },
    #     {
    #       "position": 5,
    #       "force_prefix": false,
    #       "value": "日本"
    #     },
    #     {
    #       "position": 6,
    #       "force_prefix": false,
    #       "value": "本語"
    #     },
    #     {
    #       "position": 7,
    #       "force_prefix": false,
    #       "value": "語!"
    #     },
    #     {
    #       "position": 8,
    #       "force_prefix": false,
    #       "value": "!!"
    #     },
    #     {
    #       "position": 9,
    #       "force_prefix": false,
    #       "value": "!!"
    #     },
    #     {
    #       "position": 10,
    #       "force_prefix": false,
    #       "value": "!7"
    #     },
    #     {
    #       "position": 11,
    #       "force_prefix": false,
    #       "value": "77"
    #     },
    #     {
    #       "position": 12,
    #       "force_prefix": false,
    #       "value": "77"
    #     },
    #     {
    #       "position": 13,
    #       "force_prefix": false,
    #       "value": "7"
    #     }
    #   ]
    # ]

### 7.8.3.9. `TokenUnigram`

`TokenUnigram` は TokenBigram に似ています。違いはトークンの単位です。 TokenBigram は各トークンが2文字ですが、 `TokenUnigram` は各トークンが1文字です。

実行例:

    tokenize TokenUnigram "100cents!!!" NormalizerAuto
    # [
    #   [
    #     0,
    #     1337566253.89858,
    #     0.000355720520019531
    #   ],
    #   [
    #     {
    #       "position": 0,
    #       "force_prefix": false,
    #       "value": "100"
    #     },
    #     {
    #       "position": 1,
    #       "force_prefix": false,
    #       "value": "cents"
    #     },
    #     {
    #       "position": 2,
    #       "force_prefix": false,
    #       "value": "!!!"
    #     }
    #   ]
    # ]

### 7.8.3.10. `TokenTrigram`

`TokenTrigram` は TokenBigram に似ています。違いはトークンの単位です。 TokenBigram は各トークンが2文字ですが、 `TokenTrigram` は各トークンが3文字です。

実行例:

    tokenize TokenTrigram "10000cents!!!!!" NormalizerAuto
    # [
    #   [
    #     0,
    #     1337566253.89858,
    #     0.000355720520019531
    #   ],
    #   [
    #     {
    #       "position": 0,
    #       "force_prefix": false,
    #       "value": "10000"
    #     },
    #     {
    #       "position": 1,
    #       "force_prefix": false,
    #       "value": "cents"
    #     },
    #     {
    #       "position": 2,
    #       "force_prefix": false,
    #       "value": "!!!!!"
    #     }
    #   ]
    # ]

### 7.8.3.11. `TokenDelimit`

`TokenDelimit` は1つ以上の空白文字（ `U+0020` ）で分割してトークンを抽出します。たとえば、 `Hello World` は `Hello` と `World` にトークナイズされます。

`TokenDelimit` はタグテキストに適切です。 `groonga full-text-search http` というテキストから `groonga` 、 `full-text-search` 、 `http` を抽出します。

以下は `TokenDelimit` の例です。

実行例:

    tokenize TokenDelimit "Groonga full-text-search HTTP" NormalizerAuto
    # [
    #   [
    #     0,
    #     1337566253.89858,
    #     0.000355720520019531
    #   ],
    #   [
    #     {
    #       "position": 0,
    #       "force_prefix": false,
    #       "value": "groonga"
    #     },
    #     {
    #       "position": 1,
    #       "force_prefix": false,
    #       "value": "full-text-search"
    #     },
    #     {
    #       "position": 2,
    #       "force_prefix": false,
    #       "value": "http"
    #     }
    #   ]
    # ]

`TokenDelimit` はオプションを指定することもできます。 `TokenDelimit` は `delimiter` オプションと `pattern` オプションを持っています。

`delimiter` option can split token with a specified characters.

例えば、以下のように `Hello,World` は、`Hello` と `World` にトークナイズされます。

実行例:

    tokenize 'TokenDelimit("delimiter", ",")' "Hello,World"
    # [
    #   [
    #     0,
    #     1337566253.89858,
    #     0.000355720520019531
    #   ],
    #   [
    #     {
    #       "value": "Hello",
    #       "position": 0,
    #       "force_prefix": false,
    #       "force_prefix_search": false
    #     },
    #     {
    #       "value": "World",
    #       "position": 1,
    #       "force_prefix": false,
    #       "force_prefix_search": false
    #     }
    #   ]
    # ]

`delimiter` オプションは、複数の区切り文字を指定することもできます。

例えば、以下のように `Hello, World` は、`Hello` と `World` にトークナイズされます。

実行例:

    tokenize 'TokenDelimit("delimiter", ",", "delimiter", " ")' "Hello, World"
    # [
    #   [
    #     0,
    #     1337566253.89858,
    #     0.000355720520019531
    #   ],
    #   [
    #     {
    #       "value": "Hello",
    #       "position": 0,
    #       "force_prefix": false,
    #       "force_prefix_search": false
    #     },
    #     {
    #       "value": "World",
    #       "position": 1,
    #       "force_prefix": false,
    #       "force_prefix_search": false
    #     }
    #   ]
    # ]

`pattern` オプションは、正規表現でトークンを分割できます。`pattern` オプションを使うことで、不要な空白を除去することができます。

例えば、以下のように `pattern` オプションによって、 `This is a pen. This is an apple` は `This is a pen` と `This is an apple` にトークナイズされます。

通常、 `This is a pen. This is an apple.` を `.` で分割する際は、"This is an apple."の文頭に不要な空白が含まれます。

以下の例の用に `pattern` オプションを使うことで、その不要な空白を除去できます。

実行例:

    tokenize 'TokenDelimit("pattern", "\\.\\s*")' "This is a pen. This is an apple."
    # [
    #   [
    #     0,
    #     1337566253.89858,
    #     0.000355720520019531
    #   ],
    #   [
    #     {
    #       "value": "This is a pen.",
    #       "position": 0,
    #       "force_prefix": false,
    #       "force_prefix_search": false
    #     },
    #     {
    #       "value": "This is an apple.",
    #       "position": 1,
    #       "force_prefix": false,
    #       "force_prefix_search": false
    #     }
    #   ]
    # ]

`pattern` オプションを使って複雑な条件でトークンを抽出できます。

例えば、以下のように `delimiter` オプションを使って、 `これはペンですか！？リンゴですか？「リンゴです。」` を `これはペンですか` と `リンゴですか` 、 `「リンゴです。」` とトークナイズします。

実行例:

    tokenize 'TokenDelimit("pattern", "([。！？]+(?![）」])|[\\r\\n]+)\\s*")' "これはペンですか！？リンゴですか？「リンゴです。」"
    # [
    #   [
    #     0,
    #     1545179416.22277,
    #     0.0002887248992919922
    #   ],
    #   [
    #     {
    #       "value": "これはペンですか",
    #       "position": 0,
    #       "force_prefix": false,
    #       "force_prefix_search": false
    #     },
    #     {
    #       "value": "リンゴですか",
    #       "position": 1,
    #       "force_prefix": false,
    #       "force_prefix_search": false
    #     },
    #     {
    #       "value": "「リンゴです。」",
    #       "position": 2,
    #       "force_prefix": false,
    #       "force_prefix_search": false
    #     }
    #   ]
    # ]

上記の正規表現の末尾の `\\s*` は、区切り文字の後ろの0個以上の空白にマッチします。

`[。！？]+` は、1個以上の `。` または `！`、 `？` にマッチします。例えば、 `[。！？]+` は `これはペンですか！？` の `！？` にマッチします。

`(?![）」])` は否定先読みです。 `(?![）」])` は `）` または `」` にマッチしない場合にマッチします。否定先読みは直前の正規表現と合わせて解釈します。

したがって、 `[。！？]+(?![）」])` を解釈します。

`[。！？]+(?![）」])` は、`。` または `！`、 `？` の後ろに `）` または `」` が無い場合にマッチします。

つまり、 `[。！？]+(?![）」])` は、 `これはペンですか。` の `。` にマッチしますが、 `「リンゴです。」` の `。` にはマッチしません。 `。` の後ろに `」` があるためです。

`[\\r\\n]+` は、1個以上の改行文字にマッチします。

まとめると、 `([。！？]+(?![）」])|[\\r\\n]+)\\s*` は、 `。` と `！` と `？`、 改行文字を区切り文字としています。ただし、 `。` または `!`、 `？` の後ろに `）` または `」` がある場合は、 `。` や `！`、 `？` は区切り文字としません。

### 7.8.3.12. `TokenDelimitNull`

`TokenDelimitNull` は TokenDelimit に似ています。違いは区切り文字です。 TokenDelimit は空白文字（ `U+0020` ）を使いますが、 `TokenDelimitNull` はNUL文字（ `U+0000` ）を使います。

`TokenDelimitNull` もタグテキストに適切です。

以下は `TokenDelimitNull` の例です。

実行例:

    tokenize TokenDelimitNull "Groonga\u0000full-text-search\u0000HTTP" NormalizerAuto
    # [
    #   [
    #     0,
    #     1337566253.89858,
    #     0.000355720520019531
    #   ],
    #   [
    #     {
    #       "position": 0,
    #       "force_prefix": false,
    #       "value": "groongau0000full-text-searchu0000http"
    #     }
    #   ]
    # ]

### 7.8.3.13. `TokenMecab`

`TokenMecab` は MeCab 形態素解析器をベースにしたトークナイザーです。

MeCabは日本語に依存していません。その言語用の辞書を用意すれば日本語以外でもMeCabを使えます。日本語用の辞書には NAIST Japanese Dictionary を使えます。

`TokenMecab` を使うには、追加のパッケージをインストールする必要があります。追加のパッケージをインストールする方法の詳細については、各OSのインストール方法 を参照して下さい。

`TokenMecab` は再現率より適合率に優れています。 TokenBigram では `京都` というクエリーで `東京都` も `京都` も見つかりますが、この場合は `東京都` は期待した結果ではありません。 `TokenMecab` を使うと `京都` というクエリーで `京都` だけを見つけられます。

新語をサポートしたい場合は、MeCabの辞書を更新し続ける必要があります。これはメンテナンスコストがかかります。（ TokenBigram には辞書のメンテナンスコストはありません。なぜなら、 TokenBigram は辞書を使っていないからです。）新語への対応に mecab-ipadic-NEologd : Neologism dictionary for MeCab が役に立つかもしれません。

以下は `TokenMeCab` の例です。 `東京都` は `東京` と `都` にトークナイズされています。 `京都` というトークンはありません。

実行例:

    tokenize TokenMecab "東京都"
    # [
    #   [
    #     0,
    #     1545812631.661493,
    #     0.0002415180206298828
    #   ],
    #   [
    #     {
    #       "value": "東京",
    #       "position": 0,
    #       "force_prefix": false,
    #       "force_prefix_search": false
    #     },
    #     {
    #       "value": "都",
    #       "position": 1,
    #       "force_prefix": false,
    #       "force_prefix_search": false
    #     }
    #   ]
    # ]

`TokenMecab` はオプションを指定することもできます。`TokenMecab` は、`target_class` オプション、 `include_class` オプション、 `include_reading` オプション、 `include_form` オプションと `use_reading` オプションがあります。

`target_class` オプションは、指定した品詞のトークンを検索します。例えば、以下のように名詞のみを検索できます。

実行例:

    tokenize 'TokenMecab("target_class", "名詞")' '彼の名前は山田さんのはずです。'
    # [
    #   [
    #     0,
    #     1545810238.195525,
    #     0.0003066062927246094
    #   ],
    #   [
    #     {
    #       "value": "彼",
    #       "position": 0,
    #       "force_prefix": false,
    #       "force_prefix_search": false
    #     },
    #     {
    #       "value": "名前",
    #       "position": 1,
    #       "force_prefix": false,
    #       "force_prefix_search": false
    #     },
    #     {
    #       "value": "山田",
    #       "position": 2,
    #       "force_prefix": false,
    #       "force_prefix_search": false
    #     },
    #     {
    #       "value": "さん",
    #       "position": 3,
    #       "force_prefix": false,
    #       "force_prefix_search": false
    #     },
    #     {
    #       "value": "はず",
    #       "position": 4,
    #       "force_prefix": false,
    #       "force_prefix_search": false
    #     }
    #   ]
    # ]

`target_class` オプションは、サブクラスを指定することや、 + や - を使って、特定の品詞を追加または、除外することもできます。したがって、以下のように人名の接尾語と非自立語を除いた名詞を検索することもできます。

このようにして、ノイズとなるトークンを除外して検索できます。

実行例:

    tokenize 'TokenMecab("target_class", "-名詞/非自立", "target_class", "-名詞/接尾/人名", "target_class", "名詞")' '彼の名前は山田さんのはずです。'
    # [
    #   [
    #     0,
    #     1545810363.771334,
    #     0.0003197193145751953
    #   ],
    #   [
    #     {
    #       "value": "彼",
    #       "position": 0,
    #       "force_prefix": false,
    #       "force_prefix_search": false
    #     },
    #     {
    #       "value": "名前",
    #       "position": 1,
    #       "force_prefix": false,
    #       "force_prefix_search": false
    #     },
    #     {
    #       "value": "山田",
    #       "position": 2,
    #       "force_prefix": false,
    #       "force_prefix_search": false
    #     }
    #   ]
    # ]

### 7.8.3.14. `TokenRegexp`

バージョン 5.0.1 で追加.

ご用心

このトークナイザーは実験的です。仕様が変わる可能性があります。

ご用心

このトークナイザーはUTF-8でしか使えません。EUC-JPやShift_JISなどと一緒には使えません。

`TokenRegexp` はインデックスを使った正規表現検索をサポートするトークナイザーです。

一般的に、正規表現検索は逐次検索で実行します。しかし、次のケースはインデックスを使って検索できます。

> - `hello` のようにリテラルしかないケース
> - `\A/home/alice` のようにテキストの最初でのマッチとリテラルのみのケース
> - `\.txt\z` のようにテキストの最後でのマッチとリテラルのみのケース

多くのケースでは、逐次検索よりもインデックスを使った検索の方が高速です。

`TokenRegexp` はベースはバイグラムを使います。 `TokenRegexp` は、インデックス時に、テキストの先頭にテキストの先頭であるというマーク（ `U+FFEF` ）を入れ、テキストの最後にテキストの最後であるというマーク（ `U+FFF0` ）を入れます。

実行例:

    tokenize TokenRegexp "/home/alice/test.txt" NormalizerAuto --mode ADD
    # [
    #   [
    #     0,
    #     1337566253.89858,
    #     0.000355720520019531
    #   ],
    #   [
    #     {
    #       "position": 0,
    #       "force_prefix": false,
    #       "value": "￯"
    #     },
    #     {
    #       "position": 1,
    #       "force_prefix": false,
    #       "value": "/h"
    #     },
    #     {
    #       "position": 2,
    #       "force_prefix": false,
    #       "value": "ho"
    #     },
    #     {
    #       "position": 3,
    #       "force_prefix": false,
    #       "value": "om"
    #     },
    #     {
    #       "position": 4,
    #       "force_prefix": false,
    #       "value": "me"
    #     },
    #     {
    #       "position": 5,
    #       "force_prefix": false,
    #       "value": "e/"
    #     },
    #     {
    #       "position": 6,
    #       "force_prefix": false,
    #       "value": "/a"
    #     },
    #     {
    #       "position": 7,
    #       "force_prefix": false,
    #       "value": "al"
    #     },
    #     {
    #       "position": 8,
    #       "force_prefix": false,
    #       "value": "li"
    #     },
    #     {
    #       "position": 9,
    #       "force_prefix": false,
    #       "value": "ic"
    #     },
    #     {
    #       "position": 10,
    #       "force_prefix": false,
    #       "value": "ce"
    #     },
    #     {
    #       "position": 11,
    #       "force_prefix": false,
    #       "value": "e/"
    #     },
    #     {
    #       "position": 12,
    #       "force_prefix": false,
    #       "value": "/t"
    #     },
    #     {
    #       "position": 13,
    #       "force_prefix": false,
    #       "value": "te"
    #     },
    #     {
    #       "position": 14,
    #       "force_prefix": false,
    #       "value": "es"
    #     },
    #     {
    #       "position": 15,
    #       "force_prefix": false,
    #       "value": "st"
    #     },
    #     {
    #       "position": 16,
    #       "force_prefix": false,
    #       "value": "t."
    #     },
    #     {
    #       "position": 17,
    #       "force_prefix": false,
    #       "value": ".t"
    #     },
    #     {
    #       "position": 18,
    #       "force_prefix": false,
    #       "value": "tx"
    #     },
    #     {
    #       "position": 19,
    #       "force_prefix": false,
    #       "value": "xt"
    #     },
    #     {
    #       "position": 20,
    #       "force_prefix": false,
    #       "value": "t"
    #     },
    #     {
    #       "position": 21,
    #       "force_prefix": false,
    #       "value": "￰"
    #     }
    #   ]
    # ]