Агрегации с динамическими данными / вложенными_объектами
Я пытаюсь выполнить агрегирование по динамически сопоставленным полям в ElasticSearch.
Например:
POST test/_doc/1
{
"settings": {
"range": {
"value": 200,
"display": "200 km"
},
"transmitter": {
"value": 1.2,
"display": "1.2 Ghz"
}
}
}
Недвижимость под settings
динамичны. По сути, мне нужен такой запрос:
{
"size": 0,
"query": {
"match_all": {}
},
"aggs": {
"settings": {
"terms": {
"field": "settings.*.display"
}
}
}
}
поскольку *
здесь не работает, мне интересно, есть ли способ вернуть поля из безболезненного скрипта, а затем, возможно, использовать агрегирование конвейера? Я не могу найти безболезненного эквивалентаObject.keys(settings)
в JavaScript.
Я видел подход с вложенными объектами, но я бы хотел избежать этого, поскольку может быть много свойств настроек, а ограничение по умолчанию - 50, по сравнению с nested_objects с 10000 свойствами.
1 ответ
Безболезненный эквивалент Object.keys()
является .keySet()
. Вы можете реализовать следующую итеративную логику в агрегации метрик со сценарием:
GET test/_search
{
"size": 0,
"aggs": {
"dynamic_fields_agg": {
"scripted_metric": {
"init_script": "state.map = [:];",
"map_script": """
def source = params._source['settings'];
for (def key : source.keySet()) {
if (source[key].containsKey("display")) {
if (state.map.containsKey(key)) {
state.map[key].add(source[key].display);
} else {
state.map[key] = [source[key].display];
}
}
}
""",
"combine_script": "return state",
"reduce_script": "return states"
}
}
}
}
что даст что-то вроде
{
"aggregations":{
"dynamic_fields_agg":{
"value":[
{
"map":{
"range":[
"200 km"
],
"transmitter":[
"1.2 Ghz"
]
}
}
]
}
}
}
Теперь вы можете постобработать значения в скриптах уменьшения / объединения, как вам нравится.
Использование вложенных полей здесь не принесет вам особого преимущества - пути с подстановочными знаками также не допускаются. Я сам спросил об этом некоторое время назад.
ОБНОВЛЕНИЕ - встроенная версия:
GET /test/_search
{ "size": 0, "aggs": { "dynamic_fields_agg": { "scripted_metric": { "init_script": "state.map = [:];", "map_script": " def source = params._source[\"settings\"];\n for (def key : source.keySet()) {\n if (source[key].containsKey(\"display\")) {\n if (state.map.containsKey(key)) { \n state.map[key].add(source[key].display);\n } else {\n state.map[key] = [source[key].display];\n }\n }\n }", "combine_script": "return state", "reduce_script": "return states" } } }}