Можно добиться желаемого поведения, но это потребует некоторой настройки вашего отображения и запроса.
Чтобы сократить историю, вот рабочий запрос
Во-первых,Вот отображение:
PUT my_phrase_search
{
"mappings": {
"doc": {
"properties": {
"expected_position": {
"type": "long"
},
"my_phrase": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256,
"normalizer": "my_normalizer"
}
}
}
}
}
},
"settings": {
"index": {
"analysis": {
"normalizer": {
"my_normalizer": {
"filter": [
"lowercase"
],
"type": "custom"
}
}
}
}
}
}
Примечание. Я добавил поле expected_position
, чтобы упростить оценку результатов.
Теперь запрос:
POST my_phrase_search/doc/_search
{
"query": {
"bool": {
"should": [
{
"bool": {
"should": [
{
"prefix": {
"my_phrase.keyword": "i love dogs"
}
}
],
"_name": "prefix",
"boost": 2
}
},
{
"bool": {
"should": [
{
"match": {
"my_phrase": "i love dogs"
}
}
],
"_name": "match"
}
},
{
"bool": {
"should": [
{
"match_phrase": {
"my_phrase": "i love dogs"
}
}
],
"_name": "phrase",
"boost": 2
}
}
]
}
}
}
Thisдает следующие результаты:
[
{
"_score": 4.015718,
"_source": {
"my_phrase": "I love dogs",
"expected_position": 1
},
"matched_queries": [
"match",
"phrase",
"prefix"
]
},
{
"_score": 3.233316,
"_source": {
"my_phrase": "i love dogs and birds",
"expected_position": 2
},
"matched_queries": [
"match",
"phrase",
"prefix"
]
},
{
"_score": 1.3836111,
"_source": {
"my_phrase": "birds good but i love dogs and horses ",
"expected_position": 3
},
"matched_queries": [
"match",
"phrase"
]
},
{
"_score": 1.2333161,
"_source": {
"my_phrase": "Horses and i love dogs",
"expected_position": 4
},
"matched_queries": [
"match",
"phrase"
]
},
{
"_score": 0.8630463,
"_source": {
"my_phrase": "I love horses and dogs",
"expected_position": 5
},
"matched_queries": [
"match"
]
},
{
"_score": 0.38110584,
"_source": {
"my_phrase": "good dogs and i love horses",
"expected_position": 6
},
"matched_queries": [
"match"
]
}
]
Вы можете спросить, как это работает?Все ли эти изменения необходимы?Давайте выясним.
Что если мы просто используем поле text
и запрос match
?
Запрос match
будет выглядеть так:
POST my_phrase/doc/_search
{
"query": {
"match": {
"my_phrase": "i love dogs"
}
}
}
Это даст нам следующий порядок результатов: 5 - 1 - 3 - 2 - 4 - 6
.
Вопрос в том, почему запрос для "i love dogs"
не дал идеального совпадения, 1- I love dogs
, так какпервый результат?Почему 5 - I love horses and dogs
пришел первым?
В этом случае ответом является avgFieldLength
, который используется для вычисления показателя , он вычисляется на шард и, таким образом,может немного отличаться для разных документов.
Совершенно очевидно, что ES должен давать нам результаты, которые начинаются с нашего запроса.Как мы можем сказать ES предпочитать такие документы?
Добавление prefix
поиск по keyword
поле
Мы можем использовать prefix
запрос, объединенный с match
запрос с помощью запроса bool
(который в данном случае можно приблизительно интерпретировать как OR
), например:
POST my_phrase/doc/_search
{
"query": {
"bool": {
"should": [
{
"prefix": {
"my_phrase.keyword": "i love dogs"
}
},
{
"match": {
"my_phrase": "i love dogs"
}
}
]
}
}
}
Обратите внимание, что запрос prefix
работает только с keyword
type, так как он должен интерпретировать документ как один большой токен.
Этот запрос дает нам следующий порядок результатов: 2 - 5 - 1 - 3 - 4 - 6
.
2вскочил, но 1 нет.Почему это произошло?
Здесь вводится регистр символов: keyword
тип данных не анализируется, и, таким образом, i
или I
будут иметь значение для поиска префикса.
Как мы можем сделать keyword
без учета регистра?
Создание keyword
без учета регистра
Это достигается путем определения нормализатора в отображении:
PUT my_phrase2
{
"settings": {
"analysis": {
"normalizer": {
"my_normalizer": {
"type": "custom",
"char_filter": [],
"filter": ["lowercase"]
}
}
}
},
"mappings": {
"doc": {
"properties": {
"my_phrase": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256,
"normalizer": "my_normalizer"
}
}
}
}
}
}
}
Теперь тот же запрос даст нам следующий порядок: 1 - 2 - 5 - 3 - 4 - 6
.
Это уже довольно хорошо, но 5 - I love horses and dogs
все еще слишком высоко - выше, чем 3 - birds good but i love dogs and horses
с точным совпадением фразы.
match
запрос не заботится о порядке слов в фразе.Можем ли мы повысить документы, которые имеют правильный порядок?
Добавление match_phrase
для повышения соответствия фраз
Существует match_phrase
запрос, который поддерживает токены в оригиналепорядок.Давайте использовать его в запросе:
POST my_phrase2/doc/_search
{
"query": {
"bool": {
"should": [
{
"prefix": {
"my_phrase.keyword": "i love dogs"
}
},
{
"match_phrase": {
"my_phrase": "i love dogs"
}
},
{
"match": {
"my_phrase": "i love dogs"
}
}
]
}
}
}
Это дает нам следующий порядок: 1 - 2 - 3 - 5 - 4 - 6
.
3 выскочил!Но 5 - I love horses and dogs
все еще выше, чем 4 - Horses and i love dogs
.Похоже, что совпадение фраз должно было бы быть 4.
Запрос стал довольно сложным, давайте выясним, какие его части действительно совпадают в документах.
Добавление имен к запросам
Можно дать именам запросам, чтобы понять, какие части сложного действительно вступили в силу:
POST my_phrase2/doc/_search
{
"query": {
"bool": {
"should": [
{
"bool": {
"should": [
{
"prefix": {
"my_phrase.keyword": "i love dogs"
}
}
],
"_name": "prefix"
}
},
...
Ответ на документы, представляющие интерес, даст нам:
{
"_score": 0.8630463,
"_source": {
"my_phrase": "I love horses and dogs",
"expected_position": 5
},
"matched_queries": [
"match"
]
},
{
"_score": 0.82221067,
"_source": {
"my_phrase": "Horses and i love dogs",
"expected_position": 4
},
"matched_queries": [
"match",
"phrase"
]
},
Документ 5 не соответствует части phrase
.Похоже, колебания счета снова нас ударили.
Фразовый запрос выглядит более актуально, есть ли способ повысить его?
Наконец: увеличение запросов на фразы и префиксы
Существует способ повлиять на вычислениеОценка, говорящая ES, что некоторые части запроса более важны, называется boost .Вот как это может выглядеть:
POST my_phrase2/doc/_search
{
"query": {
"bool": {
"should": [
{
"bool": {
"should": [
{
"prefix": {
"my_phrase.keyword": "i love dogs"
}
}
],
"_name": "prefix",
"boost": 2
}
},
{
"bool": {
"should": [
{
"match": {
"my_phrase": "i love dogs"
}
}
],
"_name": "match"
}
},
{
"bool": {
"should": [
{
"match_phrase": {
"my_phrase": "i love dogs"
}
}
],
"_name": "phrase",
"boost": 2
}
}
]
}
}
}
Этот дает нам желаемый порядок результатов: 1 - 2 - 3 - 4 - 5 - 6
.
Обратите внимание, что мы также увеличили запрос prefix
, потому что мы хотелипонизьте важность match
.
Безопасен ли этот подход или предупреждение о переобучении
Хотя этот запрос выполняет свою работу, вам может потребоваться выполнить значительную проверку в реальных условиях и дальнейшую настройкучтобы обеспечить адекватные результаты поиска.
Запрос, который идеально соответствует этим 6 документам, может не соответствовать большой реальной коллекции. Пожалуйста, примите этот ответ в качестве начала для оптимизации.
Как видите, не все части запросанеобходимо: имена запросов можно легко опустить, но они помогают понять, как сопоставляется документ.
Надеюсь, это поможет!