В Elasticsearch я храню моментальные снимки состояния элемента в схеме только для добавления.Например:
POST /item/item
{
"id": "1",
"time": "2018-09-19T00:00:00Z",
status": "ON_HOLD"
}
POST /item/item
{
"id": "2",
"time": "2018-09-19T00:01:00Z",
"status": "ON_HOLD"
}
POST /item/item
{
"id": "2",
"time": "2018-09-19T00:02:00Z",
"status": "DONE"
}
Теперь я хочу ответить на следующий вопрос: какие пункты еще удерживаются? (status==ON_HOLD
).
В этом простом случае ответом будет:
{
"id": "1",
"time": "2018-09-19T00:00:00Z",
status": "ON_HOLD"
}
Итак, чтобы получить последнее состояние элемента, я использую агрегирование терминов на id
, например, так:
GET /item/_search
{
"size": 0,
"query": {
"match_all": {}
},
"aggs": {
"id": {
"terms": {
"field": "id.keyword",
"size": 10
},
"aggs": {
"top_items": {
"top_hits": {
"size": 1,
"sort": [
{
"time": {
"order": "desc"
}
}
],
"_source": {
"includes": ["*"]
}
}
}
}
}
}
}
Это дает мне последнее доступное состояние каждого элемента, идентифицируемого по его идентификатору:
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 3,
"max_score": 0,
"hits": []
},
"aggregations": {
"id": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "2",
"doc_count": 2,
"top_items": {
"hits": {
"total": 2,
"max_score": null,
"hits": [
{
"_index": "item",
"_type": "item",
"_id": "S-5eCGYBNyILygyml2jR",
"_score": null,
"_source": {
"id": "2",
"time": "2018-09-19T00:02:00Z",
"status": "DONE"
},
"sort": [
1537315320000
]
}
]
}
}
},
{
"key": "1",
"doc_count": 1,
"top_items": {
"hits": {
"total": 1,
"max_score": null,
"hits": [
{
"_index": "item",
"_type": "item",
"_id": "Se5eCGYBNyILygymjmg0",
"_score": null,
"_source": {
"id": "1",
"time": "2018-09-19T00:00:00Z",
"status": "ON_HOLD"
},
"sort": [
1537315200000
]
}
]
}
}
}
]
}
}
}
Теперь проблема в том, что я хотел бы отфильтровать результат (после агрегации) на стороне Elasticsearch (не клиента)).
Я попытался агрегировать bucket_selector
, но он жалуется, поскольку результат top_hits
не является числовым или числовым агрегированием.
Я также пытался добавить поле script_, чтобы получитьчисловое значение, но не может использовать его после:
"script_fields": {
"on_hold": {
"script": {
"lang": "painless",
"source": "doc['status.keyword'].value == 'ON_HOLD' ? 1 : 0"
}
}
}
Возможно ли то, что я хочу сделать, на стороне Elasticsearch или мне нужно делать это на стороне клиента?
PS:добавление фильтра до агрегации не дает правильного результата, так как это приведет кКоличество предметов, которые были ON_HOLD
в любой момент времени.
РЕДАКТИРОВАТЬ: Хорошо, я получаю где-то с:
GET /item/_search
{
"size": 0,
"query": {
"match_all": {}
},
"aggs": {
"id": {
"terms": {
"field": "id.keyword",
"size": 50
},
"aggs": {
"top_item": {
"terms": {
"size": 1,
"field": "time",
"order": {
"_key": "desc"
}
},
"aggs": {
"on_hold": {
"filter": {
"term": {
"status.keyword": "ON_HOLD"
}
},
"aggs": {
"document": {
"top_hits": {
"size": 1,
"_source": ["*"]
}
}
}
}
}
}
}
}
}
}
Агрегация top_hits является метрикой, а не агрегации корзины,поэтому он не выполняет свою работу и должен использоваться последним.
Еще одна проблема: отфильтрованные корзины оставляют пустые листья: "хиты": []
Есть ли способ удалить такиеветви, оканчивающиеся пустыми листьями из результирующего дерева?Спасибо