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

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

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

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

{
  "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%, но возможно, есть метод более элегантный?

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

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

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

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

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

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

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

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