# Не корректно работает поиск с использованием Edge n-gram token filter

**URL:** <https://discuss.elastic.co/t/edge-n-gram-token-filter/226531>\
**Category:** Вопросы на русском языке\
**Created:** [April 4, 2020, 6:15pm UTC](https://discuss.elastic.co/t/edge-n-gram-token-filter/226531 "2020-04-04T18:15:58Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![111311](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/111311/32/65668_2.png) [@111311](https://discuss.elastic.co/u/111311)\
**Post date:** [April 4, 2020, 6:15pm UTC](https://discuss.elastic.co/t/edge-n-gram-token-filter/226531/1 "2020-04-04T18:15:58Z")

</div>

Здравствуйте, нужна помощь в корректировке настроек поиска. Вкратце опишу проблему.

Когда мы забиваем в поиск слово например "Приора" то помимо реальных документов где встречается слово приора вылетают такие документы где встречается слова типа "привода", "приготовления", "пример" и тд.

Сейчас настроен edge\_ngran таким образом, что режет слово на куски в диапазное от 3 - 4 вхождений, например - "при", "прио", "приор" и вот где встречается один из кусков, возвращаются результаты.

Мне кажется надо задать в параметрах количество вхождений кусков слова хотябы 2 или 3. То есть если в слове есть "при", "прио" и "приор" то слово проходит, иначе отсеивается. Таким образом отсеются всякие "прицепы" "примеры" и др.

Но я пока не разобрался как это сделать. Возможно я ошибаюсь и решается это иначе, короче говоря нужна помощь, если кто вкурсе как это делается, помогите пожалуйста буду очень благодарен 🙂  
Я использую php клиент для работы с elasticsearch  
Конфиг:

```
        $this->client->indices()->create([
        'index' => 'posts',
        'body' => [
            'mappings' => [
                'properties' => [
                    'id' => [
                        'type' => 'integer',
                    ],
                    'published_at' => [
                        'type' => 'date',
                    ],
                    'name' => [
                        'type' => 'text',
                    ]
                ],
            ],
            'settings' => [
                'analysis' => [
                    'char_filter' => [
                        'replace' => [
                            'type' => 'mapping',
                            'mappings' => [
                                '&=> and '
                            ],
                        ],
                    ],
                    'filter' => [
                        'word_delimiter' => [
                            'type' => 'word_delimiter',
                            'split_on_numerics' => false,
                            'split_on_case_change' => true,
                            'generate_word_parts' => true,
                            'generate_number_parts' => true,
                            'catenate_all' => true,
                            'catenate_numbers' => true,
                        ],
                        'trigrams' => [
                            'type' => 'edge_ngram',
                            'min_gram' => 3,
                            'max_gram' => 4,
                        ],
                    ],
                    'analyzer' => [
                        'default' => [
                            'type' => 'custom',
                            'char_filter' => [
                                'html_strip',
                                'replace',
                            ],
                            'tokenizer' => 'whitespace',
                            'filter' => [
                                'lowercase',
                                'word_delimiter',
                                'trigrams',
                            ],
                        ],
                    ],
                ],
            ],
        ],
    ]);

```

Запрос:

```
$this->client->search([
        'index' => 'posts',
        'body' => [
            'bool' => [
                'match' => [
                    [
                        'multi_match' => [
                            'query' => $value
                            'fields' => ['name'],
                            'operator' => 'and',
                        ],
                    ]
                ],
            ],
            'size' => 1000,
            'highlight' => [
                'fields' => [
                    'name' => new \stdClass()
                ],

                'number_of_fragments' => 0
            ]
        ]
    ])
```

---

<div class="post-metadata">

**Author:** ![111311](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/111311/32/65668_2.png) [@111311](https://discuss.elastic.co/u/111311)\
**Post date:** [April 6, 2020, 6:43am UTC](https://discuss.elastic.co/t/edge-n-gram-token-filter/226531/2 "2020-04-06T06:43:19Z")

</div>

После некоторого времени работы с elasticsearch, немного удалось подкрутить поиск под нужды, но все равно остались вопросы.  
`Маппинг:`

```
"mappings": {
        "properties": {
            "id": {
                "type": "integer"
            },
            "name": {
                "type": "text",
                "analyzer": "app_analyzer"
            },
            "info": {
                "type": "text",
                "analyzer": "app_analyzer"
            }
        }
    }

```

`Настройки:`

```
"settings": {
        "analysis": {
            "analyzer": {
                "app_analyzer": {
                    "type": "custom",
                    "tokenizer": "standard",
                    "filter": [
                        "stopwords",
                        "asciifolding",
                        "lowercase",
                        "snowball"
                    ]
                }
            },
            "filter" : {
                "snowball": {
                    "type": "snowball",
                    "language": "Russian"
                },
                "stopwords": {
                    "type": "stop",
                    "stopwords": "_russian_",
                    "ignore_case": true
                },
                "app_ngram": {
                    "type": "nGram",
                    "min_gram": 5,
                    "max_gram": 7
                }
            },
            "tokenizer": {
                "nGram": {
                    "type": "nGram",
                    "min_gram": 5,
                    "max_gram": 7
                }
            }
        }
    }

```

`Запрос:`

```
"query": {
        "bool": {
            "must": {
                "multi_match": {
                    "query": "Автомобиль камри",
                    "fields": ["name^5", "lot_info^2"],
                    "operator": "or"
                }
            }
        }
    }

```

Сейчас по слову ищет прекрасно, но если задать часть слова то соответственно ничего не находит. Если в `filter` добавить `app_ngram`, или в качестве `tokenizer` выбрать `nGram` то в таком случае выдача получается не корректной, помимо нужных вариантов попадает много лишнего, например: "автомат", "автоматизация" и тд.

Так же если в названии записи значится "Автомобиль тойота камри" и мы будем искать с `operator` `and` и `tokenizer` `nGram` то в выдачу эти записи не попадают.

Если же выбрать `tokenizer` `standard` то все работает как надо, только не ищет подстроку. Например если нам нужно найти запись в которой упоминается `Сервер` и мы введем `серве` то в выдачу ничего не попадет.

Подскажите можно как-то улучшить этот поиск чтобы получать нужные результаты?

---

<div class="post-metadata">

**Author:** ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)\
**Post date:** [April 6, 2020, 1:48pm UTC](https://discuss.elastic.co/t/edge-n-gram-token-filter/226531/3 "2020-04-06T13:48:23Z")

</div>

Вы не пробовали [задать 2 анализатора](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-analyzer.html) - один на поиск без ngram, а другой для индексации - точно такой-же но с ngram?

---

<div class="post-metadata">

**Author:** ![111311](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/111311/32/65668_2.png) [@111311](https://discuss.elastic.co/u/111311)\
**Post date:** [April 6, 2020, 3:02pm UTC](https://discuss.elastic.co/t/edge-n-gram-token-filter/226531/4 "2020-04-06T15:02:50Z")

</div>

Наверное не правильно вас понял, или что-то сделал не так.  
Вот что вышло

`маппинг :`

```
"mappings": {
    "properties": {
        "id": {
            "type": "integer"
        },
        "name": {
            "type": "text",
            "analyzer": "app_analyzer",
            "search_analyzer": "app_search_analyzer"
        },
        "lot_info": {
            "type": "text",
            "analyzer": "app_analyzer"
            "search_analyzer": "app_search_analyzer"
        }
    }
}

```

`настройки:`

```
"settings": {
    "analysis": {
        "analyzer": {
            "app_analyzer": {
                "type": "custom",
                "tokenizer": "standard",
                "filter": [
                    "stopwords",
                    "asciifolding",
                    "lowercase",
                    "snowball",
                    "app_ngram"
                ]
            },
            "app_search_analyzer": {
                "type": "custom",
                "tokenizer": "standard",
                "filter": [
                    "stopwords",
                    "asciifolding",
                    "lowercase",
                    "snowball"
                ]
            }
        },
        "filter" : {
            "snowball": {
                "type": "snowball",
                "language": "Russian"
            },
            "stopwords": {
                "type": "stop",
                "stopwords": "_russian_",
                "ignore_case": true
            },
            "app_ngram": {
                "type": "nGram",
                "min_gram": 5,
                "max_gram": 7
            }
        },
        "tokenizer": {
            "nGram": {
                "type": "nGram",
                "min_gram": 5,
                "max_gram": 7
            }
        }
    }
}

```

Запрос тот же. Так вот при таком раскладе вообще пустая поисковая выдача. Точней даже не то что пустая, работает иначе и как-то не предсказуемо. Например по предыдущему запросу `Автомобиль камри` ничего не находит, но если ввести `авто` то находится все где есть вхождения `авто`.

---

<div class="post-metadata">

**Author:** ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)\
**Post date:** [April 6, 2020, 3:34pm UTC](https://discuss.elastic.co/t/edge-n-gram-token-filter/226531/5 "2020-04-06T15:34:12Z")

</div>

А если так?

```auto
DELETE test

PUT test
{
  "mappings": {
    "properties": {
      "id": {
        "type": "integer"
      },
      "name": {
        "type": "text",
        "analyzer": "snowball_analyzer",
        "fields": {
          "ngram": {
            "type": "text",
            "analyzer": "ngram_index_analyzer",
            "search_analyzer": "ngram_search_analyzer"
          }
        }
      },
      "lot_info": {
        "type": "text",
        "analyzer": "snowball_analyzer",
        "fields": {
          "ngram": {
            "type": "text",
            "analyzer": "ngram_index_analyzer",
            "search_analyzer": "ngram_search_analyzer"
          }
        }
      }
    }
  },
  "settings": {
    "analysis": {
      "analyzer": {
        "ngram_index_analyzer": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": [
            "stopwords",
            "asciifolding",
            "lowercase",
            "app_ngram"
          ]
        },
        "ngram_search_analyzer": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": [
            "asciifolding",
            "lowercase",
            "stopwords"
          ]
        },
        "snowball_analyzer": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": [
            "asciifolding",
            "lowercase",
            "stopwords",
            "snowball"
          ]
        }
      },
      "filter": {
        "snowball": {
          "type": "snowball",
          "language": "Russian"
        },
        "stopwords": {
          "type": "stop",
          "stopwords": "_russian_"
        },
        "app_ngram": {
          "type": "ngram",
          "min_gram": 4,
          "max_gram": 4
        }
      }
    }
  }
}

POST test/_bulk?refresh
{ "index": {"_id": "1" } }
{ "name": "Автомобиль тойота камри" }

GET test/_search
{
  "query": {
    "bool": {
      "must": {
        "multi_match": {
          "query": "Автомобиль камри",
          "fields": [
            "name^5",
            "lot_info^2",
            "name.ngram^3",
            "lot_info.ngram"
          ],
          "operator": "or"
        }
      }
    }
  }
}

```

---

<div class="post-metadata">

**Author:** ![111311](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/111311/32/65668_2.png) [@111311](https://discuss.elastic.co/u/111311)\
**Post date:** [April 6, 2020, 4:17pm UTC](https://discuss.elastic.co/t/edge-n-gram-token-filter/226531/6 "2020-04-06T16:17:43Z")

</div>

Да супер, действительно стало лучше, спасибо большое за помощь. Поиск стал действительно умнее, но пока два момент еще выплыло.

Первый связанный с highlights подсветкой искомых слов, а именно если ввести `авто` то не подсвечиваются в найденных элементах, если только это не отдельное слово. Например слово `авто` подсвечивается а вот в слове `авто`мобиль, не подсвечивается. Реально ли как-то повлиять на это?

`Параметры подсветки для запроса`

```
"body": {
        "highlight" : {
            "fields" : {
                "name": {}
            },
            "number_of_fragments": 0
        }
    }

```

Второй момент это например, если мы вводим `автомобиль` то все прекрасно отрабатывает, но если ввести например `автомобил`, или `автомоби` то возвращается пустая поиcковая выдача. Но если сократить до `автом` то находится искомое. Я так понимаю тут надо играться с nGram ?

---

<div class="post-metadata">

**Author:** ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)\
**Post date:** [April 6, 2020, 4:35pm UTC](https://discuss.elastic.co/t/edge-n-gram-token-filter/226531/7 "2020-04-06T16:35:51Z")

</div>

```auto
  "highlight": {
    "fields": {
      "name": {},
      "name.ngram": {}
    },
    "number_of_fragments": 0
  }

```

---

<div class="post-metadata">

**Author:** ![111311](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/111311/32/65668_2.png) [@111311](https://discuss.elastic.co/u/111311)\
**Post date:** [April 6, 2020, 5:33pm UTC](https://discuss.elastic.co/t/edge-n-gram-token-filter/226531/8 "2020-04-06T17:33:31Z")

</div>

К сожалению почему-то не всегда срабатывает. Например если набрать `серв` то находит сервер, но не подсвечивает. А если набрать `районны`, то находит к примеру `районный` и его подсвечивает. Ну думаю с этим жить можно, спасибо большое за помощь. Еще у меня вопрос по датам, но это я уже в другой раз наверное.

Так же поделюсь впечатлением, я доволен elasticsearch, это очень крутой продукт, жалею только о том, что не начал его юзать раньше 🙂

---

<div class="post-metadata">

**Author:** ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)\
**Post date:** [April 6, 2020, 6:21pm UTC](https://discuss.elastic.co/t/edge-n-gram-token-filter/226531/9 "2020-04-06T18:21:55Z")

</div>

Вы какой версией пользуетесь?

```auto
POST test/_bulk?refresh
{ "index": {"_id": "1" } }
{ "name": "Автомобиль тойота камри" }
{ "index": {"_id": "2" } }
{ "name": "Мой крутой сервер" }

GET test/_search
{
  "query": {
    "bool": {
      "must": {
        "multi_match": {
          "query": "крут серв",
          "fields": [
            "name^5",
            "lot_info^2",
            "name.ngram^3",
            "lot_info.ngram"
          ],
          "operator": "or"
        }
      }
    }
  },
  "highlight": {
    "fields": {
      "name": {},
      "name.ngram": {}
    },
    "number_of_fragments": 0
  }
}

```

У меня все подсвечивает:

```auto
{
  "took" : 6,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 6.0996957,
    "hits" : [
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 6.0996957,
        "_source" : {
          "name" : "Мой крутой сервер"
        },
        "highlight" : {
          "name" : [
            "Мой <em>крутой</em> сервер"
          ],
          "name.ngram" : [
            "Мой <em>крутой</em> <em>сервер</em>"
          ]
        }
      }
    ]
  }
}

```

---

<div class="post-metadata">

**Author:** ![111311](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/111311/32/65668_2.png) [@111311](https://discuss.elastic.co/u/111311)\
**Post date:** [April 6, 2020, 7:01pm UTC](https://discuss.elastic.co/t/edge-n-gram-token-filter/226531/10 "2020-04-06T19:01:35Z")

</div>

Сори мой косяк, не учел тот момент, что подсвеченные элементы могут лежать как в `name` так и в `name.ngram`. Все ок, спасибо за помощь 🙂 Думаю тему можно закрывать, вопрос решен.

---

<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:** [May 4, 2020, 7:01pm UTC](https://discuss.elastic.co/t/edge-n-gram-token-filter/226531/11 "2020-05-04T19:01:39Z")

</div>

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