[Elasticsearch] ES聚合场景下部分结果数据未返回问题分析

在对ES某个筛选字段聚合查询,类似groupBy操作后,发现该字段新增的数据,聚合结果没有展示出来,但是用户在全文检索新增的筛选数据后,又可以查询出来, 针对该问题进行了相关排查。

排查思路

首先,我们需要明确我们的数据写入流程,如下所示:

[En]

First of all, we need to clarify the process of writing our data, as shown below:

首先添加日志将代码最终生成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_count" : 8
        },
        {
          "key" : 161,
          "doc_count" : 5
        },
        {
          "key" : 2,
          "doc_count" : 3
        },
        {
          "key" : 3,
          "doc_count" : 2
        },
        {
          "key" : 21,
          "doc_count" : 2
        }
      ]
    }
  }

经过观察发现,聚合结果中确实没有我们添加的筛选项,同时返回的数据只有10项。

[En]

After observation, it is found that the aggregate result really does not have the filter items we have added, and only 10 items of data are returned at the same time.

"sum_other_doc_count" : 14, 这项是关键项,从字面意思看还有有其他的文档,于是查询具体在ES中的意义是什么?

经过查询发现有段描述:

就是只会返回top结果, 部分结果不响应返回

那么,如何才能拿回这部分结果呢?

[En]

So how do you get this part of the result back?

带着问题, 发现使用桶聚合,默认会根据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怎么聚合呢

接受客户端的节点是业务流程节点

[En]

The node that accepts the client is the orchestration node

协调节点上,搜索任务会被分解成两个阶段: query和fetch

实际搜索或聚合任务的节点是数据节点,如图2、3、4所示

[En]

The nodes that actually search or aggregate tasks are data nodes, as shown in figures 2, 3, 4

聚合步骤:

  • 客户端发请求到协调节点
  • 协调器节点将请求推送到每个数据节点
    [En]

    the coordinator node pushes the request to each data node*

  • 每个数据节点分配片段参与数据收集工作
    [En]

    each data node assigns fragments to participate in the data collection work*

  • 协调节点进行总结果汇聚

es 出于效率和性能原因等,聚合的结果其实是不精确的.什么意思? 以我们上面遇到的场景为例:

默认返回top 10 聚合结果, 首先在各节点分片取自己的topic 10 返回给协调节点,然后协调节点进行汇总. 这样就会导致全量的实际聚合结果跟预期的不一致.

虽然有很多办法提高ES聚合精准度,但是如果对于大数据量的精准聚合,响应速度要快场景,es并不擅长,需要使用类似clickhouse这样的产品来解决这样的场景.

本文主要针对实际工作的应用问题,来排查解决ES聚合数据部分数据未展示问题, 同时对ES的聚合检索原理进行讲解 .在数据量大、聚合精度要求高、响应速度快的业务场景ES并不擅长.

Original: https://www.cnblogs.com/bigdata1024/p/15743208.html
Author: chaplinthink
Title: [Elasticsearch] ES聚合场景下部分结果数据未返回问题分析

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/522629/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球