У меня есть следующий документ сопоставлен в ES 5:
{
"appName" : {
"mappings" : {
"market_audit" : {
"properties" : {
"generation_date": {
"type": "date"},
"customers" : {
"type" : "nested",
"properties" : {
"customer_id" : {
"type" : "integer"},
[... other properties ...]
}
Несколько записей в узле «клиенты» могут иметь один и тот же customer_id, и я пытаюсь получить только записи, имеющие определенный customer_id (т. Е. «1»), вместе с «generation_date» документа верхнего уровня (только последний документ должен быть обработан).
Я смог придумать следующий запрос:
{
"query": {},
"sort": [
{ "generation_date": "desc" }
],
"size": 1,
"aggregations": {
"nested": {
"nested": {
"path": "customers"},
"aggregations": {
"filter": {
"filter": {
"match": {
"customers.customer_id": {
"query": "1"}
}
},
"aggregations": {
"tophits_agg": {
"top_hits": {}
}
}
}
}
}
}
}
Этот запрос возвращает мне интересующие меня данные, расположенные в массиве «агрегаты» (вместе с «попаданиями», которые содержат весь документ). Проблема здесь заключается в том, что используемая мной среда (пакет ElasticSearch ONGR вместе с пакетом DSL, использующий Symfony3) жалуется каждый раз, когда я пытаюсь получить доступ к фактическим данным, на которые нет доступных блоков.
Я прочитал документацию ES, но не смог придумать рабочий запрос, который добавил сегменты. Я уверен, что я что-то упустил, небольшая помощь будет более чем приветствоваться. Если у вас есть идея о том, как соответствующим образом изменить запрос, я думаю, что могу придумать код PHP для его создания.
РЕДАКТИРОВАТЬ: так как этот вопрос получил несколько просмотров и ответа нет (и я все еще застрял), я бы согласился на любой запрос, который позволяет мне получить информацию о конкретном «клиенте» (используя customer_id) из последнего сгенерированного документа (в соответствии с поле «generation_date»). Вопрос, который я дал, это то, что я смог придумать, и я уверен, что есть гораздо лучший способ сделать это. Предложения, может быть?
РЕДАКТИРОВАТЬ 2:
Вот данные, отправленные в ES:
{
"index": {
"_type": "market_data_audit_document"}
}
{
"customers": [
{
"customer_id": 1,
"colocation_name": "colo1",
"colocation_id": 26,
"device_name": "device 1",
"channels": [
{
"name": "channel1-5",
"multicast":"1.2.1.5",
"sugar_state":4,
"network_state":1
}
]
},
{
"customer_id":2,
"colocation_name":"colo2",
"colocation_id":27,
"device_name":"device 2",
"channels": [
{
"name":"channel2-5",
"multicast":"1.2.2.5",
"sugar_state":4,
"network_state":1
}
]
},
{
"customer_id":3,
"colocation_name":"colo3",
"colocation_id":28,
"device_name":"device 3",
"channels": [
{
"name":"channel3-5",
"multicast":"1.2.3.5",
"sugar_state":4,
"network_state":1
}
]
},
{
"customer_id":4,
"colocation_name":"colo4",
"colocation_id":29,
"device_name":"device 4","channels": [
{
"name":"channel4-5",
"multicast":"1.2.4.5",
"sugar_state":4,
"network_state":1
}
]
},
{
"customer_id":5,
"colocation_name":"colo5",
"colocation_id":30,
"device_name":"device 5",
"channels": [
{
"name":"channel5-5",
"multicast":"1.2.5.5",
"sugar_state":4,
"network_state":1
}
]
}
],
"generation_date":"2017-02-27T10:55:45+0100"}
К сожалению, когда я попытался отправить запрос, указанный в этом посте, я обнаружил, что агрегация не делает то, что я ожидал: она возвращает «хорошие» данные, но из ВСЕ сохраненные документы! Вот пример вывода:
{
"timed_out" : false,
"took" : 60,
"hits" : {
"total" : 2,
"hits" : [
{
"_source" : {
"customers" : [
{
"colocation_id" : 26,
"channels" : [
{
"name" : "channel1-5",
"sugar_state" : 4,
"network_state" : 1,
"multicast" : "1.2.1.5"}
],
"customer_id" : 1,
"colocation_name" : "colo1",
"device_name" : "device 1"},
{
"colocation_id" : 27,
"channels" : [
{
"multicast" : "1.2.2.5",
"network_state" : 1,
"name" : "channel2-5",
"sugar_state" : 4
}
],
"customer_id" : 2,
"device_name" : "device 2",
"colocation_name" : "colo2"},
{
"device_name" : "device 3",
"colocation_name" : "colo3",
"customer_id" : 3,
"channels" : [
{
"multicast" : "1.2.3.5",
"network_state" : 1,
"sugar_state" : 4,
"name" : "channel3-5"}
],
"colocation_id" : 28
},
{
"channels" : [
{
"sugar_state" : 4,
"name" : "channel4-5",
"multicast" : "1.2.4.5",
"network_state" : 1
}
],
"customer_id" : 4,
"colocation_id" : 29,
"colocation_name" : "colo4",
"device_name" : "device 4"},
{
"device_name" : "device 5",
"colocation_name" : "colo5",
"colocation_id" : 30,
"channels" : [
{
"sugar_state" : 4,
"name" : "channel5-5",
"multicast" : "1.2.5.5",
"network_state" : 1
}
],
"customer_id" : 5
}
],
"generation_date" : "2017-02-27T11:45:37+0100"},
"_type" : "market_data_audit_document",
"sort" : [
1488192337000
],
"_index" : "mars",
"_score" : null,
"_id" : "AVp_LPeJdrvi0cWb8CrL"}
],
"max_score" : null
},
"aggregations" : {
"nested" : {
"doc_count" : 10,
"filter" : {
"doc_count" : 2,
"tophits_agg" : {
"hits" : {
"max_score" : 1,
"total" : 2,
"hits" : [
{
"_nested" : {
"offset" : 0,
"field" : "customers"},
"_score" : 1,
"_source" : {
"channels" : [
{
"name" : "channel1-5",
"sugar_state" : 4,
"multicast" : "1.2.1.5",
"network_state" : 1
}
],
"customer_id" : 1,
"colocation_id" : 26,
"colocation_name" : "colo1",
"device_name" : "device 1"}
},
{
"_source" : {
"colocation_id" : 26,
"customer_id" : 1,
"channels" : [
{
"multicast" : "1.2.1.5",
"network_state" : 1,
"name" : "channel1-5",
"sugar_state" : 4
}
],
"device_name" : "device 1",
"colocation_name" : "colo1"},
"_nested" : {
"offset" : 0,
"field" : "customers"},
"_score" : 1
}
]
}
}
}
}
},
"_shards" : {
"total" : 13,
"successful" : 1,
"failures" : [
{
"reason" : {
"index" : ".kibana",
"index_uuid" : "bTkwoysSQ0y8Tt9yYFRStg",
"type" : "query_shard_exception",
"reason" : "No mapping found for [generation_date] in order to sort on"},
"shard" : 0,
"node" : "4ZUgOm4VRry6EtUK15UH3Q",
"index" : ".kibana"},
{
"reason" : {
"index_uuid" : "lN2mVF9bRjuDtiBF2qACfA",
"index" : "archiv1_log",
"type" : "query_shard_exception",
"reason" : "No mapping found for [generation_date] in order to sort on"},
"shard" : 0,
"node" : "4ZUgOm4VRry6EtUK15UH3Q",
"index" : "archiv1_log"},
{
"index" : "archiv1_session",
"shard" : 0,
"node" : "4ZUgOm4VRry6EtUK15UH3Q",
"reason" : {
"type" : "query_shard_exception",
"index" : "archiv1_session",
"index_uuid" : "cmMAW04YTtCb0khEqHpNyA",
"reason" : "No mapping found for [generation_date] in order to sort on"}
},
{
"shard" : 0,
"node" : "4ZUgOm4VRry6EtUK15UH3Q",
"reason" : {
"reason" : "No mapping found for [generation_date] in order to sort on",
"index" : "archiv1_users_dev",
"index_uuid" : "AH48gIf5T0CXSQaE7uvVRg",
"type" : "query_shard_exception"},
"index" : "archiv1_users_dev"}
],
"failed" : 12
}
}
Существует 2 вида скоплений:
В вашем случае у вас есть 2 Агрегации под вложенными Agg: Фильтр и Метрика.
Фильтр:
Я сомневаюсь, что ваша PHP-библиотека будет правильно обрабатывать результаты вложенного агрегирования, но вы могли бы использовать фильтрs вместо фильтров агрегации, чтобы получить список сегментов
{
"aggregations": {
"nested": {
"nested": {
"path": "customers"},
"aggregations": {
"filters_customer": {
"filters": {
"filters": [
{
"match": {
"customers.customer_id": "1"}
}
]
},
"aggregations": {
"top_hits_customer": {
"top_hits": {}
}
}
}
}
}
}
}
Обеспечит что-то вроде:
{
"aggregations": {
"nested": {
"doc_count": 15,
"filters_customer": {
"buckets": [
{
"doc_count": 3,
"top_hits_customer": {
"hits": {
"total": 3,
"max_score": 1,
"hits": [
{
"_nested": {
"field": "customers",
"offset": 0
},
"_score": 1,
"_source": {
"customer_id": 1,
"foo": "bar"}
},
{
"_nested": {
"field": "customers",
"offset": 0
},
"_score": 1,
"_source": {
"customer_id": 1,
"foo": "bar"}
},
{
"_nested": {
"field": "customers",
"offset": 0
},
"_score": 1,
"_source": {
"customer_id": 1,
"foo": "bar"}
}
]
}
}
}
]
}
}
}
}
Elasticsearch выполнит поиск по всем документам, а не по документу «TOP 1», основываясь на дате вашего отчета. Чтобы разделить результаты по отчетам, используйте группу терминов на дату отчета:
{
"query": {},
"size": 0,
"aggregations": {
"grp_report": {
"terms": {
"field": "generation_date"},
"aggregations": {
"nested_customers": {
"nested": {
"path": "customers"},
"aggregations": {
"filters_customer": {
"filters": {
"filters": [
{
"match": {
"customers.customer_id": "1"}
}
]
},
"aggregations": {
"top_hits_customer": {
"top_hits": {}
}
}
}
}
}
}
}
}
}
Избегайте сложных документов, предпочитайте разбивать отчет на небольшие документы со связанным ключом (например, reportId). Вы сможете легко фильтровать и агрегировать без вложенного документа. Добавьте в документ клиента информацию о том, что вы будете фильтровать по всем типам (избыточность не является проблемой в этом случае).
Примеры использования:
Пример текущего документа: / indexName / market_audit
{
"generation_date": "...",
"customers": [
{
"id": 1,
"foo": "bar 1"},
{
"id": 2,
"foo": "bar 2"},
{
"id": 3,
"foo": "bar 3"}
]
}
Переформатированный документ:
/ IndexName / market_audit_report
{
"report_id" : "123456""generation_date": "...",
"foo":"bar"}
/ indexName / market_audit_customer Documents
{
"report_id" : "123456""customer_id": 1,
"foo": "bar 1"}{
"report_id" : "123456""customer_id": 2,
"foo": "bar 2"}{
"report_id" : "123456""customer_id": 3,
"foo": "bar 3"}
Если вам известен идентификатор вашего отчета, вы сможете получить все свои данные за один запрос:
Или же
Не забудьте предоставить size
в ваших top_hits в противном случае вы получите только топ 3
Чтение эластичного поиска первой строки определение агрегатов Я думаю, что вы не очень хорошо понимаете, как это работает:
Структура агрегирования помогает предоставлять агрегированные данные на основе
поисковый запрос
Так как ваш запрос не имеет никакого фильтра, возврате ВСЕ сохраненные документы в hits.hits
Объекты — это ожидаемый результат.
Тогда вы используете filter
агрегация, которая поможет вам получить нужные документы, но они находятся в aggs
собственность возвращена dict
Если я прав, я бы рекомендовал вам сделать это как можно проще, поэтому вот мой угаданный вопрос
{
"query": {
"filtered": {
"filter": {
"nested": {
"path" : "customers",
"filter": {
"bool": {
"must" : [
"term": {"customer_id" : "1"}
]
}
}
}
}
}
},
"aggregations": {
"tophits_agg": {
"top_hits": {}
}
}
}