Оценка документов по текстовому совпадению и расстоянию до точки
У меня есть индекс ElasticSearch со списком "магазинов".
Я хотел бы позволить клиентам искать эти магазины по обоим geo_distance
(так, найдите точку и найдите магазины рядом с этим местом) и текстовое соответствие, например совпадения по названию / адресу магазина.
Я хотел бы получить результаты, которые соответствуют любому из этих двух критериев, и я хотел бы, чтобы порядок этих результатов был комбинацией обоих. Чем сильнее текстовое соответствие и чем ближе к искомой точке, тем выше результат. (Очевидно, что будет формула для объединения этих двух, которую нужно будет подправить, пока не слишком переживая за эту часть).
Моя проблема / что я пробовал:
geo_distance
этоfilter
неquery
поэтому я не могу объединить оба наquery
часть запроса.Я могу использовать
bool => should
фильтр (а не запрос), который соответствует либо имени, либо местоположению. Это дает мне результаты, которые я хочу, но не в порядке.Я также могу иметь
_geo_distance
как частьsort
пункт, так что документы ближе к точке ранга выше.
Что я не понял, так это то, как я бы взял "обычный" _score
что ElasticSearch дает документам при выполнении текстовых сопоставлений, и объединяет это с geo_distance
Гол.
Наличие текстового соответствия в фильтре не влияет на оценку документов (что имеет смысл). И я не вижу, как я мог бы объединить текстовое совпадение в query
часть и geo_distance filter
так что это OR
а не AND
,
Я думаю, что моя лучшая ставка будет эквивалентна этому:
{
function_score: {
query: { ... },
functions: [
{ geo_distance function },
{ multi_match_result score },
],
score_mode: 'multiply'
}
}
но я не уверен, что вы можете сделать geo_distance
как функция оценки, и я не знаю, как иметь multi_match_result score
в качестве функции оценки, или, если это вообще возможно.
Любые указатели будут с благодарностью.
Я работаю с ElasticSearch v1.4, но я могу обновить при необходимости.
1 ответ
но я не уверен, что вы можете использовать geo_distance в качестве функции оценки, и я не знаю, как получить оценку multi_match_result в качестве функции оценки или, если это вообще возможно.
Вы не можете сделать это так, как вы просите, но вы можете делать то, что хотите, так же легко. В более простом случае вы получаете оценку, просто используя обычный запрос.
Проблема с фильтрами в том, что это вопросы типа да / нет, поэтому, если вы используете их в function_score
, то это либо увеличивает счет, либо нет. То, что вы, вероятно, хотите, это ухудшение оценки по мере увеличения расстояния от источника. Это природа да / нет, которая не дает им вообще повлиять на результат. Совпадение фильтра не приводит к улучшению релевантности - это просто означает, что это часть ответа, но нет смысла говорить, что в результате он должен быть ближе к верху / низу.
Именно здесь помогает оценка функции затухания. Работает с числами, date
с, и - самое полезное здесь - geo_point
s. В дополнение к типам данных, которые он принимает, он может распадаться с использованием гауссовых, экспоненциальных или линейных функций распада. Тот, который вы хотите выбрать, является честно произвольным, и вы должны дать тот, который выбирает лучший "опыт". Я бы предложил начать с gauss
,
"function_score": {
"functions": [
"gauss": {
"my_geo_point_field": {
"origin": "0, 1",
"scale": "5km",
"offset": "500m",
"decay": 0.5
}
}
]
}
Обратите внимание, что origin
в x, y
формат (из-за стандартного GeoJSON), который longitude, latitude
,
Каждое из значений влияет на то, как оценка уменьшается на основе графика (взяты оптом из документации). Если бы вы использовали смещение 0
, затем счет начинает падать, как только он не совсем в начале координат. Со смещением это позволяет считать некоторый буфер таким же хорошим.
scale
напрямую связан с decay
в том, что счет будет срублен decay
ценность, как только она scale
-дистанция от origin
(+/- offset
). В моем примере выше, ничего 5km
от origin
получит половину счета как что-либо на origin
,
Опять же, просто обратите внимание, что различные типы функций затухания меняют форму оценки.
Я бы хотел, чтобы порядок этих результатов был комбинацией обоих.
Это цель bool
/ should
сложный запрос. Вы получаете ИЛИ поведение с улучшением оценки на основе каждого матча. В сочетании с вышесказанным, вы бы хотели что-то вроде:
{
"query": {
"bool": {
"should": [
{
"multi_match": { ... }
},
{
"function_score": {
"functions": [
"gauss": {
"my_geo_point_field": {
"origin": "0, 1",
"scale": "5km",
"offset": "500m",
"decay": 0.5
}
}
]
}
}
]
}
}
}
ПРИМЕЧАНИЕ. Если добавить must
тогда should
поведение изменяется от буквального OR-подобного поведения (по крайней мере, 1 должно совпадать) до полностью необязательного поведения (ни одно не должно совпадать).
Я работаю с ElasticSearch v1.4, но я могу обновить при необходимости.
Начиная с Elasticsearch 2.0, каждый фильтр является запросом, и каждый запрос также является фильтром. Единственная разница - это контекст, в котором он используется. Это не меняет моего ответа здесь, но это то, что может помочь вам в будущем в дополнение к тому, что я скажу дальше.
Производительность, связанная с гео, значительно возросла в ES 2.2+. Вы должны обновить (и воссоздать ваши гео-связанные индексы), чтобы воспользоваться этими изменениями. ES 5.0 будет иметь аналогичные преимущества!