ES Terms 聚合数据不确定性

Elasticsearch是一个分布式的搜索引擎,每个索引都可以有多个分片,用来将一份大索引的数据切分成多个小的物理索引,解决单个索引数据量过大导致的性能问题,另外每个shard还可以配置多个副本,来保证高可靠以及更好的抗并发的能力。
将一个索引切分成多个shard,大多数时候是没有问题的,但是在es里面如果索引被切分成多个shard,在使用group进行聚合时,可能会出现问题,参见官网文档
先了解ES 聚合的核心概念:桶(bucket)和指标(metric)
  • 桶(bucket): 满足特定条件的文档的集合
  • 指标(metric): 对桶内的文档进行聚合分析的操作

聚合是由桶和指标组成的。聚合可能只有一个桶,可能只有一个指标,或者可能两个都有。转换成成对应的sql语句如下:

  select count(*) from Table_A  group by FieldA
其中:bucket 相当于 group by FieldA --> FieldA 字段内相同的数据,就会被划分到一个bucket中
   metric 相当于 count(*) --> 对每个FieldA  bucket中所有的数据计算一个数量
如下图:
ES Terms 聚合数据不确定性
 
针对官网的例子,描述group count如果有多个shard可能会出现的问题
  • 有一份商品的索引数据,它有3个shard,每个shard的数据如下所示(括号内表示商品document count), 要获取name字段中出现频率最高的前5个
  • ES Terms 聚合数据不确定性
  • 客户端向ES发送聚合请求,主节点接收到请求后,会向每个独立的分片发送该请求。分片独立的计算自己分片上的前5个name如下图,然后返回:
  • ES Terms 聚合数据不确定性
  • 当所有的分片结果都返回后,在主节点进行结果的合并,再求出频率最高的前5个,返回给客户端, 结果如下图:
  • ES Terms 聚合数据不确定性
  • 最后发现这个top5的结果,并不是100%精确的,只是一个近似精确的结果值:
  1. Product A在所有top5的shard数据里面都存在,所以它的结果是精确的
  2. Product C仅仅返回了 shard A 和 C里面的top5的数据,所以这里显示50是不精确的, Product C在shard B里面也存在,但是它在 top5里面没有出现,所以group后的结果实际上是有误差的
  3. Product Z仅仅返回了2个shards的数据 因为第三个里面不存在,所以它的结果是准确的
  4. Product H实际上它的总数是44,横跨三个shard 但是它在每个shard的top5里面并没有出现,所以最终的top5里面也没有这条数据

这样看来最终的top5的值并不是100% 准确的

虽然我们可以调大返回size的个数来提高精确度,但是size个数的提升,也意味着有更多的数据会被返回,从而会导致检索性能的下降,这一点是需要找到平衡点的,  为解决这种不精确的统计,可以尝试的方案:
  1. 聚合操作在单个shard时是精确的,也就是说我们索引的数据全部插入到一个shard的时候 它的聚合统计结果是准确的。
  2. 在索引数据的时候,使用route路由字段,将所有聚合的数据分布到同一个shard即可,这样再聚合时也是精确的。 参见:ES Route
  • 第一种适合数据量不大的场景下,我们直接把数据放在一份索引里面,第二种办法适合数据量比较大的场景下,我们通过业务字段将相同属性的数据路由在同一个shard里面即可,具体使用哪个需要和具体的业务场景相结合。

3. size与shard_size

  • size参数规定了最后返回的term个数(默认是10个)
  • shard_size参数规定了每个分片上返回的个数
  • 如果shard_size小于size,那么分片也会按照size指定的个数计算
  • 通过这两个参数,如果我们想要返回前5个,size=5;shard_size可以设置大于5,这样每个分片返回的词条信息就会增多,相应的误差几率也会减小。

上面提到那个例子,如果聚合的key本来就很少,那么它的聚合结果也是准确的,比如按性别,月份聚合,因为这些返回的key,都是有限的,所以结果没问题,但是一旦对分组的个数没法确定,这种情况下出现问题的几率就比较大,跨表或者跨分片聚合其实在任何db系统里面都会存在这种问题,所以我们应该尽量在设计业务时就考虑到这种特殊情况,然后最终做特殊处理。

上一篇:JS最简单的字符串转数字类型


下一篇:【UI 设计】PhotoShop基础工具 -- 移动工具