# Нечеткий поиск с учетом минимального процента совпадений

**URL:** <https://discuss.elastic.co/t/topic/133519>\
**Category:** Вопросы на русском языке\
**Created:** [May 28, 2018, 10:54am UTC](https://discuss.elastic.co/t/topic/133519 "2018-05-28T10:54:56Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![IvanTushin](https://avatars.discourse-cdn.com/v4/letter/i/dbc845/32.png) [@IvanTushin](https://discuss.elastic.co/u/IvanTushin)\
**Post date:** [May 28, 2018, 10:54am UTC](https://discuss.elastic.co/t/topic/133519/1 "2018-05-28T10:54:56Z")

</div>

Добрый день! В своей работе мне приходится делать сравнение строк на основе триграмм, таким образом при сравнении двух строк я могу получить коэффициент схожести строк.

Могу ли я как-нибудь в Elasticsearch составить запрос, так что бы указать "найди мне документы где содержится такая строка и с минимальным совпадением по триграммам равным 90%"?

На данный момент я составил индекс с использованием nGram фильтра:

```auto
{
  "mappings": {
    "organization": {
      "_all": {
        "enabled": false
      },
      "dynamic": "strict",

      "properties": {
        "id": {
          "type": "integer"
        },

        "requisites": {
          "type": "nested",
          "dynamic": "strict",
          "properties": {
            "fullName": {
              "type": "text",
              "analyzer": "russian",
              "fields": {
                "ngramText": {
                  "type": "text",
                  "analyzer": "russian_ngram"
                }
              }
            },
            "shortName": {
              "type": "text",
              "analyzer": "russian",
              "fields": {
                "ngramText": {
                  "type": "text",
                  "analyzer": "russian_ngram"
                }
              }
            },
            "inn": {
              "type": "keyword",
              "index": "not_analyzed"
            },
            "kpp": {
              "type": "keyword",
              "index": "not_analyzed"
            },
            "ogrn": {
              "type": "keyword",
              "index": "not_analyzed"
            },
            "region": {
              "type": "keyword",
              "index": "not_analyzed"
            },
            "address": {
              "type": "string",
              "position_increment_gap": 0
            },

            "opfCode": {
              "type": "keyword",
              "index": "not_analyzed"
            },
            "opfName": {
              "type": "string",
              "index": "no"
            }
          }
        }
      }
    }
  },

  "settings": {
    "number_of_shards": 6,
    "number_of_replicas": 0,
    "index.refresh_interval": "5s",
    "index.mapper.dynamic": false,
    "analysis": {
      "filter": {
        "ru_stop": {
          "type": "stop",
          "stopwords": "а,бы,был,была,были,было,быть,вам,вас,весь,вот,все,всего,всех,вы,где,да,даже,его,ее,если,есть,еще,же,здесь,и,или,им,их,как,когда,кто,ли,мне,может,мы,надо,наш,него,нее,нет,ни,них,но,ну,однако,он,она,они,оно,очень,так,также,такой,там,те,тем,того,тоже,той,только,том,ты,уже,хотя,чего,чей,чем,что,чтобы,чье,чья,эта,эти,это,я"
        },
        "ngram_filter": {
          "type": "nGram",
          "min_gram": 3,
          "max_gram": 3
        }
      },
      "char_filter": {
        "dot_split": {
          "pattern": "\\.",
          "type": "pattern_replace",
          "replacement": " "
        },
        "replace_e": {
          "type": "mapping",
          "mappings": [
            "ё => е"
          ]
        }
      },

      "analyzer": {
        "russian": {
          "filter": [
            "lowercase",
            "ru_stop"
          ],
          "char_filter": [
            "html_strip",
            "dot_split",
            "replace_e"
          ],
          "tokenizer": "standard"
        },
        "russian_ngram": {
          "filter": [
            "lowercase",
            "ngram_filter"
          ],
          "char_filter": [
            "dot_split",
            "replace_e"
          ],
          "tokenizer": "standard"
        }
      }
    }
  }
}

```

У меня, конечно, есть вариант разбить строку на термы(триграммы) и поместить их в should с minimum\_should\_match = 90%, но возможно, есть метод более элегантный?

---

<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:** [May 29, 2018, 1:36pm UTC](https://discuss.elastic.co/t/topic/133519/2 "2018-05-29T13:36:01Z")

</div>

Строка и с минимальным совпадением по триграммам равным 90%?

---

<div class="post-metadata">

**Author:** ![IvanTushin](https://avatars.discourse-cdn.com/v4/letter/i/dbc845/32.png) [@IvanTushin](https://discuss.elastic.co/u/IvanTushin)\
**Post date:** [May 29, 2018, 6:02pm UTC](https://discuss.elastic.co/t/topic/133519/3 "2018-05-29T18:02:06Z")

</div>

Да, например, у меня на входе есть строка с ошибкой "продуакты", в индексе есть документ содержащий значение без ошибки "продукты".  
Мне нужно представить входную строку в виде триграмм:

1. про
2. род
3. оду
4. дуа
5. уак
6. акт
7. кты

Теперь, я хочу найти все документы в которых встречаются значения похожие на входную строку "продуакты", причем что бы они были схожи более чем на 90%.  
Для этого я панирую сделать примерно так:

```
{
"query": {
    "bool": {
        "should": [
            {
                "term": {
                    "ngramField": "про"
                }
            },
            {
                "term": {
                    "ngramField": "род"
                }
            },
            {...},
            {
                "term": {
                    "ngramField": "кты"
                }
            }
        ],
        "minimum_should_match":"90%"
    }
  }
}

```

Таким образом я найду все документы похожие на заданную строку с указанным допущением в 10%. Fuzzy Query мне не подходит потому, что иногда в строке могут отсутствуют целые слова или наоборот, присутствует мусор.

---

<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:** [May 29, 2018, 6:41pm UTC](https://discuss.elastic.co/t/topic/133519/4 "2018-05-29T18:41:50Z")

</div>

> [@IvanTushin](#):
>
> Fuzzy Query мне не подходит потому, что иногда в строке могут отсутствуют целые слова или наоборот, присутствует мусор.

Ну так, если на слова разбить, то отсутствие слов проблемой не будет.

---

<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:** [June 26, 2018, 6:41pm UTC](https://discuss.elastic.co/t/topic/133519/5 "2018-06-26T18:41:53Z")

</div>

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