elasticsearchのindexingをunderscoreで分割する

elasticsearchのデフォルトのtokenizerは'-'や'&'では分割してくれますが，'_'では分割してくれません．つまり

```
"elastic-search test_data"
```
は
```
elastic, search, test_data
```
のように分割されます．これを```test, data```のようにunderscoreで分割する方法を探していました．

## Word Delimiter Token Filter を使う

filterの```word_delimiter```では区切り文字に関する設定を色々変えることができます．詳しくは[https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-word-delimiter-tokenfilter.html](https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-word-delimiter-tokenfilter.html)を参照してください．

この```word_delimiter```にある```type_table```を使うと文字の属性(ALPHA, ALPHANUM, DIGIT, SUBWORD_DELIM等)を変えることができます．今回はunderscoreの属性をSUBWORD_DELIMに変えます．

```
$ curl -XPOST 'http://localhost:9200/test/' -d '
{
  "settings": {
    "analysis": {
      "filter": {
        "underscore_splitter": {
          "type": "word_delimiter",
          "type_table": [
            "_ => SUBWORD_DELIM"
          ]
        }
      },
      "analyzer": {
        "default": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": [
            "lowercase",
            "underscore_splitter"
          ]
        }
      }
    }
  }
}
'
```
でセッテイングを登録し，analyzerの挙動を確認すると，

```
$ curl 'localhost:9200/test/_analyze' -d 'elastic-search test_data'
```

```json
{
  "tokens": [
    {
      "token": "elastic",
      "start_offset": 0,
      "end_offset": 7,
      "type": "<ALPHANUM>",
      "position": 1
    },
    {
      "token": "search",
      "start_offset": 8,
      "end_offset": 14,
      "type": "<ALPHANUM>",
      "position": 2
    },
    {
      "token": "test",
      "start_offset": 15,
      "end_offset": 19,
      "type": "<ALPHANUM>",
      "position": 3
    },
    {
      "token": "data",
      "start_offset": 20,
      "end_offset": 24,
      "type": "<ALPHANUM>",
      "position": 4
    }
  ]
}
```

確かにtokenizerがunderscoreで分割しています．

## おまけ: オリジナルを残す

また，```word_delimiter```は，```preserve_original```を```true```に設定することでindexingする際にオリジナルの文章を残すこともできます．

```
$ curl -XPOST 'http://localhost:9200/test/' -d '
{
  "settings": {
    "analysis": {
      "filter": {
        "underscore_splitter": {
          "type": "word_delimiter",
          "preserve_original": true,
          "type_table": [
            "_ => SUBWORD_DELIM"
          ]
        }
      },
      "analyzer": {
        "default": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": [
            "lowercase",
            "underscore_splitter"
          ]
        }
      }
    }
  }
}
'
```

これにより，```"elastic-search test_data"```を，```elastic, search, test_data, test, data```のように分割することができます．

### 更におまけ: Mapping Char Filter を使う

mapping char filter を使うと，indexに登録する際に文字を変換して登録することができます．詳しくは[こちら](https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-mapping-charfilter.html)．

これを使って，

```json
{
  "settings": {
    "analysis": {
      "char_filter": {
        "my_mapping": {
          "type": "mapping",
          "mappings": ["_=>-"]
        }
      },
      "analyzer": {
        "default": {
          "tokenizer": "standard",
          "char_filter": [
            "my_mapping"
          ]
        }
      }
    }
  }
}
```
のように無理やり'_'を'-'に変換して登録し，無理やり```test, data```と分割する方法も考えましたが，あまりに汚いので他の方法を探し，上記のやり方にたどり着きました．ただMapping Char Filter自体は色々便利そうです．