ElasticsearchのAnalyzerについて

実際にデータを投入し検索できる環境を整える前に、ElasticsearchのAnalyzerに関してもメモを残しておきます。

ElasticsearchのAnalyzerに関する部分は、なかなか難解でした。Elasticsearchには「Character Filter」と「Tokenizer」と「Token Filter」の3つの概念が出てくるのですが、以下のサイトを参考に理解を深めました。ざっくりと説明すると「Character Filter」はその名の通り文字列をフィルタリングして解析に不要なHTMLタグの削除等の事前処理を実行します。次に「Tokenizer」がその文字列を指定された形式毎(通常は品詞毎やスペース毎等)に分割し、「Token Filter」はそこよりさらに解析時に不要となるであろうトークンの削除(例えば助詞とか)やトークンの追加(たとえば漢字のふりがなとか)を行っています。

ElasticsearchのAnalyzerを理解するため全文検索の仕組みをシンプルに考える - $shibayu36->blog;

今回はkuromojiを利用して形態素解析する訳ですが、どういった設定が用意されているか、マニュアルに記載されています。

kuromoji analyzer | Elasticsearch Plugins and Integrations [2.4] | Elastic

こちらのサイトでは日本語で用意されている設定内容を紹介してくれています。

Elasticsearch 日本語で全文検索 その2 – Hello! Elasticsearch. – Medium

資料を読むだけでなく、実際にコマンドを叩きながら解析結果を眺めるのが、理解するに早いです。explainというオプションがあるので、それを利用するのが便利です。

Explain Analyze | Elasticsearch Reference [2.4] | Elastic

tokenizerとして「kuromoji_tokenizer」を利用して、token_filterとして「kuromoji_baseform」と「kuromoji_part_of_speech」を指定し、『飲み放題2時間制の店』という文字列を解析してます。

explainオプションを有効にして実行すると、上から、「token_fileterを使用しないパターン」「kuromoji_baseformのみ有効となっているパターン」「kuromoji_baseformとkuromoji_part_of_speechを有効としているパターン」それぞれが表示されています。

# curl -XGET 'localhost:9200/shikiho/_analyze?pretty' -d'
{
  "tokenizer" : "kuromoji_tokenizer",
  "token_filter" : ["kuromoji_baseform", "kuromoji_part_of_speech"],
  "text" : "飲み放題2時間制の店",
  "explain" : true,
  "attributes" : ["keyword"]
}'
{
  "detail" : {
    "custom_analyzer" : true,
    "charfilters" : [ ],
    "tokenizer" : {
      "name" : "kuromoji_tokenizer",
      "tokens" : [ {
        "token" : "飲み",
        "start_offset" : 0,
        "end_offset" : 2,
        "type" : "word",
        "position" : 0
      }, {
        "token" : "放題",
        "start_offset" : 2,
        "end_offset" : 4,
        "type" : "word",
        "position" : 1
      }, {
        "token" : "2",
        "start_offset" : 4,
        "end_offset" : 5,
        "type" : "word",
        "position" : 2
      }, {
        "token" : "時間",
        "start_offset" : 5,
        "end_offset" : 7,
        "type" : "word",
        "position" : 3
      }, {
        "token" : "制",
        "start_offset" : 7,
        "end_offset" : 8,
        "type" : "word",
        "position" : 4
      }, {
        "token" : "の",
        "start_offset" : 8,
        "end_offset" : 9,
        "type" : "word",
        "position" : 5
      }, {
        "token" : "店",
        "start_offset" : 9,
        "end_offset" : 10,
        "type" : "word",
        "position" : 6
      } ]
    },
    "tokenfilters" : [ {
      "name" : "kuromoji_baseform",
      "tokens" : [ {
        "token" : "飲む",
        "start_offset" : 0,
        "end_offset" : 2,
        "type" : "word",
        "position" : 0,
        "keyword" : false
      }, {
        "token" : "放題",
        "start_offset" : 2,
        "end_offset" : 4,
        "type" : "word",
        "position" : 1,
        "keyword" : false
      }, {
        "token" : "2",
        "start_offset" : 4,
        "end_offset" : 5,
        "type" : "word",
        "position" : 2,
        "keyword" : false
      }, {
        "token" : "時間",
        "start_offset" : 5,
        "end_offset" : 7,
        "type" : "word",
        "position" : 3,
        "keyword" : false
      }, {
        "token" : "制",
        "start_offset" : 7,
        "end_offset" : 8,
        "type" : "word",
        "position" : 4,
        "keyword" : false
      }, {
        "token" : "の",
        "start_offset" : 8,
        "end_offset" : 9,
        "type" : "word",
        "position" : 5,
        "keyword" : false
      }, {
        "token" : "店",
        "start_offset" : 9,
        "end_offset" : 10,
        "type" : "word",
        "position" : 6,
        "keyword" : false
      } ]
    }, {
      "name" : "kuromoji_part_of_speech",
      "tokens" : [ {
        "token" : "飲む",
        "start_offset" : 0,
        "end_offset" : 2,
        "type" : "word",
        "position" : 0,
        "keyword" : false
      }, {
        "token" : "放題",
        "start_offset" : 2,
        "end_offset" : 4,
        "type" : "word",
        "position" : 1,
        "keyword" : false
      }, {
        "token" : "2",
        "start_offset" : 4,
        "end_offset" : 5,
        "type" : "word",
        "position" : 2,
        "keyword" : false
      }, {
        "token" : "時間",
        "start_offset" : 5,
        "end_offset" : 7,
        "type" : "word",
        "position" : 3,
        "keyword" : false
      }, {
        "token" : "制",
        "start_offset" : 7,
        "end_offset" : 8,
        "type" : "word",
        "position" : 4,
        "keyword" : false
      }, {
        "token" : "店",
        "start_offset" : 9,
        "end_offset" : 10,
        "type" : "word",
        "position" : 6,
        "keyword" : false
      } ]
    } ]
  }
}