概要
Elasticsearchでアナライザを設定する方法です。
N-gramや形態素解析などありますが、今回は単に設定する方法だけを紹介します。設定方法は主に以下の3通りがあります。
- configで設定する
- インデクス全体に設定する
- 各フィールド個別に設定する
これらを順に説明していきます。
環境
- Ubuntu 14.04
- Elasticsearch 1.4.2
事前知識
アナライザの構成要素
アナライザは次のように構成されています。
ref: Writing analyzers | Elasticsearch.Net and NEST: the .NET clients [2.x] | Elastic
要素 | 説明 | 例 | 順番 | 個数 |
---|---|---|---|---|
Char Filter | 文字レベルの前処理 | Unicode正規化 HTMLエンティティの除去: & を & に変換する |
1 | 0~n |
Tokenizer | テキストをトークンに分割 | スペースを基にして単語に分割する | 2 | 1 |
Token Filter | トークンレベルでの後処理 | 小文字化: Hello を hello に変換する ストップワードの除去: and, the などの一般的な単語を削除 |
3 | 0~n |
パラメータ
Elasticsearchは機能が多い分パラメータも非常に多いです。
設定をする上で知らないと「このパラメータはどういう意味?」ということがあるので、
基本的なものだけあらかじめ紹介します。
デフォルトアナライザ
マッピング定義等で使用されるアナライザが定義されなかった場合はデフォルトのアナライザが使用されます。
設定 | 説明 |
---|---|
default | インデクス時と検索APIの両方でデフォルトのアナライザとして使用 |
default_index | インデクス時のみのデフォルトのアナライザとして使用 |
default_search | 検索時のみのデフォルトのアナライザとして使用 |
これを設定するとデフォルトのアナライザがその設定通りになります。
対象トークン
対象とする文字列の種類です。token_chars
で設定します。
設定 | 説明 |
---|---|
letter | 文字 |
digit | 数字 |
symbol | 記号 |
punctuation | 句読点、濁点など |
では以降アナライザの設定の説明です。
configで設定する
アナライザを指定せずにインデクスを作成した場合にこの設定がデフォルトとなります。
今回はバイグラムでアナライザを設定します。
設定
/etc/elasticsearch/elasticsearch.yml
を編集します。
以下の設定を追加
# default analayzer(2-gram) index.analysis.analyzer.default.tokenizer: custom_bigram_tokenizer index.analysis.tokenizer.custom_bigram_tokenizer.type: nGram index.analysis.tokenizer.custom_bigram_tokenizer.min_gram: 2 index.analysis.tokenizer.custom_bigram_tokenizer.max_gram: 2 index.analysis.tokenizer.custom_bigram_tokenizer.token_chars.0: letter index.analysis.tokenizer.custom_bigram_tokenizer.token_chars.1: digit index.analysis.tokenizer.custom_bigram_tokenizer.token_chars.2: symbol
設定を反映させるため、Elasticsearchを再起動します。
$ sudo service elasticsearch restart
動作確認
インデクスを作成します。
curl -XPUT 'localhost:9200/test'
アナライザの動作を確かめてみましょう。こんにちは世界
という文字列を送ってみます。
$ curl 'localhost:9200/test/_analyze?pretty' -d 'こんにちは世界' { "tokens" : [ { "token" : "こん", "start_offset" : 0, "end_offset" : 2, "type" : "word", "position" : 1 }, { "token" : "んに", "start_offset" : 1, "end_offset" : 3, "type" : "word", "position" : 2 }, { "token" : "にち", "start_offset" : 2, "end_offset" : 4, "type" : "word", "position" : 3 }, { "token" : "ちは", "start_offset" : 3, "end_offset" : 5, "type" : "word", "position" : 4 }, { "token" : "は世", "start_offset" : 4, "end_offset" : 6, "type" : "word", "position" : 5 }, { "token" : "世界", "start_offset" : 5, "end_offset" : 7, "type" : "word", "position" : 6 } ] }
設定したとおり、バイグラムで解析されました。
インデクス全体に設定する
今度はあるインデクスtest
に対して設定してみます。
トリグラムで設定してます。
設定
$ curl -XPUT 'localhost:9200/test' -d ' { "settings": { "analysis": { "analyzer": { "default": { "tokenizer": "custom_trigram_tokenizer" } }, "tokenizer": { "custom_trigram_tokenizer": { "type": "nGram", "min_gram": "3", "max_gram": "3", "token_chars": [ "letter", "digit", "symbol" ] } } } } } '
動作確認
$ curl 'localhost:9200/test/_analyze?pretty' -d 'こんにちは世界' { "tokens" : [ { "token" : "こんに", "start_offset" : 0, "end_offset" : 3, "type" : "word", "position" : 1 }, { "token" : "んにち", "start_offset" : 1, "end_offset" : 4, "type" : "word", "position" : 2 }, { "token" : "にちは", "start_offset" : 2, "end_offset" : 5, "type" : "word", "position" : 3 }, { "token" : "ちは世", "start_offset" : 3, "end_offset" : 6, "type" : "word", "position" : 4 }, { "token" : "は世界", "start_offset" : 4, "end_offset" : 7, "type" : "word", "position" : 5 } ] }
解析するとちゃんと3文字ずつになりました。
マッピングで設定する
個々のフィールドに対してアナライザを指定することもできます。
以下の様なデータを投入するとします。
{ "title": "こんにちは世界", "content": "はじめまして世界" }
設定
マッピングではデフォルトアナライザの指定を以下の名前でフィールドに付けます。
設定 | 説明 |
---|---|
analyzer | インデクス時と検索APIの両方でデフォルトのアナライザとして使用 |
index_analyzer | インデクス時のみのデフォルトのアナライザとして使用 |
search_analyzer | 検索時のみのデフォルトのアナライザとして使用 |
ではマッピングを行います。設定が大きいのであらかじめ以下の内容のmapping.json
というファイルを作ります。
title
をバイグラムで、content
をトリグラムで解析する設定です。
{ "settings": { "analysis": { "analyzer": { "bigram_analyzer": { "tokenizer": "bigram_tokenizer" }, "trigram_analyzer": { "tokenizer": "trigram_tokenizer" } }, "tokenizer": { "bigram_tokenizer": { "type": "nGram", "min_gram": "2", "max_gram": "2", "token_chars": [ "letter", "digit" ] }, "trigram_tokenizer": { "type": "nGram", "min_gram": "3", "max_gram": "3", "token_chars": [ "letter", "digit" ] } } } }, "mappings": { "blog": { "dynamic": false, "properties": { "title": { "type": "string", "index": "analyzed", "analyzer": "bigram_analyzer" }, "content": { "type": "string", "index": "analyzed", "analyzer": "trigram_analyzer" } } } } }
インデクスを作成します。
$ curl -XPUT 'localhost:9200/test' -d @mapping.json
ちゃんと登録されたか確認します。
$ curl -XGET 'localhost:9200/test/_mapping/blog/?pretty' { "test" : { "mappings" : { "blog" : { "dynamic" : "false", "properties" : { "content" : { "type" : "string", "analyzer" : "trigram_analyzer" }, "title" : { "type" : "string", "analyzer" : "bigram_analyzer" } } } } } }
大丈夫そうですね。
動作確認
実際にデータを投入してみます。
$ curl -XPUT 'localhost:9200/test/blog/1' -d ' { "title": "こんにちは世界", "content": "はじめまして世界" } '
ちゃんとtitle
がバイグラムで、content
がトリグラムで引っかかるか確かめます。
curl -XGET 'localhost:9200/test/_search?pretty' -d ' { "query": { "simple_query_string": { "fields": ["title"], "query": "こん" } } } '
以下の結果が出力されます。
{ "took" : 6, "timed_out" : false, "_shards" : { "total" : 5, "successful" : 5, "failed" : 0 }, "hits" : { "total" : 1, "max_score" : 0.11506981, "hits" : [ { "_index" : "test", "_type" : "blog", "_id" : "1", "_score" : 0.11506981, "_source": { "title": "こんにちは世界", "content": "はじめまして世界" } } ] } }
ではトリグラムで作ったインデクスに対して、バイグラムで検索をかけてみるとどうなるでしょう。
curl -XGET 'localhost:9200/test/_search?pretty' -d ' { "query": { "simple_query_string": { "fields": ["content"], "query": "はじ" } } } '
結果は以下のように引っかかりません。インデクス通りですね。
{ "took" : 3, "timed_out" : false, "_shards" : { "total" : 5, "successful" : 5, "failed" : 0 }, "hits" : { "total" : 0, "max_score" : null, "hits" : [ ] } }
トリグラムに対して3文字以上で検索してみましょう。
curl -XGET 'localhost:9200/test/_search?pretty' -d ' { "query": { "simple_query_string": { "fields": ["content"], "query": "て世界" } } } '
予想通りちゃんと引っかかりました。
{ "took" : 2, "timed_out" : false, "_shards" : { "total" : 5, "successful" : 5, "failed" : 0 }, "hits" : { "total" : 1, "max_score" : 0.11506981, "hits" : [ { "_index" : "test", "_type" : "blog", "_id" : "1", "_score" : 0.11506981, "_source": { "title": "こんにちは世界", "content": "はじめまして世界" } } ] } }
以上です。お疲れ様でした。