Elasticsearchにメールアドレスを放り込む際、どうもサブドメイン等でSearchを行う際にうまく検索ができないことがあった。 そもそもElasticsearchの検索の仕組みをよく理解できてなかったのもあるのだが、ドキュメント作成時にAnalyzerで分割した文字単位で検索を行うようだ。 で、その差異にデフォルトのAnalyzerではうまくメールアドレスの分割ができていなかったのが原因のようだ。

Elasticsearchでは、以下のようにリクエストを投げることでAnalyzerでどのように分割されるのかを見ることができるので、それでメールアドレスがどのように分割されるのか見てみよう。

まず、新規で追加するAnalyzerは以下のjsonで作成できるので、これを適当なファイル名(ここではdomain_analyzer.json)でファイルを作成しよう。

{
  "analysis": {
    "analyzer": {
      "domain_analyzer": {
        "filter":"lowercase",
        "tokenizer": "domain_tokenizer",
        "type": "custom"
      }
    },
    "tokenizer": {
      "domain_tokenizer": {
        "type": "PathHierarchy",
        "delimiter": ".",
        "reverse": true
      }
    }
  }
}

ファイルを作成したら、以下のコマンドで既存のINDEXにAnalyzerを追加する。

curl -XPUT 'localhost:9200/INDEX名/_mapping/TYPE名' -d @domain_analyzer.json

これで、指定したINDEXにAnalyzerの追加ができたはずだ。 以下のコマンドで、追加したAnalyzerがどのようにパースするのかが確認できる。

curl 'localhost:9200/INDEX名/_analyze?analyzer=domain_analyzer&pretty' -d 'xxx-ddd.test.co.jp'
test@test-es:~$ curl 'localhost:9200/test/_analyze?analyzer=domain_analyzer&pretty' -d 'xxx-ddd.test.co.jp'
{
  "tokens" : [
    {
      "token" : "xxx-ddd.test.co.jp",
      "start_offset" : 0,
      "end_offset" : 18,
      "type" : "word",
      "position" : 0
    },
    {
      "token" : "test.co.jp",
      "start_offset" : 8,
      "end_offset" : 18,
      "type" : "word",
      "position" : 0
    },
    {
      "token" : "co.jp",
      "start_offset" : 13,
      "end_offset" : 18,
      "type" : "word",
      "position" : 0
    },
    {
      "token" : "jp",
      "start_offset" : 16,
      "end_offset" : 18,
      "type" : "word",
      "position" : 0
    }
  ]
}

あとは、mappingで特定のフィールドにAnalyzerを追加してやればいいだろう。 既存のデータに対しては、後からフィールドにAnalyzerを追加しても意味がないようなので、インデックス化を再度やり直したほうがいいようだ。