多样化取样(diversified_sampler)聚合

sampler 聚合一样,这是一个过滤聚合,用于将任何子聚合的处理限制在得分最高的文档样本中。 diversified_sampler 聚合增加了限制共享一个公共值(如“author”)的匹配数量的能力。

任何一个优秀的市场调研人员都会告诉你,在处理数据样本时,重要的是样本要代表健康的各种观点,而不是被任何单一的声音所扭曲。 聚合也是如此,使用这些多样化的设置进行采样可以提供一种方法来消除内容中的偏见(人口过多的地理位置、时间轴上的一个大峰值或过于活跃的论坛垃圾邮件发送者)。

用例示例:

  • 将分析的焦点集中在高相关性匹配上,而不是潜在的低质量匹配长尾上
  • 通过确保公平呈现不同来源的内容,消除分析中的偏见
  • 降低仅使用样本(例如 significant_terms)即可产生有用结果的聚合的运行成本

选择 fieldscript 设置来提供用于数据去重的值,max_docs_per_value设置控制在任何一个共享公共值的分片上收集的文档的最大数量。 max_docs_per_value 的默认设置为 1

如果选择的 fieldscript 为单个文档产生多个值,则聚合将引发错误(出于效率考虑,不支持使用多值字段进行去重)。

例如:

我们可能想看看哪些标签与 StackOverflow 论坛帖子上的 #elasticsearch 密切相关,但忽略了一些高产用户倾向于将 #Kibana 拼写为 #Cabana 的影响。

POST /stackoverflow/_search?size=0
{
    "query": {
        "query_string": {
            "query": "tags:elasticsearch"
        }
    },
    "aggs": {
        "my_unbiased_sample": {
            "diversified_sampler": {
                "shard_size": 200,
                "field" : "author"
            },
            "aggs": {
                "keywords": {
                    "significant_terms": {
                        "field": "tags",
                        "exclude": ["elasticsearch"]
                    }
                }
            }
        }
    }
}

响应:

{
    ...
    "aggregations": {
        "my_unbiased_sample": {
            "doc_count": 151,
            "keywords": {
                "doc_count": 151,
                "bg_count": 650,
                "buckets": [
                    {
                        "key": "kibana",
                        "doc_count": 150,
                        "score": 2.213,
                        "bg_count": 200
                    }
                ]
            }
        }
    }
}

一共抽样了151份分档。

significant_terms 聚合的结果不会因为任何一个作者的怪癖而扭曲,因为我们要求样本中的任何一个作者最多发表一篇文章。

脚本化示例:

在这个场景下,我们可能希望对字段值的组合进行多样化。 我们可以使用一个 script 来产生一个 tags 字段中的多个值的哈希,以确保我们没有一个由相同的重复的 tag 组合组成的样本。

POST /stackoverflow/_search?size=0
{
    "query": {
        "query_string": {
            "query": "tags:kibana"
        }
    },
    "aggs": {
        "my_unbiased_sample": {
            "diversified_sampler": {
                "shard_size": 200,
                "max_docs_per_value" : 3,
                "script" : {
                    "lang": "painless",
                    "source": "doc['tags'].hashCode()"
                }
            },
            "aggs": {
                "keywords": {
                    "significant_terms": {
                        "field": "tags",
                        "exclude": ["kibana"]
                    }
                }
            }
        }
    }
}

响应:

{
    ...
    "aggregations": {
        "my_unbiased_sample": {
            "doc_count": 6,
            "keywords": {
                "doc_count": 6,
                "bg_count": 650,
                "buckets": [
                    {
                        "key": "logstash",
                        "doc_count": 3,
                        "score": 2.213,
                        "bg_count": 50
                    },
                    {
                        "key": "elasticsearch",
                        "doc_count": 3,
                        "score": 1.34,
                        "bg_count": 200
                    }
                ]
            }
        }
    }
}

shard_size

参数 shard_size 限制了在每个分片上处理的样本中收集多少个得分最高的文档。默认值为 100

max_docs_per_value

max_docs_per_value 是一个可选参数,它限制每次选择数值去重时允许的文档数量。默认值为 1

execution_hint

可选的 execution_hint 设置会影响用于值的去重的管理。 在执行去重时,每个选项最多可在内存中保存的个数为 shard_size,但保存的值的类型可以控制如下:

  • 直接保存字段值(map
  • 保存由Lucene索引确定的字段序号(global_ordinals
  • 保存字段值的哈希 - 这有可能导致哈希冲突(bytes_hash

如果这个信息可以从 Lucene 索引中获得,则默认是使用 global_ordinals,否则,就恢复使用 mapbytes_hash 设置在某些情况下可能会更快,但由于可能会发生哈希冲突,因此可能会在去重逻辑中引入误报。 请注意,如果不适用,Elasticsearch 将忽略执行提示的选择,并且这些提示没有向后兼容性保证。

局限性

不能在breadth_first聚合下嵌套

作为一个基于质量的过滤器,diversified_sampler 聚合需要访问每个文档的相关性分数。 因此,它不能嵌套在将 collect_mode 从默认的depth_first模式切换到 breadth_first 模式的 terms 聚合下,因为这个模式下会丢弃分数。 在这种情况下,将会抛出一个错误。

有限的去重逻辑

去重逻辑仅适用于分片级别,因此不适用于所有分片。

geo/date 字段没有专门的语法

目前,定义多样化值的语法是通过选择 fieldscript 来定义的——没有添加语法糖来表示 geo 或 date 单位,如“7d”(7天)。 此项支持可能会在以后的版本中添加,用户现在必须使用脚本来创建这些类型的值。