对动态属性的字段进行Elasticsearch聚合



给定以下映射,其中变体是nested类型,选项是flattened类型:

{
"doc_type" : "product",
"id" : 1,
"variants" : [
{
"options" : {
"Size" : "XS",
},
"price" : 1,
},
{
"options" : {
"Size" : "S",
"Material": "Wool"
},
"price" : 6.99,
},
]
} 

我想运行一个聚合,生成以下格式的数据:

{
"variants.options.Size": {
"buckets" : [
{
"key" : "XS",
"doc_count" : 1
},
{
"key" : "S",
"doc_count" : 1
},
],
},
"variants.options.Material": {
"buckets" : [
{
"key" : "Wool",
"doc_count" : 1
}
],
},
} 

我可以很容易地这样做:

"aggs": {
"variants.options.Size": {
"terms": {
"field": "variants.options.Size"
}
},
"variants.options.Material": {
"terms": {
"field": "variants.options.Material"
}
}
}
这里的警告是,我们使用flattened类型的选项,因为选项中的字段是动态因此,我没有办法事先知道我们要在SizeMaterial上聚合。

本质上,我想告诉Elasticsearch,它应该聚合它在options下找到的任何键。有办法做到这一点吗?

我想告诉Elasticsearch它应该聚合它在选项下找到的任何键。有办法做到这一点吗?

不直接。我之前也有过同样的问题。到今天为止,我还没有找到一个干净利落的解决办法,而且我相信根本没有。

幸运的是,有一个scripted_metric的解决方案,我在这里概述。将它应用到您的用例:

POST your_index/_search
{
"size": 0,
"aggs": {
"dynamic_variant_options": {
"scripted_metric": {
"init_script": "state.buckets = [:];",
"map_script": """
def variants = params._source['variants'];
for (def variant : variants) {
for (def entry : variant['options'].entrySet()) {
def key = entry.getKey();
def value = entry.getValue();
def path = "variants.options." + key;
if (state.buckets.containsKey(path)) {
if (state.buckets[path].containsKey(value)) {
state.buckets[path][value] += 1;
} else {
state.buckets[path][value] = 1;
}
} else {
state.buckets[path] = [value:1];
}
}
}
""",
"combine_script": "return state",
"reduce_script": "return states"
}
}
}
}

将收益率:

"aggregations" : {
"dynamic_variant_options" : {
"value" : [
{
"buckets" : {
"variants.options.Size" : {
"S" : 1,
"XS" : 1
},
"variants.options.Material" : {
"Wool" : 1
}
}
}
]
}
}

如果您希望buckets是key-doc_count对的数组,而不是像我的示例那样的哈希映射,则需要调整painless代码。

最新更新