# NGram Tokenizerについて

**URL:** <https://discuss.elastic.co/t/ngram-tokenizer/217161>\
**Category:** 日本語による質問・議論はこちら\
**Created:** [January 30, 2020, 10:56am UTC](https://discuss.elastic.co/t/ngram-tokenizer/217161 "2020-01-30T10:56:30Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![Yukie](https://avatars.discourse-cdn.com/v4/letter/y/7ba0ec/32.png) [@Yukie](https://discuss.elastic.co/u/Yukie)\
**Post date:** [January 30, 2020, 10:56am UTC](https://discuss.elastic.co/t/ngram-tokenizer/217161/1 "2020-01-30T10:56:30Z")

</div>

はじめまして。  
Elasticsearch初心者です。

日本語・英語・記号など、さまざまな文字が含まれるデータの中より、  
単純に指定した文字が含まれる（部分一致）データを抽出しようとしています。

指定する文字は「１文字～」です。

```
ngram_tokenizer: {
    type: "nGram",
    min_gram: "1",
    max_gram: "2",
    token_chars: ["letter", "digit", "punctuation", "symbol"]
 }

 ngram_analyzer: {
    tokenizer: "ngram_tokenizer",
    filter: [
        "greek_lowercase_filter"
    ]
 }

```

といったようなAnalyzer定義をし、実際のデータの  
マッピング指定は、単純に以下のような指定としています。

```
descriptiondata: { type: 'text',
                                 analyzer: "ngram_analyzer" }

```

インデックスに登録されたデータが日本語、英語であろうと、  
大半のパターンが問題なく検索できているのですが、  
検索対象文字を test と指定しているにも関わらず、

```
 esstem

```

がデータで登録されているものがヒットしてしまいます。

ElasticserachのVerは5.4.3です。  
NGramであれば、このような検索結果となってしまうのでしょうか。

よろしくお願いいたします。

---

<div class="post-metadata">

**Author:** ![tsgkdt](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/tsgkdt/32/39151_2.png) [@tsgkdt](https://discuss.elastic.co/u/tsgkdt)\
**Post date:** [January 31, 2020, 12:37am UTC](https://discuss.elastic.co/t/ngram-tokenizer/217161/2 "2020-01-31T00:37:39Z")

</div>

こんにちわ

NGramであれば、というよりは検索クエリに依ると考えています。  
どのような検索クエリを実行されてますでしょうか？

たとえば、以下のようなクエリを想定しました。

```auto
POST forum0131/_search
{
  "query": {
    "simple_query_string": {
      "query": "test",
      "fields": ["descriptiondata"],
      "default_operator": "and"
    }
  }
}

POST forum0131/_search
{
  "query": {
    "match": {
      "descriptiondata": {
        "query": "test",
        "operator": "and"
      }
    }
  }
}

```

こうした指定ですと、"t”, "e", "s", "t", "te", "es", "st" が **順不同で** 、 **トークンとして存在すれば** 、検索にヒットとなります。  
esstem を考えたとき、 "e", "s", "t" というトークンが出来るわけで、順不同であれば testから生成されるトークンと合致しますよね。

順不同ではなく、順序も条件に含めたいときは、simple\_query\_stringであれば 検索キーワードを""で囲む、あるいはmatch\_phraseを使うと良いのではと思います。

```auto
POST forum0131/_search
{
  "query": {
    "simple_query_string": {
      "query": "\"test\"",
      "fields": ["descriptiondata"],
      "default_operator": "and"
    }
  }
}

POST forum0131/_search
{
  "query": {
    "match_phrase": {
      "descriptiondata": "test"
    }
  }
}

```

念のためですが、simple\_query\_stringやmatchは、デフォルトでOR検索になっているので  
test という条件を入れたときは、 t OR e OR s OR t OR te OR es OR st というような検索になるので、  
検索対象のフィールドに "t" しかない状態でも、testという検索キーワードでヒットする、ということになります。

そのため、最初の方に示した例では、operatorにand指定を追加するようにしております。

ご参考になれば幸いです。

以下、こちらが確認した際に使った設定を転記しておきます。

### インデックス設定

```auto
PUT forum0131
{
  "settings": {
    "analysis": {
      "analyzer": {
        "ngram_analyzer": {
          "tokenizer": "ngram_tokenizer",
          "filter": [
            
          ]
        }
      },
      "tokenizer": {
        "ngram_tokenizer": {
          "type": "nGram",
          "min_gram": "1",
          "max_gram": "2",
          "token_chars": [
            "letter",
            "digit",
            "punctuation",
            "symbol"
          ]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "descriptiondata": {
        "type": "text",
        "analyzer": "ngram_analyzer"
      }
    }
  }
}

```

### テストデータ

```auto
POST forum0131/_doc/1
{
  "descriptiondata": "esstem"
}

```

---

<div class="post-metadata">

**Author:** ![Yukie](https://avatars.discourse-cdn.com/v4/letter/y/7ba0ec/32.png) [@Yukie](https://discuss.elastic.co/u/Yukie)\
**Post date:** [January 31, 2020, 1:49am UTC](https://discuss.elastic.co/t/ngram-tokenizer/217161/3 "2020-01-31T01:49:28Z")

</div>

tsgkdt さん、ありがとうございます！

ご指摘通り、単に and 指定のクエリになっています。  
NGram自体の使い方には、これ以上変更するものはない  
と思っていましたので、怪しい可能性があるクエリを  
ご指摘いただき、希望の光が見えてきました。

「 こうした指定ですと、"t”, "e", "s", "t", "te", "es", "st" が **順不同で** 、  
**トークンとして存在すれば** 、検索にヒットとなります。  
esstem を考えたとき、 "e", "s", "t" というトークンが出来るわけで、  
順不同であれば testから生成されるトークンと合致しますよね。」

そうですよね。おっしゃる通りです。

クエリに関する知識がほとんどないので、本当に助かりました。  
ご提示いただいた内容で、いろいろ試してみたいと思います。

取り急ぎ、お礼のお返事でした。。

---

<div class="post-metadata">

**Author:** ![tsgkdt](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/tsgkdt/32/39151_2.png) [@tsgkdt](https://discuss.elastic.co/u/tsgkdt)\
**Post date:** [January 31, 2020, 2:25am UTC](https://discuss.elastic.co/t/ngram-tokenizer/217161/4 "2020-01-31T02:25:53Z")

</div>

何点か補足させてください。

5.4.xは、既にEOLになっているので、バージョンアップも計画されたほうが良いと老婆心ながら思いました。  
[https://www.elastic.co/jp/support/eol](https://www.elastic.co/jp/support/eol)

なぜヒットするか、ヒットしないのか、という点については、  
どういうトークンに分割されているのかという確認が大切だと思っています。  
その確認には、analyze apiが使えます。よろしければ参照ください。  
[https://www.elastic.co/guide/en/elasticsearch/reference/5.4/indices-analyze.html](https://www.elastic.co/guide/en/elasticsearch/reference/5.4/indices-analyze.html)

GUIでの確認については、@johtani さんが、プラグインとして作成されて公開していらっしゃいます。  
利用イメージは下記をごらんください。（たぶん、バージョン６系以降のリリースだった気がします）

> **[Analyze UIとKibanaのプラグインの作成方法（第1回）](https://blog.johtani.info/blog/2018/01/19/how-to-make-kibana-plugin-example-analysis-ui/#analyze-ui-plugin%E3%81%A8%E3%81%AF)**
>
> johtaniの日記です。技術とか、他愛のないことを書き連ねていくブログです。 | johtani's blog site that includes topics, e.g. technical, life, hobby, etc.

あとは、検索クエリに "explain": true をつけることで、検索にヒットしたときのより詳細な情報を得ることができます。

ご参考になれば幸いです。

---

<div class="post-metadata">

**Author:** ![Yukie](https://avatars.discourse-cdn.com/v4/letter/y/7ba0ec/32.png) [@Yukie](https://discuss.elastic.co/u/Yukie)\
**Post date:** [January 31, 2020, 2:50am UTC](https://discuss.elastic.co/t/ngram-tokenizer/217161/5 "2020-01-31T02:50:01Z")

</div>

tsgkdtさん

もろもろご指摘、情報ありがとうございます！  
まずは、先程のアドバイスに従って修正したところ、  
期待している動きとなりました。ありがとうございました！

そうですよね。VerUPも必要ですよね。計画しておきます。  
Kibanaもインストールして利用しているのですが、  
まだ十分に活用できてない気がしてます。

トークン分割の確認もマストですよね。  
そもそも、ヒットが順不同という点を動きから推測は  
できてもどのように対処すべきか調べきれてませんでした。

大変助かりました。本当にありがとうございました。  
（"explain":true も初めてりました。ありがとうございます）

---

<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, 2020, 2:50am UTC](https://discuss.elastic.co/t/ngram-tokenizer/217161/6 "2020-02-28T02:50:14Z")

</div>

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