Multi-Term Auto Completion Elasticsearch - PullRequest
1 голос
/ 09 января 2020

Я использую Elasticsearch 7.2.0 и хочу создать предложение для поиска.

Например, у меня есть три названия фильмов:

Мстители: Бесконечная война
Мстители : Война Бесконечности, часть 2
Мстители: Эра Альтрона

Когда я набираю " aven ", должно появиться предложение вроде:

Авен Джерс
Авен Герс бесконечность
Авен Джерс возраст

Когда я набираю " Мстители инф "

Мстители инфы Война интимов
Мстители инфы Война инентов часть 2

после множества обучающих программ по упругому поиску я сделал это:

Проверка кластера

PUT movies
{
  "settings": {
    "index": {
      "analysis": {
        "filter": {},
        "analyzer": {
          "keyword_analyzer": {
            "filter": [
              "lowercase",
              "asciifolding",
              "trim"
            ],
            "char_filter": [],
            "type": "custom",
            "tokenizer": "keyword"
          },
          "edge_ngram_analyzer": {
            "filter": [
              "lowercase"
            ],
            "tokenizer": "edge_ngram_tokenizer"
          },
          "edge_ngram_search_analyzer": {
            "tokenizer": "lowercase"
          },
          "completion_analyzer": {
            "tokenizer": "keyword",
            "filter": "lowercase"
          }
        },
        "tokenizer": {
          "edge_ngram_tokenizer": {
            "type": "edge_ngram",
            "min_gram": 2,
            "max_gram": 5,
            "token_chars": [
              "letter"
            ]
          }
        }
      }
    }
  },
  "mappings": {

      "properties": {
        "name": {
          "type": "text",
          "fields": {
            "keywordstring": {
              "type": "text",
              "analyzer": "keyword_analyzer"
            },
            "edgengram": {
              "type": "text",
              "analyzer": "edge_ngram_analyzer",
              "search_analyzer": "edge_ngram_search_analyzer"
            },
            "completion": {
              "type": "completion"
            }
          },
          "analyzer": "standard"
        },
        "completion_terms": {
          "type": "text",
          "fielddata": true,
          "analyzer": "completion_analyzer"
        }
      }

  }
}

с указанием следующих документов:

POST movies/_doc/1
{
  "name": "Spider-Man: Homecoming",
  "completion_terms": [
    "spider-man",
    "homecomming"
  ]
}

POST movies/_doc/2
{
  "name": "Ant-man and the Wasp",
  "completion_terms": [
    "ant-man",
    "and",
    "the",
    "wasp"
  ]
}

POST movies/_doc/3
{
  "name": "Avengers: Infinity War Part 2",
  "completion_terms": [
    "avangers",
    "infinity",
    "war",
    "part",
    "2"
  ]
}

POST movies/_doc/4
{
  "name": "Captain Marvel",
  "completion_terms": [
    "captain",
    "marvel"
  ]
}

POST movies/_doc/5
{
  "name": "Black Panther",
  "completion_terms": [
    "black",
    "panther"
  ]
}

POST movies/_doc/6
{
  "name": "Avengers: Infinity War",
  "completion_terms": [
    "avangers",
    "infinity",
    "war"
  ]
}

POST movies/_doc/7
{
  "name": "Thor: Ragnarok",
  "completion_terms": [
    "thor",
    "ragnarok"
  ]
}

POST movies/_doc/8
{
  "name": "Guardians of the Galaxy Vol 2",
  "completion_terms": [
    "guardians",
    "of",
    "the",
    "galaxy",
    "vol",
    "2"
  ]
}

POST movies/_doc/9
{
  "name": "Doctor Strange",
  "completion_terms": [
    "doctor",
    "strange"
  ]
}

POST movies/_doc/10
{
  "name": "Captain America: Civil War",
  "completion_terms": [
    "captain",
    "america",
    "civil",
    "war"
  ]
}

POST movies/_doc/11
{
  "name": "Ant-Man",
  "completion_terms": [
    "ant-man"
  ]
}

