Groongaのトークナイザーがいっぱいあるけど、どれを使えば良いのか迷っていた阿部です。
特にNgram関連がいっぱいあって迷います。
さらにいうとBigramをしたいときに TokenNgram
と TokenBigram
のどちらを使えば良いのか迷います。
名前からは両方とも同じ処理ができそうです。
今回はこの疑問点について解説します。
この記事はグルカイ!第58回 の内容をククログとしてまとめました。
結論
さっそく結論ですが、Ngramをしたい場合は
TokenNgram
を使えば良いです。
他のNgram関連のトークナイザーは考えなくてよいです。
解説
TokenNgram
はオプションによって動作を指定できます。
それにより他のNgram系のトークナイザーの処理はすべて TokenNgram
で実現できます。
例えば、 TokenUnigram
、TokenBigram
、TokenTrigram
は TokenNgram
で以下のように指定できます。
TokenUnigram
:TokenNgram("n", 1)
TokenBigram
:TokenNgram("n", 2)
TokenTrigram
:TokenNgram("n", 3)
解説の補足
このような状況になっている理由は以下の2点です。
- 以前はオプションの書式が使えなかった
- Groongaは後方互換性を大事にしている
1. 以前はオプションの書式が使えなかった
オプションの書式とは ()
で指定しているものです。先ほどの例だと
TokenNgram("n", 1)
の ("n", 1)
の部分です。
以前はオプションで挙動を変えられませんでした。挙動を変えたい場合は
その変えたい挙動ごとに TokenBigram
などを追加する必要がありました。
今は TokenNgram
のオプションで他のすべてのNgramのトークナイザーと同じ
処理ができるようになっています。
2. Groongaは後方互換性を大事にしている
TokenNgram
があれば十分なので他のトークナイザーは消しても良いのですが、
Groongaは後方互換性を大事にしているため、TokenNgram
以外も引き続き
利用できるようになっています。
まとめ
歴史的経緯と後方互換性のためにたくさんのNgramのトークナイザーがありますが、
TokenNgram
を使えばOKです。
補足: GroongaのNgram
GroongaのNgramは純粋なNgramではありません。
TokenBigram
の説明にもありますが、
GroongaのNgramはノーマライザーを使うとASCII文字以外にNgramを適用します。
(ASCII文字はNgramで分割されません。)
ノーマライザーの使用の有無で挙動が変わるのはノーマライザーが「ASCII文字」 といったフラグを付けるためです。 このフラグがないとASCII文字か否か判別できないため、ノーマライザーの使用なしの場合は すべてにNgramを適用、ノーマライザー使用ありの場合はASCII文字以外にNgramを適用という 動きをします。
デフォルトでASCII文字以外にNgramを適用する理由はそのほうが便利なことが多いからです。
ASCII文字のみを使う言語(例えば英語)の場合は空白で単語を区切れるので、
その単語で検索することが多いです(= Ngramを使う必要性が低い)。
(apple
を検索するときに app
で検索することはあまりない。)
逆に日本語や中国語などの場合は空白で文字が区切られないため、Ngramを使ったほうが便利なことが多いです。
という状況からGroongaでは TokenNgram
を純粋なNgramではなく、ASCII文字か否かで分割方法を変えるようにしています。
補足: TokenNgram
のオプション例
例として2つのみ掲載しますが、他のNgram系のトークナイザーも同様に TokenNgram
を使うことで実現できます。
指定できるオプションについては ドキュメント をご確認ください。
TokenBigramIgnoreBlank
と同じ挙動
> tokenize TokenBigramIgnoreBlank "日本語 の 勉強" NormalizerAuto
上述の TokenBigramIgnoreBlank
と同じ処理をする TokenNgram
は以下の通りです。
ポイントはオプションで、 "n", 2
でBigramを、"ignore_blank", true
でIgnoreBlankを指定しています。
> tokenize --tokenizer 'TokenNgram("n", 2, "ignore_blank", true)' --string "日本語 の 勉強" --normalizer NormalizerAuto --output_pretty yes
[
[
0,
1713827246.760704,
0.0002770423889160156
],
[
{
"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
},
{
"value": "強",
"position": 5,
"force_prefix": false,
"force_prefix_search": false
}
]
]
TokenBigramSplitSymbolAlpha
と同じ挙動
> tokenize TokenBigramSplitSymbolAlpha "Hello world こんにちは" NormalizerAuto
上述の TokenBigramSplitSymbolAlpha
と同じ処理をする TokenNgram
は以下の通りです。
"unify_alphabet", false
でASCII文字についてもBigramで分割するようになります。
> tokenize --tokenizer 'TokenNgram("n", 2, "unify_alphabet", false)' --string "Hello world こんにちは" --normalizer NormalizerAuto --output_pretty yes
[
[
0,
1713848466.56066,
0.0004296302795410156
],
[
{
"value": "he",
"position": 0,
"force_prefix": false,
"force_prefix_search": false
},
{
"value": "el",
"position": 1,
"force_prefix": false,
"force_prefix_search": false
},
{
"value": "ll",
"position": 2,
"force_prefix": false,
"force_prefix_search": false
},
{
"value": "lo",
"position": 3,
"force_prefix": false,
"force_prefix_search": false
},
{
"value": "o",
"position": 4,
"force_prefix": false,
"force_prefix_search": false
},
{
"value": "wo",
"position": 5,
"force_prefix": false,
"force_prefix_search": false
},
{
"value": "or",
"position": 6,
"force_prefix": false,
"force_prefix_search": false
},
{
"value": "rl",
"position": 7,
"force_prefix": false,
"force_prefix_search": false
},
{
"value": "ld",
"position": 8,
"force_prefix": false,
"force_prefix_search": false
},
{
"value": "d",
"position": 9,
"force_prefix": false,
"force_prefix_search": false
},
{
"value": "こん",
"position": 10,
"force_prefix": false,
"force_prefix_search": false
},
{
"value": "んに",
"position": 11,
"force_prefix": false,
"force_prefix_search": false
},
{
"value": "にち",
"position": 12,
"force_prefix": false,
"force_prefix_search": false
},
{
"value": "ちは",
"position": 13,
"force_prefix": false,
"force_prefix_search": false
},
{
"value": "は",
"position": 14,
"force_prefix": false,
"force_prefix_search": false
}
]
]