Извлечь запись из нескольких массивов на основе фильтра

У меня есть документы в ElasticSearch со следующей структурой:

"_source": {
          "last_updated": "2017-10-25T18:33:51.434706",
          "country": "Italia",
          "price": [
            "€ 139",
            "€ 125",
            "€ 120",
            "€ 108"
          ],
          "max_occupancy": [
            2,
            2,
            1,
            1
          ],
          "type": [
            "Type 1",
            "Type 1 - (Tag)",
            "Type 2",
            "Type 2 (Tag)",
          ],
          "availability": [
            10,
            10,
            10,
            10
          ],
          "size": [
            "26 m²",
            "35 m²",
            "47 m²",
            "31 m²"
          ]
        }
      }

По сути, записи сведений разбиты на 5 массивов, а поля одной и той же записи имеют одинаковую позицию индекса в 5 массивах. Как видно из данных примера, есть 5 массивов (цена, max_occupancy, тип, доступность, размер), которые содержат значения, относящиеся к одному и тому же элементу. Я хочу извлечь элемент, у которого поле max_occupancy больше или равно 2 (если нет записи с 2, возьмите 3, если нет 3, возьмите четыре,...), с более низкой ценой, в этом случае запись и поместите результат в новый объект JSON, как показано ниже:

{
          "last_updated": "2017-10-25T18:33:51.434706",
          "country": "Italia",
          "price: ": "€ 125",
          "max_occupancy": "2",
          "type": "Type 1 - (Tag)",
          "availability": 10,
          "size": "35 m²"
}  

По сути, структура результата должна отображать извлеченную запись (в данном случае это второй индекс всего массива) и добавлять к ней общую информацию (поля: «last_updated», «country»).

Можно ли извлечь такой результат из эластичного поиска? Какой запрос мне нужно выполнить?

Может ли кто-нибудь предложить лучший подход?


person aleroot    schedule 27.10.2017    source источник


Ответы (1)


Мой лучший подход: вложиться с вложенным типом данных

За исключением упрощения запросов, легче читать и понимать связи между теми объектами, которые в настоящее время разбросаны по разным массивам.

Да, если вы выберете этот подход, вам придется отредактировать свой mapping и переиндексировать все ваши данные.

Как будет выглядеть отображение? что-то вроде этого:

{
  "mappings": {
    "properties": {
      "last_updated": {
        "type": "date"
      },
      "country": {
        "type": "string"
      },
      "records": {
        "type": "nested",
        "properties": {
          "price": {
            "type": "string"
          },
          "max_occupancy": {
            "type": "long"
          },
          "type": {
            "type": "string"
          },
          "availability": {
            "type": "long"
          },
          "size": {
            "type": "string"
          }
        }
      }
    }
  }
}

EDIT: новая структура документа (содержащая вложенные документы) -

{
  "last_updated": "2017-10-25T18:33:51.434706",
  "country": "Italia",
  "records": [
    {
      "price": "€ 139",
      "max_occupancy": 2,
      "type": "Type 1",
      "availability": 10,
      "size": "26 m²"
    },
    {
      "price": "€ 125",
      "max_occupancy": 2,
      "type": "Type 1 - (Tag)",
      "availability": 10,
      "size": "35 m²"
    },
    {
      "price": "€ 120",
      "max_occupancy": 1,
      "type": "Type 2",
      "availability": 10,
      "size": "47 m²"
    },
    {
      "price": "€ 108",
      "max_occupancy": 1,
      "type": "Type 2 (Tag)",
      "availability": 10,
      "size": "31 m²"
    }
  ]
}

Теперь проще запросить любое конкретное условие с помощью Вложенный запрос и Внутренние совпадения. Например:

{
  "_source": [
    "last_updated",
    "country"
  ],
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "country": "Italia"
          }
        },
        {
          "nested": {
            "path": "records",
            "query": {
              "bool": {
                "must": [
                  {
                    "range": {
                      "records.max_occupancy": {
                        "gte": 2
                      }
                    }
                  }
                ]
              }
            },
            "inner_hits": {
              "sort": {
                "records.price": "asc"
              },
              "size": 1
            }
          }
        }
      ]
    }
  }
}

Условия: Italia И max_occupancy > 2.

Внутренние совпадения: отсортировать по возрастанию цены и получить первый результат.

Надеюсь, вам будет полезно

person Eli    schedule 29.10.2017
comment
Нужно ли настраивать сопоставление перед вставкой данных в индекс? После установки сопоставления все последующие данные, вставленные в этот индекс, будут автоматически сопоставлены соответствующим образом? Есть ли способ добиться этого без отображения? - person aleroot; 30.10.2017
comment
1) Да 2) Вам нужно будет добавить документы с новой вложенной структурой Я отредактирую свой ответ с примером 3) Нет - person Eli; 30.10.2017