POST movies/_doc/12
{
  "name": "Avengers: Age of Ultron",
  "completion_terms": [
    "avangers",
    "age",
    "of",
    "ultron"
  ]
}

POST movies/_doc/13
{
  "name": "Guardians of the Galaxy",
  "completion_terms": [
    "guardians",
    "of",
    "the",
    "galaxy"
  ]
}

POST movies/_doc/14
{
  "name": "Captain America: The Winter Soldier",
  "completion_terms": [
    "captain",
    "america",
    "the",
    "winter",
    "solider"
  ]
}

POST movies/_doc/15
{
  "name": "Thor: The Dark World",
  "completion_terms": [
    "thor",
    "the",
    "dark",
    "world"
  ]
}

POST movies/_doc/16
{
  "name": "Iron Man 3",
  "completion_terms": [
    "iron",
    "man",
    "3"
  ]
}

POST movies/_doc/17
{
  "name": "Marvel’s The Avengers",
  "completion_terms": [
    "marvels",
    "the",
    "avangers"
  ]
}

POST movies/_doc/18
{
  "name": "Captain America: The First Avenger",
  "completion_terms": [
    "captain",
    "america",
    "the",
    "first",
    "avanger"
  ]
}

POST movies/_doc/19
{
  "name": "Thor",
  "completion_terms": [
    "thor"
  ]
}

POST movies/_doc/20
{
  "name": "Iron Man 2",
  "completion_terms": [
    "iron",
    "man",
    "2"
  ]
}

POST movies/_doc/21
{
  "name": "The Incredible Hulk",
  "completion_terms": [
    "the",
    "incredible",
    "hulk"
  ]
}

POST movies/_doc/22
{
  "name": "Iron Man",
  "completion_terms": [
    "iron",
    "man"
  ]
}

и запроса

POST movies/_search
{
  "suggest": {
    "movie-suggest-fuzzy": {
        "prefix": "avan",
        "completion": {
          "field": "name.completion",
          "fuzzy": {
            "fuzziness": 1
          }
      }
    }
  }
}

Мой запрос возвращает полное название не штук.

1 Ответ

0 голосов
/ 13 января 2020

Это отличный вопрос, который показывает, что вы провели много исследований, чтобы заставить его работать, но вам не нужно делать его сложным (пытаясь полностью обработать его в ES), у меня был точно такой же вариант использования и решил ее, используя комбинацию прикладных логи c с ES.

Что вам действительно нужно, так это запрос соответствия по (n-1) терминам и запрос префикса по n-му поисковому запросу, как вы упомянули, в случае aven как первый и n-й термин, префиксный запрос будет на нем, а в случае avengers inf поискового термина, avengers будет на запросе на совпадение, а префикс будет на inf term.

I просто проиндексировал предоставленные вами документы и попробовал оба упомянутых условия поиска, и это работает:

Создание индекса

{
    "mappings": {
        "properties": {
            "name": {
                "type": "text"
            }
        }
    }
}

Индекс 3 документа

{
  "name" : "Avengers: Age of Ultron"
},
{
  "name" : "Avengers: Infinity War Part 2"
},
{
  "name" : "Avengers: Infinity War"
}

Поисковый запрос

{
    "query": {
        "bool": {
            "must": [
                {
                    "match": {   --> Note match queries on (n-1) terms
                        "name": "avengers"
                    }
                },
                {
                    "prefix": {  --> Prefix query on nth term
                        "name": "ag"
                    }
                }
            ]
        }
    }
}

По сути, в коде приложения необходимо разделить поисковые термины на основе пробелов, а затем построить запрос bool с предложением соответствия на (n-1) терминах и запросом префикса на T шестое слагаемое.

Обратите внимание, что вам даже не нужно использовать анализатор краев n-грамм и другие сложные вещи при индексации, что сэкономит много места в вашем индексе, но вы можете захотеть поместить ограничение на количество символов в запросе префикса, так как оно может быть дорогостоящим при поиске в миллионах документов, поскольку не соответствует токену токену, как в запросе на совпадение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...