Оценка документов по текстовому совпадению и расстоянию до точки

У меня есть индекс 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_points. В дополнение к типам данных, которые он принимает, он может распадаться с использованием гауссовых, экспоненциальных или линейных функций распада. Тот, который вы хотите выбрать, является честно произвольным, и вы должны дать тот, который выбирает лучший "опыт". Я бы предложил начать с 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 будет иметь аналогичные преимущества!

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