Elasticsearch多terms聚合结果中如何移除key或key_as_string字段以避免内容重复?
嗨,这个问题我之前也碰到过,Elasticsearch的multi_terms聚合默认确实会同时返回key(数组格式的多字段值)和key_as_string(竖线拼接的字符串),很容易造成内容冗余。下面给你两种可行的解决思路:
方案一:在Elasticsearch层面通过脚本聚合自定义返回结构
你可以使用scripted_metric聚合来手动构建聚合结果,只保留你需要的字段。比如如果想只保留key数组,示例查询如下:{ "size": 0, "aggs": { "contexts": { "scripted_metric": { "init_script": "state.buckets = [:]", "map_script": """ def key1 = doc['context_1.id'].value; def key2 = doc['context_2.id'].value; def compositeKey = key1 + '|' + key2; if (state.buckets.containsKey(compositeKey)) { state.buckets[compositeKey]++; } else { state.buckets[compositeKey] = 1; } """, "combine_script": "return state.buckets", "reduce_script": """ def finalBuckets = [:]; for (bucket in states) { for (entry in bucket.entrySet()) { if (finalBuckets.containsKey(entry.getKey())) { finalBuckets[entry.getKey()] += entry.getValue(); } else { finalBuckets[entry.getKey()] = entry.getValue(); } } } // 转换成你需要的格式,比如只保留key数组 def result = []; for (entry in finalBuckets.entrySet()) { def keys = entry.getKey().split('\\|'); result.add(['key': keys, 'doc_count': entry.getValue()]); } return result; """ } } } }这个脚本会手动统计两个字段组合后的文档数,最后返回只包含
key和doc_count的结构,完全避开了默认的key_as_string字段。如果想保留key_as_string而去掉key,只需要修改reduce_script里的返回逻辑,把['key': keys, ...]改成['key_as_string': entry.getKey(), 'doc_count': entry.getValue()]就行。方案二:在应用层过滤冗余字段
如果不想在Elasticsearch层面写复杂的脚本,更简单的方式是在拿到聚合结果后,在你的应用代码里遍历每个bucket,删除不需要的字段。比如用Python处理的示例代码:# 假设es_response是Elasticsearch返回的完整结果 for bucket in es_response['aggregations']['contexts']['buckets']: # 删除key_as_string,只保留key字段 del bucket['key_as_string'] # 如果你想保留key_as_string而删除key,就用下面这行替换上面的 # del bucket['key']这种方式灵活又省心,不需要改动Elasticsearch的查询逻辑,适合大多数日常开发场景。
补充一句:目前Elasticsearch的multi_terms聚合还没有提供直接关闭key或key_as_string的配置参数,所以上面两种是开发者们常用的解决办法。如果你的ES版本比较新,也可以多留意官方的更新,说不定后续会新增相关的配置项哦。
内容来源于stack exchange

