Сортировка Elasticsearch на основе элемента в массиве, который удовлетворяет фильтру - PullRequest
0 голосов
/ 04 декабря 2018

Мои типы имеют поле, которое является массивом раз в формате ISO 8601.Я хочу получить все списки, которые имеют время в определенный день, а затем упорядочить их в кратчайшие сроки, когда они появляются в этот конкретный день.Проблема в том, что мой запрос упорядочен по раннему времени all days.

Вы можете воспроизвести проблему ниже.

curl -XPUT 'localhost:9200/listings?pretty'

curl -XPOST 'localhost:9200/listings/listing/_bulk?pretty' -d '
{"index": { } }
{ "name": "second on 6th (3rd on the 5th)", "times": ["2018-12-05T12:00:00","2018-12-06T11:00:00"] }
{"index": { } }
{ "name": "third on 6th (1st on the 5th)", "times": ["2018-12-05T10:00:00","2018-12-06T12:00:00"] }
{"index": { } }
{ "name": "first on the 6th (2nd on the 5th)", "times": ["2018-12-05T11:00:00","2018-12-06T10:00:00"] }
'

# because ES takes time to add them to index 
sleep 2

echo "Query listings on the 6th!"

curl -XPOST 'localhost:9200/listings/_search?pretty' -d '
{
  "sort": {
    "times": {
      "order": "asc",
      "nested_filter": {
        "range": {
          "times": {
            "gte": "2018-12-06T00:00:00",
            "lte": "2018-12-06T23:59:59"
          }
        }
      }
    }
  },
  "query": {
    "bool": {
      "filter": {
        "range": {
          "times": {
            "gte": "2018-12-06T00:00:00",
            "lte": "2018-12-06T23:59:59"
          }
        }
      }
    }
  }
}'

curl -XDELETE 'localhost:9200/listings?pretty'

Добавление вышеуказанного скрипта в a.sh файл и его запуск помогает воспроизвести проблему.Вы увидите, что порядок происходит на основе 5-го, а не 6-го.Elasticsearch преобразует время в число epoch_millis для сортировки, вы можете увидеть номер эпохи в поле сортировки в объекте попаданий, например, 1544007600000. При выполнении сортировки по asc in принимает наименьшее число в массиве (порядок не важен) исортировки, основанные на этом.

Каким-то образом мне нужно, чтобы он был заказан в самое раннее время, которое происходит в запрашиваемый день, т.е.

В настоящее время используется Elasticsearch 2.4, но даже если кто-то может показать мне, как это делается в текущей версии, это было бы здорово.

Вот их документация по вложенным запросам и сценариям , если это поможет.

1 Ответ

0 голосов
/ 05 декабря 2018

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

Если вы преобразуете документ в тот, который использует массив вложенных объектов вместо простого массива датзатем вы можете создать вложенную фильтрованную сортировку, которая работает.

Ниже приводится Elasticsearch 6.0 - они немного изменили синтаксис для версии 6.1, и я не уверен, насколько это работает с 2.x:

Отображения:

PUT nested-listings
{
  "mappings": {
    "listing": {
      "properties": {
        "name": {
          "type": "keyword"
        },
        "openTimes": {
          "type": "nested",
          "properties": {
            "date": {
              "type": "date"
            }
          }
        }
      }
    }
  }
}

Данные:

POST nested-listings/listing/_bulk
{"index": { } }
{ "name": "second on 6th (3rd on the 5th)", "openTimes": [ { "date": "2018-12-05T12:00:00" }, { "date": "2018-12-06T11:00:00" }] }
{"index": { } }
{ "name": "third on 6th (1st on the 5th)", "openTimes": [ {"date": "2018-12-05T10:00:00"}, { "date": "2018-12-06T12:00:00" }] }
{"index": { } }
{ "name": "first on the 6th (2nd on the 5th)", "openTimes": [ {"date": "2018-12-05T11:00:00" }, { "date": "2018-12-06T10:00:00" }] }

Таким образом, вместо «nextNexpectionOpenTimes» у нас есть вложенный объект «openTimes» и каждый листингсодержит массив openTimes.

Теперь поиск:

POST nested-listings/_search
{
  "sort": {
    "openTimes.date": {
      "order": "asc",
      "nested_path": "openTimes",
      "nested_filter": {
        "range": {
          "openTimes.date": {
            "gte": "2018-12-06T00:00:00",
            "lte": "2018-12-06T23:59:59"
          }
        }
      }
    }
  },
  "query": {
    "nested": {
      "path": "openTimes",
      "query": {
        "bool": {
          "filter": {
            "range": {
              "openTimes.date": {
                "gte": "2018-12-06T00:00:00",
                "lte": "2018-12-06T23:59:59"
              }
            }
          }
        }
      }
    }
  }
}

Основным отличием здесь является немного другой запрос, так как вам нужно использовать «вложенный» запрос для фильтрации вложенных объектов..

И это дает следующий результат:

{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 3,
    "max_score": null,
    "hits": [
      {
        "_index": "nested-listings",
        "_type": "listing",
        "_id": "vHH6e2cB28sphqox2Dcm",
        "_score": null,
        "_source": {
          "name": "first on the 6th (2nd on the 5th)"
        },
        "sort": [
          1544090400000
        ]
      },
      {
        "_index": "nested-listings",
        "_type": "listing",
        "_id": "unH6e2cB28sphqox2Dcm",
        "_score": null,
        "_source": {
          "name": "second on 6th (3rd on the 5th)"
        },
        "sort": [
          1544094000000
        ]
      },
      {
        "_index": "nested-listings",
        "_type": "listing",
        "_id": "u3H6e2cB28sphqox2Dcm",
        "_score": null,
        "_source": {
          "name": "third on 6th (1st on the 5th)"
        },
        "sort": [
          1544097600000
        ]
      }
    ]
  }
}

Я не думаю, что вы действительно можете выбрать одно значение из массива в ES, поэтому для сортировки вы всегда собиралисьсортируйсяп все результаты.Лучшее, что вы можете сделать с простым массивом - это выбрать способ обработки этого массива для целей сортировки (используйте наименьшее, наибольшее, среднее и т. Д.).

...