[Elasticsearch] ES聚合场景下部分结果数据未返回问题分析
背景
在对ES某个筛选字段聚合查询,类似groupBy操作后,发现该字段新增的数据,聚合结果没有展示出来,但是用户在全文检索新增的筛选数据后,又可以查询出来, 针对该问题进行了相关排查。
排查思路
首先要明确我们数据的写入流程, 下图:
在检查Mysql库的数据没有问题之后,开始检查ES是否有问题,根据现象我们知道既然在全文检索中都能搜索到,说明数据肯定是写入ES里了,但是又如何确定聚合结果呢?
首先添加日志将代码最终生成DSL语句打印出来
LOGGER.info("\n{}", searchRequestBuilder);
这样就很方便地使用curl命令进行调试了
下面是对生成的DSL语句执行查询:
curl -XGET 'http://ip:9200/es_data_index/_search?pretty' -H 'Content-Type: application/json' -d' { "query":{ "bool":{ "must":[ { "term":{ "companyId":{ "value":1, "boost":1 } } }, { "term":{ "yn":{ "value":1, "boost":1 } } }, { "match_all":{ "boost":1 } } ], "must_not":[ { "term":{ "table_sentinel":{ "value":2, "boost":1 } } } ], "disable_coord":false, "adjust_pure_negative":true, "boost":1 } }, "aggregations":{ "group_by_topics":{ "terms":{ "field":"topic", "size":10, "min_doc_count":1, "shard_min_doc_count":0, "show_term_doc_count_error":false, "order":[ { "_count":"desc" }, { "_term":"asc" } ] } } } }'
上图group_by_topics 就是我们要聚合的字段, 下面是执行该DSL语句的结果:
"aggregations" : { "group_by_topics" : { "doc_count_error_upper_bound" : 0, "sum_other_doc_count" : 14, "buckets" : [ { "key" : 1, "doc_count" : 35 }, { "key" : 19, "doc_count" : 25 }, { "key" : 18, "doc_count" : 17 }, { "key" : 29, "doc_count" : 15 }, { "key" : 20, "doc_count" : 12 }, { "key" : 41, "doc_coun ad8 t" : 8 }, { "key" : 161, "doc_count" : 5 }, { "key" : 2, "doc_count" : 3 }, { "key" : 3, "doc_count" : 2 }, { "key" : 21, "doc_count" : 2 } ] } }
经过观察发现聚合结果确实没有我们新增的筛选项, 同时返回的数据只有10条
"sum_other_doc_count" : 14,这项是关键项,从字面意思看还有有其他的文档,于是查询具体在ES中的意义是什么?
经过查询发现有段描述:
就是只会返回top结果, 部分结果不响应返回
那如何让这部分结果返回呢?
带着问题, 发现使用桶聚合,默认会根据doc_count 降序排序,同时默认只返回10条聚合结果.
可以通过在聚合查询增大属性size来解决,如下
curl -XGET 'http://ip:9200/es_data_index/_search?pretty' -H 'Content-Type: application/json' -d' { "query":{ "bool":{ "must":[ { "term":{ "companyId":{ "value":1, "boost":1 } } }, { "term":{ "yn":{ "value":1, "boost":1 } } }, { "match_all":{ "boost":1 } } ], "must_not":[ { "term":{ "table_sentinel":{ "value":2, "boost":1 } } } ], "disable_coord":false, "adjust_pure_negative":true, "boost":1 } }, "aggregations":{ "group_by_topics":{ "terms":{ "field":"topic", "size":100, "min_doc_count":1, "shard_min_doc_count":0, "show_term_doc_count_error":false, "order":[ { "_count":"desc" }, { "_term":"asc" } ] } } } }'
下面是查询结果:
"aggregations" : { "group_by_topics" : { "doc_count_error_upper_bound" : 0, "sum_other_doc_count" : 0, "buckets" : [ { "key" : 1, "doc_count" : 35 }, { "key" : 19, "doc_count" : 25 }, { "key" : 18, "doc_count" : 17 }, { "key" : 29, "doc_count" : 15 }, { "key" : 20, "doc_count" : 12 }, { "key" : 41, "doc_count" : 8 }, { "key" : 161, "doc_count" : 5 }, { "key" : 2, "doc_count" : 3 }, { "key" : 3, "doc_count" : 2 }, { "key" : 21, "doc_count" : 2 }, { "key" : 81, "doc_count" : 2 }, { "key" : 801, "doc_count" : 2 }, { "key" : 0, "doc_count" : 1 }, { "key" : 4, "doc_count" : 1 }, { "key" : 5, "doc_count" : 1 }, { "key" : 6, "doc_count" : 1 }, { "key" : 7, "doc_count" : 1 }, { "key" : 11, "doc_count" : 1 }, { "key" : 23, "doc_count" : 1 }, { "key" : 28, "doc_count" : 1 }, { "key" : 201, "doc_count" : 1 }, { "key" : 241, "doc_count" : 1 } ] }
把ES所有的筛选项数据都统计返回来.
代码里设置size:
TermsAggregationBuilder termAgg1 = AggregationBuilders.terms("group_by_topics") .field("topic").size(100);
我们解决了问题, 现在思考下ES为什么不一下子返回所有统计项的结果数据呢?
答案是由ES聚合机制决定, ES怎么聚合呢
接受客户端的节点是协调节点
协调节点上,搜索任务会被分解成两个阶段: query和fetch
真正搜索或聚合任务的节点为数据节点,如图 2, 3, 4
聚合步骤:
- 客户端发请求到协调节点
- 协调节点将请求推送到各数据节点
- 各数据节点指定分片参与数据汇集工作
- 协调节点进行总结果汇聚
es 出于效率和性能原因等,聚合的结果其实是不精确的.什么意思? 以我们上面遇到的场景为例:
默认返回top 10 聚合结果, 首先在各节点分片取自己的topic 10 返回给协调节点,然后协调节点进行汇总. 这样就会导致全量的实际聚合结果跟预期的不一致.
虽然有很多办法提高ES聚合精准度,但是如果对于大数据量的精准聚合,响应速度要快场景,es并不擅长,需要使用类似clickhouse这样的产品来解决这样的场景.
总结
本文主要针对实际工作的应用问题,来排查解决ES聚合数据部分数据未展示问题, 同时对ES的聚合检索原理进行讲解 .在数据量大、聚合精度要求高、响应速度快的业务场景ES并不擅长.
参考
https://discuss.elastic.co/t/what-does-sum-other-doc-count-mean-exactly/159687
- elasticsearch核心知识--30.分页搜索以及deep paging性能问题深度理解和es中聚合aggregation的分组可能结果不准确的原因
- elasticsearch的基础语句介绍 聚合功能很强大 可以分析数据
- nginx返回部分数据的问题
- js解析php返回的json数据无法获取length的问题分析
- mybatis使用 datamap作为返回的数据,返回的结果存在既有大写又有小写的问题
- 时间序列数据库——索引用ES、聚合分析时加载数据用什么?docvalues的列存储貌似更优优势一些。那分布式计算呢?ES做
- 白话Elasticsearch38-深入聚合数据分析之案例实战 下钻分析之统计每季度每个品牌的销售额
- elasticsearch选择器聚合,分组返回聚合结果
- 如何解决jmeter响应结果树中,返回数据显示不完整的问题?
- 白话Elasticsearch44-深入聚合数据分析之案例实战_颜色+品牌下钻分析时按最深层metric进行排序
- 【互动媒体】结课作业第二部分:数据分析、可视化以及几个额外问题
- RFM模型数据处理结果分析(回答网友的问题)
- 对于Volley中onResponse无法返回数据结果的问题解决方法
- php函数unserialize数据返回false问题分析
- 大数据日志分析系统-python脚本利用es聚合计算
- es的嵌套聚合、嵌套分析、下钻分析案例学习之Elasticsearch 07
- 白话Elasticsearch41-深入聚合数据分析之案例实战__过滤+聚合:统计价格大于2000的电视平均价格
- ElasticSearch6:document的dataSource元数据以及定制返回结果解析
- c# webserice 返回DataTable部分数据被截取 显示不全的问题
- ES-MongoDB学习1_elasticsearch与mongodb分布式集群环境下数据同步以及遇到的相应问题解答