es聚合中的一些问题解答
Per bucket Document Count Error
每个桶的错误文档数量,可以通过参数show_term_doc_count_error=true来展示每个文档未被纳入结果集的数量
GET /_search
{
"aggs" : {
"products" : {
"terms" : {
"field" : "product",
"size" : 5,
"show_term_doc_count_error": true
}
}
}
}
返回结果
order问题
可以设置桶的排序,默认是按照桶的doc_count降序排序的。
order的可选值:
“order” : { “_count” : “asc” }
“order” : { “_key” : “asc” }
支持子聚合的结果作为排序字段。
GET /_search
{
"aggs" : {
"genres" : {
"terms" : {
"field" : "genre",
"order" : { "max_play_count" : "desc" } // "order" : { "playback_stats.max" : "desc" }
},
"aggs" : {
"max_play_count" : { "max" : { "field" : "play_count" } } // "playback_stats" : { "stats" : { "field" : "play_count" } }
}
}
}
}
Filtering values(值过滤)
对值使用正则表达式进行过滤,示例如下:
GET /_search
{
"aggs" : {
"tags" : {
"terms" : {
"field" : "tags",
"include" : ".*sport.*", // include 包含
"exclude" : "water_.*" // exclude 排除
}
}
}
}
精确值匹配
"JapaneseCars" : {
"terms" : {
"field" : "make",
"include" : ["mazda", "honda"]
}
}
分区过滤:
GET /_search
{
"size": 0,
"aggs": {
"expired_sessions": {
"terms": {
"field": "account_id",
"include": {
"partition": 0, // @1
"num_partitions": 20 // @2
},
"size": 10000,
"order": {
"last_access": "asc"
}
},
"aggs": {
"last_access": {
"max": {
"field": "access_date"
}
}
}
}
}
}
分区的意思就是将值分成多个组,没一个请求只处理其中一个组,其中参数 @1表示请求的分组ID,num_partitions表示总共的分组数。\
Collect mode
收集模式,ES支持两种收集模式:
depth_first:深度优先,默认值。
breadth_first:广度优先。
首先我们先学习一下树的基本知识(深度遍历与广度遍历),例如有如下一颗二叉树:
深度遍历:深度遍历是从一个节点开始,先遍历完该节点所有的子节点,然后再返回遍历它的兄弟节点,通常深度遍历分为中序遍历、前序遍历,后序遍历。
中序遍历(遍历左子树–>访问根–>遍历右子树):D B E A F C G
前序遍历(访问根–>遍历左子树–>遍历右子树):A B D E C F G
后序遍历(遍历左子树–>遍历右子树–>访问根):D E B F G C A
广度遍历(一层一层遍历):A B C D E F G
广度优先聚合与深度优先聚合的构建流程(聚合流程)与其遍历顺序一致。
查询member_age最多的三个,并且member_id数量最多的5个–>广度查询 默认是深度查询
GET /wipro-headpic/_doc/_search?size=0
{
"aggs" : {
"一级actors" : {
"terms" : {
"field" : "member_age",
"size" : 3,
"shard_size" : 10,
"collect_mode" : "breadth_first"
},
"aggs" : {
"二级costars" : {
"terms" : {
"field" : "member_id.keyword",
"size" : 5
}
}
}
}
}
}
查询结果
{
"took" : 197,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 10000,
"relation" : "gte"
},
"max_score" : null,
"hits" : [ ]
},
"aggregations" : {
"一级actors" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 9991,
"buckets" : [
{
"key" : 1,
"doc_count" : 5,
"二级costars" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "7992254",
"doc_count" : 5
}
]
}
},
{
"key" : 0,
"doc_count" : 3,
"二级costars" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "7992254",
"doc_count" : 3
}
]
}
},
{
"key" : 2,
"doc_count" : 3,
"二级costars" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "7992254",
"doc_count" : 3
}
]
}
}
]
}
}
}
深度遍历优先的执行路径:
开始对整个文档进行搜索,从文档中得出第一个最大值,然后立马执行子聚合,首先刷选出有该字段参与的文档集中的词根,并聚合其数量,排名前3的组成一个聚合结果,
然后再返回上一层聚合,再对上一层的下一个词根执行类似的聚合,最后进行排序,在第一层进行裁剪(刷选)前size个文档返回个客户端。
广度遍历优先的执行路径:
首先执行第一层聚合,也就是针对所有文档中的actors字段进行聚合,得到文档集中所有的演员,然后按doc_count排序,进行裁剪,刷选前3个文档,然后只针对这3个文档进行第二层聚合。
看上去广度遍历优先会非常高效,其实这里掩藏了一个实现细节,就是广度优先,会缓存裁剪后剩余的所有文档,也就是本例中与这3个演员的所有文档集在内存中,然后基于这些内存执行第二层聚合,故如果第一层每个桶如果包含的文档数量巨大,则会耗费很大的内存,容易触发OOM异常,故广度优先的使用场景是子聚合所需要处理的数据很少的情况下会非常高效。
参考知识:http://www.cnblogs.com/bonelee/p/7832738.html
上一篇: 图论基础——遍历图的DFS
下一篇: 学习webpack遇到的一些问题