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


#1

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

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


(Igor Motov) #2

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


#3

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

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

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

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

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


(Igor Motov) #4

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


(system) #5

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