# Edge NGram Token Filterを使用した場合のhighlightについて

**URL:** <https://discuss.elastic.co/t/edge-ngram-token-filter-highlight/166275>\
**Category:** 日本語による質問・議論はこちら\
**Created:** [January 30, 2019, 7:12am UTC](https://discuss.elastic.co/t/edge-ngram-token-filter-highlight/166275 "2019-01-30T07:12:40Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![b18bd8be4bf795b30ee7](https://avatars.discourse-cdn.com/v4/letter/b/3e96dc/32.png) [@b18bd8be4bf795b30ee7](https://discuss.elastic.co/u/b18bd8be4bf795b30ee7)\
**Post date:** [January 30, 2019, 7:12am UTC](https://discuss.elastic.co/t/edge-ngram-token-filter-highlight/166275/1 "2019-01-30T07:12:40Z")

</div>

Edge NGram Token Filterを使用しています。検索にてHITした箇所にhighlightをつけたいのですが、想定した箇所とは異なる部分がhighlightされており、どうすればよいのか、アドバイスをいただければ幸いです。

Elasticsearch 6.3.0

●インデックスのmapping

```
PUT /my_index
{
  "settings" : {
    "index": {
      "analysis": {
        "filter":{
          "edgeNGramFilter":{
            "type" : "edgeNGram",
            "max_gram" : 50
          }
        },
        "analyzer": {
          "jp_analyzer": {
            "tokenizer": "kuromoji_tokenizer",
            "filter": [
              "kuromoji_stemmer",
              "edgeNGramFilter"
            ]
          },
          "jp_search_analyzer": {
            "tokenizer": "kuromoji_tokenizer",
            "filter": [
              "kuromoji_stemmer"
            ]
          }
        }
      }
    }
  },
  "mappings" : {
    "my_type" : {
      "properties" : {
        "code" : {
          "type" : "keyword"
        },
        "contents" : {
          "type" : "text",
          "analyzer" : "jp_analyzer",
          "search_analyzer" : "jp_search_analyzer"
        }
      }
    }
  }
}

```

●ドキュメント

```
POST _bulk
{ "index" : { "_index" : "my_index", "_type" : "my_type", "_id" : "1" } }
{ "contents": "本日は晴天なり。お隣の花壇に、秋桜の花が咲き乱れる。", "code": "1-1" }

```

●クエリ

```
GET my_index/_search
{
  "_source": false, 
  "query": {
    "match": {
      "contents": "秋"
    }
  },
  "highlight": {
    "fields": {
      "contents" : {}
    }
  }
}

```

●結果

```
{
  "took": 17,
  "timed_out": false,
  "_shards": {
    ･･･
  },
  "hits": {
    "total": 1,
    "max_score": 0.73617005,
    "hits": [
      {
        "_index": "my_index",
        "_type": "my_type",
        "_id": "1",
        "_score": 0.34992102,
        "highlight": {
          "contents": [
            "お隣の花壇に、<em>秋桜</em>の花が咲き乱れる。"
          ]
        }
      }
    ]
  }
}

```

結果として

```auto
"お隣の花壇に、<em>秋桜</em>の花が咲き乱れる。"

```

となりますが、検索したワードが「秋」の為

```auto
"お隣の花壇に、<em>秋</em>桜の花が咲き乱れる。"

```

となるのが理想です。

tokenizerの結果としての「秋桜」がhighlightされているのであろう、という事象は理解できるのですが、ではどうすれば「秋」だけがhighlightされるのかが判りません。  
調べてみたところ、Token FilterではなくTokenizerでEdge NGram を使用すればうまくいく、ということがわかりましたが、対象とする文字列が日本語の文章であるため、Tokenizerはkuromojiでないと単語の区切りができないのでは？と考えております。

前方一致検索をしたい為、Edge NGramを使用しておりますが、Edge NGramにこだわってはおりません。（ただ、Edge NGramを使用せずにPrefix Queryも試してみましたが、結果は同じでした。）

どうぞよろしくお願いいたします。

---

<div class="post-metadata">

**Author:** ![r4-keisuke](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/r4-keisuke/32/9268_2.png) [@r4-keisuke](https://discuss.elastic.co/u/r4-keisuke)\
**Post date:** [January 30, 2019, 2:25pm UTC](https://discuss.elastic.co/t/edge-ngram-token-filter-highlight/166275/2 "2019-01-30T14:25:45Z")

</div>

こんばんは。

ハイライトはanalyzerで作られたTermが反映されるようなので、kuromoji\_tokenizerにしてしまうと、どっちにしろtokenの分け方が形態素になってしまうと思うので、それをtoken filterでedgeNGramにして1文字ずつにしてもhighlightされないようです。

なので、もう最初から区切ったほうがいいので、kuromoji\_tokenizerを使わず、最初からngramでやっちゃいます。

```auto
PUT /my_index
{
  "settings" : {
    "index": {
      "analysis": {
        "tokenizer":{
          "ngram_tokenizer":{
            "type" : "nGram"
          }
        },
        "analyzer": {
          "jp_analyzer": {
            "tokenizer": "ngram_tokenizer"
          },
          "jp_search_analyzer": {
            "tokenizer": "kuromoji_tokenizer",
            "filter": [
              "kuromoji_stemmer"
            ]
          }
        }
      }
    }
  },
  "mappings" : {
    "my_type" : {
      "properties" : {
        "code" : {
          "type" : "keyword"
        },
        "contents" : {
          "type" : "text",
          "analyzer" : "jp_analyzer",
          "search_analyzer" : "jp_search_analyzer"
        }
      }
    }
  }
}

```

これでいけます。

試してみると

```auto
{
  "took": 13,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 1,
    "max_score": 0.29000834,
    "hits": [
      {
        "_index": "my_index2",
        "_type": "my_type",
        "_id": "1",
        "_score": 0.29000834,
        "_source": {
          "contents": "本日は晴天なり。お隣の花壇に、秋桜の花が咲き乱れる。",
          "code": "1-1"
        },
        "highlight": {
          "contents": [
            "お隣の花壇に、<em>秋</em>桜の花が咲き乱れる。"
          ]
        }
      }
    ]
  }
}

```

少し厄介ですが、これでなんとかいけそうですね。

---

<div class="post-metadata">

**Author:** ![r4-keisuke](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/r4-keisuke/32/9268_2.png) [@r4-keisuke](https://discuss.elastic.co/u/r4-keisuke)\
**Post date:** [January 30, 2019, 2:35pm UTC](https://discuss.elastic.co/t/edge-ngram-token-filter-highlight/166275/3 "2019-01-30T14:35:44Z")

</div>

と思いましたけど  
単純にanalyzerがngramになってるだけで適用されたものなので、結局検索がngramになってしまってだめですねー

うーん  
もう少し調べます

---

<div class="post-metadata">

**Author:** ![r4-keisuke](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/r4-keisuke/32/9268_2.png) [@r4-keisuke](https://discuss.elastic.co/u/r4-keisuke)\
**Post date:** [January 30, 2019, 3:02pm UTC](https://discuss.elastic.co/t/edge-ngram-token-filter-highlight/166275/4 "2019-01-30T15:02:11Z")

</div>

少し考えてみましたが、ハイライトがanalyzerで指定したanalyzerによってtokenizeされたもの（token\_filterの影響は受けないようなので）、index自体を分けたほうがいいなと思いました。  
ちょっとトリッキーではありますが、  
以下のようにすると要件は満たせます。

Mapping

```auto
PUT /my_index2
{
  "settings" : {
    "index": {
      "analysis": {
        "filter":{
          "edgeNGramFilter":{
            "type" : "edgeNGram",
            "max_gram" : 50
          }
        },
        "tokenizer":{
          "ngram_tokenizer":{
            "type" : "nGram"
          }
        },
        
        "analyzer": {
          "jp_analyzer": {
            "tokenizer": "kuromoji_tokenizer",
            "filter": [
              "kuromoji_stemmer",
              "edgeNGramFilter"
            ]
          },
          "highlight_analyzer": {
            "tokenizer": "ngram_tokenizer"
          },
          "jp_search_analyzer": {
            "tokenizer": "kuromoji_tokenizer",
            "filter": [
              "kuromoji_stemmer"
            ]
          }
        }
      }
    }
  },
  "mappings" : {
    "my_type" : {
      "properties" : {
        "code" : {
          "type" : "keyword"
        },
        "contents" : {
          "type" : "text",
          "analyzer" : "jp_analyzer",
          "search_analyzer" : "jp_search_analyzer"
        },
        "contents_highlight" : {
          "type" : "text",
          "analyzer" : "highlight_analyzer"
        }
      }
    }
  }
}

```

Query

```auto
GET my_index2/_search
{
  "_source": false,
  "query": {
    "match": {
      "contents": "秋"
    }
  },
  "highlight": {
    "fields": {
      "contents_highlight" : {
        "highlight_query": {
          "match": {
            "contents_highlight": "秋"
          }
        }
      }
    }
  }
}

```

Result

```auto
{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 1,
    "max_score": 0.34992102,
    "hits": [
      {
        "_index": "my_index2",
        "_type": "my_type",
        "_id": "1",
        "_score": 0.34992102,
        "highlight": {
          "contents_highlight": [
            "お隣の花壇に、<em>秋</em>桜の花が咲き乱れる。"
          ]
        }
      }
    ]
  }
}

```

今はこれくらいしか思いつかないですね、すみません！

---

<div class="post-metadata">

**Author:** ![b18bd8be4bf795b30ee7](https://avatars.discourse-cdn.com/v4/letter/b/3e96dc/32.png) [@b18bd8be4bf795b30ee7](https://discuss.elastic.co/u/b18bd8be4bf795b30ee7)\
**Post date:** [January 31, 2019, 3:18am UTC](https://discuss.elastic.co/t/edge-ngram-token-filter-highlight/166275/5 "2019-01-31T03:18:45Z")

</div>

ご回答ありがとうございます。

> 少し考えてみましたが、ハイライトがanalyzerで指定したanalyzerによってtokenizeされたもの（token\_filterの影響は受けないようなので）、index自体を分けたほうがいいなと思いました。

highlight\_queryを知らなかったので、matchクエリと highlight\_queryで別々のfieldを対象としてanalyzerを変える、というアプローチがあるのか！と、とても勉強になりました。

ご提示いただいた方法で検証いたしました。大体において要件を満たしていたのですが、highlight\_queryにてnGramしたものをmatchで探しに行くと、ノイズがひっかかってしまいました。（「隣人」をhighlightで囲いたいのに、「隣の客」の「隣」もHITしてしまう。）  
こちらを避ける為、match\_phraseでの検索に修正いたしました。

また、contentsとcontents\_highlightで、同じデータを登録するのが面倒に思えたので、copy\_toを使用するようmappingを修正しました。  
結果、下記にて、イメージどおりの検索が行えるようになりました。ありがとうございます。

●mapping

```
PUT /my_index3
{
  "settings" : {
    "index": {
      "analysis": {
        "filter":{
          "edgeNGramFilter":{
            "type" : "edgeNGram",
            "max_gram" : 50
          }
        },
        "tokenizer":{
          "ngram_tokenizer":{
            "type" : "nGram"
          }
        },
        "analyzer": {
          "jp_analyzer": {
            "tokenizer": "kuromoji_tokenizer",
            "filter": [
              "kuromoji_stemmer",
              "edgeNGramFilter"
            ]
          },
          "highlight_analyzer": {
            "tokenizer": "ngram_tokenizer"
          },
          "jp_search_analyzer": {
            "tokenizer": "kuromoji_tokenizer",
            "filter": [
              "kuromoji_stemmer"
            ]
          }
        }
      }
    }
  },
  "mappings" : {
    "my_type" : {
      "properties" : {
        "code" : {
          "type" : "keyword"
        },
        "contents" : {
          "type" : "text",
          "analyzer" : "jp_analyzer",
          "search_analyzer" : "jp_search_analyzer",
          "copy_to": "contents_highlight"
        },
        "contents_highlight" : {
          "type" : "text",
          "analyzer" : "highlight_analyzer",
          "store": true
        }
      }
    }
  }
}

```

●ドキュメント

```
POST _bulk
{ "index" : { "_index" : "my_index3", "_type" : "my_type", "_id" : "1" } }
{ "contents": "本日は晴天なり。お隣の花壇に、秋桜の花が咲き乱れる。", "code": "1-1" }
{ "index" : { "_index" : "my_index3", "_type" : "my_type", "_id" : "2" } }
{ "contents": "隣の客が隣の人の柿食う。その隣人とはまた違う。", "code": "1-2" } 

```

●クエリ

```
GET my_index3/_search
{
  "_source": false,
  "query": {
    "match": {
      "contents": "隣人"
    }
  },
  "highlight": {
    "fields": {
      "contents_highlight" : {
        "highlight_query": {
          "match_phrase": {
            "contents_highlight": "隣人"
          }
        }
      }
    }
  }
}

```

●結果

```
{
  "took": 2,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 1,
    "max_score": 0.3187269,
    "hits": [
      {
        "_index": "my_index3",
        "_type": "my_type",
        "_id": "2",
        "_score": 0.3187269,
        "highlight": {
          "contents_highlight": [
            "その<em>隣</em><em>人</em>とはまた違う。"
          ]
        }
      }
    ]
  }
}

```

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/elastic/original/3X/1/a/1ac57faf039f6b580b3f104ef42a2a89e41014de.png) [@system](https://discuss.elastic.co/u/system)\
**Post date:** [February 28, 2019, 3:18am UTC](https://discuss.elastic.co/t/edge-ngram-token-filter-highlight/166275/6 "2019-02-28T03:18:49Z")

</div>

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.
