Как интерпретировать поисковый запрос пользователя (в 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 возможностей анализа текста!