Получение пропущенного значения в Elasticsearch

Я ищу запрос, который вернет значение, отсутствующее в документах из заданного списка значений. Например, в документах есть поле страны со значениями США, Дубай, Сингапур, Япония. Теперь я хочу сказать эластичному поиску, что я даю вам список стран (США, Дубай, Россия), вы даете мне вывод, который говорит, что Россия не является частью какого-либо документа. Это возможно?


person vinay    schedule 05.11.2020    source источник


Ответы (1)


Вам нужно выполнить запрос, подобный приведенному ниже, который будет выбирать только документы с США, Дубаем и Россией, а затем агрегировать значения country.

{
  "size": 0,
  "query": {
    "terms": {
      "country": [
        "USA",
        "Dubai",
        "Russia"
      ]
    }
  },
  "aggs": {
    "countries": {
      "terms": {
        "field": "country"
      }
    }
  }
}

В результате вы получите сегменты для всех присутствующих стран (например, США и Дубай) и не получите сегменты для России.

Затем вы можете выполнить простую арифметику набора, вычитая входной массив с тем, который вы получили из результатов агрегации, и вы найдете то, что вам нужно, то есть:

[USA, Dubai, Russia] - [USA, Dubai] = [Russia]

ОБНОВЛЕНИЕ. Если вы хотите сделать все вышеперечисленное в одной стране, вы можете использовать scripted_metric агрегация.

map_script будет выполняться для каждого документа в сегменте и сохранять все существующие страны во временной переменной state.countries.

reduce_script собирается работать на координирующем узле и получает результаты всех осколков. Этот скрипт просто сравнивает, какие страны в массиве params.countries присутствуют, и выводит только страны, которых нет.

POST country/_search
{
  "size": 0,
  "query": {
    "terms": {
      "country": [
        "USA",
        "Dubai",
        "Russia"
      ]
    }
  },
  "aggs": {
    "missing_countries": {
      "scripted_metric": {
        "init_script": "state.countries = [:]",
        "map_script": """
          def country = doc['country.keyword'].value;
          if (!state.countries.containsKey(country)) {
            state.countries[country] = 0;
          }
          state.countries[country]++;
        """,
        "combine_script": """
          return state.countries;
        """,
        "reduce_script": """
          // gather all present countries
          def countries = new HashSet(); 
          for (state in states) {
            countries.addAll(state.keySet());
          }
          // figure out which country in params is not present in countries
          def missing = [];
          for (country in params.countries) {
            if (!countries.contains(country)) {
              missing.add(country);
            }
          }
          return missing;
        """,
        "params": {
          "countries": ["USA", "Dubai", "Russia"]
        }
      }
    }
  }
}

В этом случае выход будет

  "aggregations" : {
    "missing_countries" : {
      "value" : [
        "Russia"
      ]
    }
  }
person Val    schedule 05.11.2020
comment
Как выполнить арифметику множества? все, что у меня есть, это только панель запросов kibana. Поэтому все, что мне нужно достичь, используя только один запрос. Извините, я новичок в мире Elasticsearch. - person vinay; 07.11.2020
comment
это дает синтаксическую ошибку в map_script: . Говорит ожидаемый ',' вместо '' - person vinay; 10.11.2020
comment
Где ты это ведешь? В Kibana Dev Tools? - person Val; 10.11.2020
comment
Если нет, вам нужно заменить """ на " и встроить скрипты в одну строку между двойными кавычками. Только Кибана понимает тройные кавычки """ - person Val; 10.11.2020
comment
Я использую редактор запросов извлечения внутри предупреждений kibana. Даже не помогает. Позвольте мне попробовать еще несколько способов. - person vinay; 10.11.2020
comment
Я не уверен, что такое редактор запросов извлечения внутри предупреждений kibana. - person Val; 10.11.2020
comment
Внутри открытого дистрибутива kibana есть панель оповещения. Где вы можете создавать мониторы и оповещения, чтобы получать уведомления о любых отклонениях. - person vinay; 10.11.2020
comment
Хорошо, тогда это определенно не тот запрос, который вы можете использовать повторно, я боюсь... В вашем вопросе действительно не упоминается этот момент - person Val; 10.11.2020