Как интерпретировать поисковый запрос пользователя (в Elasticsearch)

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

Например, пользователь ищет "красные кровати для детей 120см"

Я хотел бы интерпретировать:

Категория-фильтр "Кровати" И "Дети" Цвет-фильтр красный Размер-фильтр 120см

Есть ли готовые инструменты для эластичного поиска? Буду ли я нуждаться в НЛП перед началом поиска?

0 ответов

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

Под капотом он всегда выполняет анализ текста для полнотекстового поиска (для полей типа text). Текст анализатор состоит из символов фильтра, Tokenizer и лексемы фильтра.

Например, фильтр токенов синонимов может заменитьkids с children в пользовательском запросе.

Кроме того, поисковые запросы на современных веб-сайтах часто выполняются с помощью селекторов категорий в пользовательском интерфейсе, которые легко реализовать с помощью запросов. keyword поля Elasticsearch.

Возможно, этого будет достаточно, чтобы правильно смоделировать ваши данные и настроить их индексирование для реализации нужного вам поиска - и если этого недостаточно, вы всегда можете добавить дополнительный уровень логики, подобной NLP, на стороне клиента, как предлагается @2ps.

А теперь позвольте мне показать игрушечный пример того, чего можно достичь с помощью synonym фильтр токенов и copy_to особенность.

Определим отображение

Предположим, наша продукция обладает следующими свойствами: Category, Color, а также Size.LengthCM.

Отображение будет выглядеть примерно так:

PUT /my_index
{
    "mappings": {
        "properties": {
            "Category": {
                "type": "keyword",
                "copy_to": "DescriptionAuto"
            },
            "Color": {
                "type": "keyword",
                "copy_to": "DescriptionAuto"
            },
            "Size": {
                "properties": {
                    "LengthCM": {
                        "type": "integer",
                        "copy_to": "DescriptionAuto"
                    }
                }
            },
            "DescriptionAuto": {
                "type": "text",
                "analyzer": "MySynonymAnalyzer"
            }
        }
    },
    "settings": {
        "index": {
            "analysis": {
                "analyzer": {
                    "MySynonymAnalyzer": {
                        "tokenizer": "standard",
                        "filter": [
                            "MySynonymFilter"
                        ]
                    }
                },
                "filter": {
                    "MySynonymFilter": {
                        "type": "synonym",
                        "lenient": true,
                        "synonyms": [
                            "kid, kids => children"
                        ]
                    }
                }
            }
        }
    }
}

Обратите внимание, что мы выбрали тип keyword для полей Category а также Color.

А что насчет этих copy_to а также synonym?

Что будет copy_to делать?

Каждый раз, когда мы отправляем объект для индексации в наш индекс, значение поля ключевого слова Category будет скопировано в полнотекстовое поле DescritpionAuto. Это что copy_to делает.

Что будет synonym делать?

Включить synonym нам нужно определить собственный анализатор, см. MySynonymAnalyzer который мы определили в "settings" над.

Грубо говоря, он заменит каждый токен, который соответствует чему-то слева от => с жетоном справа.

Как будут выглядеть документы?

Вставим несколько примеров документов:

POST /my_index/_doc
{
    "Category": [
        "beds",
        "adult"
    ],
    "Color": "red",
    "Size": {
        "LengthCM": 150
    }
}

POST /my_index/_doc
{
    "Category": [
        "beds",
        "children"
    ],
    "Color": "red",
    "Size": {
        "LengthCM": 120
    }
}

POST /my_index/_doc
{
    "Category": [
        "couches",
        "adult",
        "family"
    ],
    "Color": "blue",
    "Size": {
        "LengthCM": 200
    }
}

POST /my_index/_doc
{
    "Category": [
        "couches",
        "adult",
        "family"
    ],
    "Color": "red",
    "Size": {
        "LengthCM": 200
    }
}

Как вы видете, DescriptionAuto отсутствует в исходных документах - хотя из-за copy_to мы сможем запросить его.

Посмотрим как.

Осуществляем поиск!

Теперь мы можем опробовать наш индекс с помощью простого query_string запрос:

POST /my_index/_doc/_search
{
    "query": {
        "query_string": {
            "query": "red beds for kids 120cm",
            "default_field": "DescriptionAuto"
        }
    }
}

Результаты будут выглядеть примерно так:

  "hits": {
    ...
    "max_score": 2.3611186,
    "hits": [
      {
        ...
        "_score": 2.3611186,
        "_source": {
          "Category": [
            "beds",
            "children"
          ],
          "Color": "red",
          "Size": {
            "LengthCM": 120
          }
        }
      },
      {
        ...
        "_score": 1.0998137,
        "_source": {
          "Category": [
            "beds",
            "adult"
          ],
          "Color": "red",
          "Size": {
            "LengthCM": 150
          }
        }
      },
      {
        ...
        "_score": 0.34116736,
        "_source": {
          "Category": [
            "couches",
            "adult",
            "family"
          ],
          "Color": "red",
          "Size": {
            "LengthCM": 200
          }
        }
      }
    ]
  }

Документ с категориями beds а также children и цвет redнаходится сверху. И его оценка релевантности вдвое больше, чем у его продолжения!

Как я могу проверить, как Elasticsearch интерпретировал запрос пользователя?

Это легко сделать через API-интерфейс анализа:

POST /my_index/_analyze
{
    "text": "red bed for kids 120cm",
    "analyzer": "MySynonymAnalyzer"
}

{
  "tokens": [
    {
      "token": "red",
      "start_offset": 0,
      "end_offset": 3,
      "type": "<ALPHANUM>",
      "position": 0
    },
    {
      "token": "bed",
      "start_offset": 4,
      "end_offset": 7,
      "type": "<ALPHANUM>",
      "position": 1
    },
    {
      "token": "for",
      "start_offset": 8,
      "end_offset": 11,
      "type": "<ALPHANUM>",
      "position": 2
    },
    {
      "token": "children",
      "start_offset": 12,
      "end_offset": 16,
      "type": "SYNONYM",
      "position": 3
    },
    {
      "token": "120cm",
      "start_offset": 17,
      "end_offset": 22,
      "type": "<ALPHANUM>",
      "position": 4
    }
  ]
}

Как видите, токена нет kids, но есть жетон children.

Кстати, в этом примере Elasticsearch не смог проанализировать размер кровати: token 120cm не совпал ни с чем, так как все размеры целые, например 120, 150и т. д. Потребуется еще один уровень настройки для извлечения 120 от 120cm токен.


Надеюсь, это дает представление о том, чего можно достичь с помощью встроенных в Elasticsearch возможностей анализа текста!

Другие вопросы по тегам