ページ

2016年3月3日木曜日

Elasticsearchを学ぶ 4 - Analyzer -


今回はMappingする際に設定できるAnalyzerというものを触ってみたいと思います。
その前に・・・
前回作成したmapping.jsonの補足です
"user_id":  {
  "type":   "string",
  "index":  "not_analyzed"
},
user_idのフィールドに対してtypeがstringでindexがnot_analyzedとなっています。
このnot_analyzedですが構文解析せず完全一致で検索します。
例えば・・
user_idにABCD-1234というデータが入ってる場合にnot_analyzedを指定せずにABCDや1234で検索した場合
ABCD-5678でもEFGH-1234でもヒットしてしまいます。
ユニークなフィールドにはつけたほうがいいやつです。
次に・・
"created":  {
  "type":   "date",
  "format": "strict_date_optional_time||epoch_millis"
}
ですが、JSONは日時のデータ型を持ってないので、以下の3つの方法で表現します。
  1. 文字列 ('2016-01-01'や'2016/01/01 10:10:50'など)
  2. 数値 (1970/01/01 00:00:00からの経過ミリ秒(UTC))
  3. 数値 (1970/01/01 00:00:00からの経過秒(UTC))
↑のstrict_date_optional_time||epoch_millis2になります

Analyzer


一つのanalyzerは一つのTokenizerと0個以上のTokenFiltersで構成されます。
サンプルとして以下のMappingをanalyzer_testというIndexに作成します。
※このサンプルではTokenFiltersは使用してません。
{
  "settings": {
      "analysis": {
          "analyzer": {
              "my_analyzer": {
                  "tokenizer": "my_tokenizer"
              }
          },
          "tokenizer": {
              "my_tokenizer": {
                  "type": "nGram",
                  "min_gram": "2",
                  "max_gram": "2",
                  "token_chars": [
                      "letter",
                      "digit"
                  ]
              }
          }
      }
  },
  "mappings": {
    "sample": {
      "properties": {
        "text": {
          "type": "string",
          "analyzer": "my_analyzer"
        },
        "subtext": {
          "type": "string",
          "analyzer": "my_analyzer"
        }
      }
    }
  }
}
my_tokenizerとして設定している箇所で、nGramとありますが、
これはN個文字を区切って検索するものです。ここではmin_grammax_gram
2と設定しているので2文字毎区切って検索を行います。
早速analyzer_test_mapping.jsonとして保存しインポート
$ curl -X POST 192.168.33.180:9200/analyzer_test -d @analyzer_test_mapping.json
ちゃんと設定できているか確認してみます。
$ curl -X GET '192.168.33.180:9200/analyzer_test/_mapping/sample/?pretty'
{
  "analyzer_test" : {
    "mappings" : {
      "sample" : {
        "properties" : {
          "subtext" : {
            "type" : "string",
            "analyzer" : "my_analyzer"
          },
          "text" : {
            "type" : "string",
            "analyzer" : "my_analyzer"
          }
        }
      }
    }
  }
}
ちゃんと設定できているので、データ登録して動作を確認してみます。
$ curl -X PUT 192.168.33.180:9200/analyzer_test/sample/1 -d '{
   "text" : "abcdefg", "subtext" : "123456789"
 }'
まずは、分割された2文字に対して検索。
$ curl -XPOST '192.168.33.180:9200/analyzer_test/_search?pretty' -d
'{ "query": { "match": { "text": "cd" } } }'
{
  "took" : 3,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "failed" : 0
  },
  "hits" : {
    "total" : 1,
    "max_score" : 0.11506981,
    "hits" : [ {
      "_index" : "analyzer_test",
      "_type" : "sample",
      "_id" : "1",
      "_score" : 0.11506981,
      "_source" : {
        "text" : "abcdefg",
        "subtext" : "123456789"
      }
    } ]
  }
}
これはヒットしますが、1文字で検索してみると、
$ curl -XPOST '192.168.33.180:9200/analyzer_test/_search?pretty' -d
'{ "query": { "match": { "text": "c" } } }'
{
  "took" : 8,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "failed" : 0
  },
  "hits" : {
    "total" : 0,
    "max_score" : null,
    "hits" : [ ]
  }
}
最低2文字で単語を分割してる為こちらはヒットしません。
結構細かくAnalyzerを調整できるので、チューニング次第でヒット率が上がったり下がったりしそうですね。

0 件のコメント:

コメントを投稿