子聚合导致数据丢失

Subaggregation leads to missing data

问题简述:使用子聚合执行查询时,为什么在某些情况下内部聚合会丢失数据?

问题详细:我有一个带有子聚合(桶中桶)的搜索查询如下:

{
    "size": 0,
    "aggs": {
        "outer_docs": {
            "terms": {"size": 20, "field": "field_1_to_aggregate_on"},
            "aggs": {
                "inner_docs": {
                    "terms": {"size": 10000, "field": "field_2_to_aggregate_on"},
                    "aggs": "things to display here"
                }
            }
        }
    }
}

如果我执行此查询,对于一些 outer_docs,我收到的不是所有与之关联的 inner_docs。在下面的输出中,外部文档 key_1 有三个内部文档。

{
    "hits": {
        "total": 9853,
        "max_score": 0.0,
        "hits": []
    },
    "aggregations": {
        "outer_docs": {
            "doc_count_error_upper_bound": -1, "sum_other_doc_count": 9801,
            "buckets": [
                {
                    "key": "key_1", "doc_count": 3,
                    "inner_docs": {
                        "doc_count_error_upper_bound": 0,
                        "sum_other_doc_count": 0,
                        "buckets": [
                            {"key": "1", "doc_count": 1, "some": "data here"},
                            ...
                            {"key": "3", "doc_count": 1, "some": "data here"},
                        ]
                    }
                },
                ...
            ]
        }
    }
}

现在,我将一个查询添加到单个 select 一个 outer_doc 无论如何都会在前 20 个中。

"query": {"bool": {"must": [{'term': {'field_1_to_aggregate_on': 'key_1'}}]}}

在这种情况下,我确实得到了所有 inner_docs,它们位于外部文档 key_1.

的七个内部文档下方的输出中
{
    "hits": {
        "total": 8,
        "max_score": 0.0,
        "hits": []
    },
    "aggregations": {
        "outer_docs": {
            "doc_count_error_upper_bound": -1, "sum_other_doc_count": 9801,
            "buckets": [
                {
                    "key": "key_1", "doc_count": 8,
                    "inner_docs": {
                        "doc_count_error_upper_bound": 0,
                        "sum_other_doc_count": 0,
                        "buckets": [
                            {"key": "1", "doc_count": 1, "some": "data here"},
                            ...
                            {"key": "7", "doc_count": 2, "some": "data here"},
                        ]
                    }
                },
                ...
            ]
        }
    }
}

我已经明确指定我想要每个 outer_doc 10,000 inner_docs。是什么阻止我获取所有数据?

这是我的版本信息:

{
    'build_date': '2018-09-26T13:34:09.098244Z',
    'build_flavor': 'default',
    'build_hash': '04711c2',
    'build_snapshot': False,
    'build_type': 'deb',
    'lucene_version': '7.4.0',
    'minimum_index_compatibility_version': '5.0.0',
    'minimum_wire_compatibility_version': '5.6.0',
    'number': '6.4.2'
}

编辑:进一步挖掘后,我发现问题与子聚合无关,而是与聚合本身和分片的使用有关。我已经为 Elastic 打开了这个错误报告:

为此使用 composite aggregation 怎么样?肯定能解决您的问题。

GET /_search
{
    "aggs" : {
        "all_docs": {
            "composite" : {
                "size": 1000,
                "sources" : [
                    { "outer_docs": { "terms": { "field": "field_1_to_aggregate_on" } } },
                    { "inner_docs": { "terms": { "field": "field_2_to_aggregate_on" } } }
                ]
            }
        }
    }
}

如果您有多个存储桶,复合聚合将帮助您使用 size/after 滚动浏览每个存储桶。

检查您的弹性弃用日志文件。您可能会收到这样的警告:

This aggregation creates too many buckets (10001) and will throw an error in future versions. You should update the [search.max_buckets] cluster setting or use the [composite] aggregation to paginate all buckets in multiple requests.

search.max_buckets 是一个动态集群设置,在 7.0 中默认为 10.000 个桶。

现在,这在任何地方都没有记录,但根据我的经验:分配超过 10.000 个桶会导致您的查询终止,但您将取回在那一刻之前获得的结果。这解释了结果中缺少的数据

使用复合聚合会有所帮助,您的另一个选择是增加 max_buckets。请小心,您可能会以这种方式使整个集群崩溃,因为每个存储桶 (RAM) 都有成本。如果你真的使用了所有分配的桶并不重要,你可以只用空桶崩溃。

参见:

https://www.elastic.co/guide/en/elasticsearch/reference/master/breaking-changes-7.0.html#_literal_search_max_buckets_literal_in_the_cluster_setting https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket.html https://github.com/elastic/elasticsearch/issues/35896

事实证明问题不是由于子聚合引起的,而是 ElasticSearch 的一个实际功能。我们使用 5 个分片,使用分片时,聚合仅 return 近似结果。

我们已将此问题重现,并将其发布在 Elastic discuss forum. There, we learned that aggregations do not always return all data, with a link to the documentation 中,其中对此进行了更详细的解释。

我们还了解到,仅使用 1 个分片即可解决问题,当这不可能时,参数 shard_size 可以缓解问题。