Elasticsearchで電話番号をAutoCompleteさせる

# 概要

Elasticsearchのサジェスト機能を使って、電話番号のような数字の羅列をAutoCompleteさせようとしたときに詰まったところの備忘録がてらにご紹介。

|soft|version|
|----|----|
|Elasticsearch|6.3.2|
|Kibana|6.3.2|



# 使うもの

- Completion Suggester

  https://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters-completion.html

# 嵌りポイント

公式のドキュメントを写経しても、電話番号のような文字列を入れたときには、期待した結果が得られない。

```
PUT music
{
    "mappings": {
        "_doc" : {
            "properties" : {
                "suggest" : {
                    "type" : "completion"
                },
                "title" : {
                    "type": "keyword"
                }
            }
        }
    },
    "settings": {
        "number_of_shards": 1,
        "number_of_replicas": 0
    }
}
POST music/_doc/1?refresh
{
    "suggest" : {
        "input": [ "Nevermind", "Nirvana" ],
        "weight" : 34
    }
}

POST music/_doc/2?refresh
{
    "suggest" : {
        "input": [ "aiueo", "0120444449" ],
        "weight" : 30
    }
}

```

と、このようにデータを用意します。
本家のドキュメント、ほぼそのままです。

```
POST music/_search
{
    "suggest": {
        "song-suggest" : {
            "prefix" : "Nir", 
            "completion" : { 
                "field" : "suggest" 
            }
        }
    }
}
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/111676/bc7f4da4-31bd-f9d9-8878-1ec1759134f4.png)


これだと、サジェスト結果が得られますが、下のほうにprefixで0120といれたときは、結果が得られません。
0120で始まるデータ（id=2)のデータがヒットして欲しいと思っています。


```
POST music/_search
{
    "suggest": {
        "song-suggest" : {
            "prefix" : "0120", 
            "completion" : { 
                "field" : "suggest" 
            }
        }
    }
}
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/111676/1c21fd60-2225-b042-c24b-5b852847a619.png)


# 何が良くないのか

困ったときは、公式のドキュメントをググるか、discussやGithubのissueを見るのが手っ取り早いです。

そうしますと、良い感じのものが既に投稿されていますね。

[Completion Suggester : Support for numeric value completion suggestion](
https://discuss.elastic.co/t/completion-suggester-support-for-numeric-value-completion-suggestion/19135)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/111676/691fe698-624b-863c-7db9-1ddb391732cd.png)


> The default analyzer used in the completion suggester is the simple one,
which strips out numbers.

デフォルトのAnalyzer（=simple)だと、数字はstripされるよ、と。
なので、通常の文字列は問題なく動作したのに、数字の羅列のような電話番号だと、サジェストされなかった、ということですな。

# じゃあ、どうするか

analyzerをsimpleでなく、例えばstandardなどを選びます。
（このあたりは、discussにもあるように、ユースケースに応じて選ぶべきでしょう）

```
PUT music
{
    "mappings": {
        "_doc" : {
            "properties" : {
                "suggest" : {
                    "type" : "completion",
                    "analyzer": "standard"
                },
                "title" : {
                    "type": "keyword"
                }
            }
        }
    }
    , "settings": {
        "number_of_shards": 1,
        "number_of_replicas": 0
    }
}
```

このように、マッピングを作り直して、再度クエリを投げてみます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/111676/96fd8e9c-53fa-1e18-f7e4-81575981751f.png)


おおお、サジェスト結果が得られましたね！！！

# ドキュメントを再度見る

で、再度ドキュメントを確認しますと、analyzerのところには、こんな記述があります。

https://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters-completion.html


![image.png](https://qiita-image-store.s3.amazonaws.com/0/111676/d05922a1-2ce4-ddb0-fc17-2599a55a8ee2.png)


> In case you are wondering why we did not opt for the standard analyzer: We try to have easy to understand behaviour here

理解を容易にするためstandardじゃなくてsimple analyzerにしてるよ、とちゃんと書いてありました。
入る値、どういう検索をしたいのかを考慮してanalyzerを選びなさい、ってことですな。