Поиск общих значений поля массива двух документов в ElasticSearch

#elasticsearch

#elasticsearch

Вопрос:

У меня есть два документа в эластичном поиске со следующими значениями

 uid  preferences
1    [10,20,30,40,50,60,70,80,100]
2    [20,70,30,100,1000,77,45]
 

Есть ли какой-либо способ, которым мы можем выполнить пересечение массива по предпочтениям для этих двух записей и получить результат [20,70,30,100] ? В настоящее время мы отправляем эти две записи на сервер приложений и выполняем intersect , но хотели проверить, есть ли какой-либо прямой способ получения значений intersect напрямую из Elasticsearch.Спасибо.

Комментарии:

1. Пересекать значения для чего? Для группы идентификаторов документов? Или просто пара из 2, как в вашем примере?

2. Спасибо @JoeSorocin за ваш комментарий . Пара из 2, как указано в примере, в порядке.

Ответ №1:

Я бы решил это с помощью параметризованной скриптовой агрегации метрик. Вот более читаемая версия:

 {
  "size": 0,
  "query": {
    "terms": {
      "id": [
        1,
        2
      ]
    }
  },
  "aggs": {
    "preferences_intersection": {
      "scripted_metric": {
        "init_script": "state.shared_vals = [];",
        "map_script": "state.shared_vals.addAll(new ArrayList(doc['preferences']));",
        "combine_script": """
          return state.shared_vals.stream()
                                  .filter(i -> Collections.frequency(state.shared_vals, i) >= params.compared_docs_count)
                                  .sorted((o1, o2) -> o1.compareTo(o2))
                                  .collect(Collectors.toCollection(TreeSet::new))
        """,
        "reduce_script": "return states[0]",
        "params": {
          "compared_docs_count": 2
        }
      }
    }
  }
}
 

Обратите внимание, как terms был применен запрос, params.compared_docs_count чтобы мы могли проверить количество вхождений общих значений.

Вот компактная версия запроса без тройных кавычек:

 {"size":0,"query":{"terms":{"id":[1,2]}},"aggs":{"preferences_intersection":{"scripted_metric":{"init_script":"state.shared_vals = [];","map_script":"state.shared_vals.addAll(new ArrayList(doc['preferences']));","combine_script":"          return state.shared_vals.stream()n                                  .filter(i -> Collections.frequency(state.shared_vals, i) >= params.compared_docs_count)n                                  .sorted((o1, o2) -> o1.compareTo(o2))n                                  .collect(Collectors.toCollection(TreeSet::new))","reduce_script":"return states[0]","params":{"compared_docs_count":2}}}}}
 

Комментарии:

1. Спасибо @JoeSorocin за ваш ответ. Поскольку это основанное на сценарии мышление о проблемах с производительностью. Удачи вашему «Руководству по Elasticsearch»

2. Спасибо! Да, сценарии, как правило, работают медленно, но в этом мы просматриваем только 2 документа благодаря terms запросу, поэтому я бы не стал беспокоиться об этом.