搜索引擎ElasticSearch之(7)、聚合查询

1、度量聚合

度量聚合从文档中提取值并进行计算,这些值通常从文档中的字段中提取出来,也可以使用脚本进行计算。数字型度量聚合是一种特殊类型的度量聚合,输出数字类型的值,聚合输出一个数字指标的为单值数字型度量聚合;输出多指标的为多值数字型度量聚合。

1.1、平均值聚合

平均值聚合是一个单值度量聚合,计算从聚合的文档中提取数字型值的平均值。
示例1:

GET /city/_doc/_search
{
  "aggs":{
    "avg_population":{"avg":{"field":"population"}}
  }
}

示例2:基于脚本

GET /city/_doc/_search
{
  "aggs":{
    "avg_population":{"avg":{"script":"doc['population'].value + 1000"}}
  }
}

示例3:默认值

GET /city/_doc/_search
{
  "aggs":{
    "avg_population":{
      "avg":{
        "field":"population",
        "missing":100
      }
    }
  }
}

1.2、基数聚合

基数聚合是一个单值度量聚合,计算不同值的近似计数,值可以从特定字段提取或通过脚本生成。
示例:

GET /people/_doc/_search
{
  "query":{
    "match":{"country":"中国"}
  },
  "aggs":{
    "country_count":{"cardinality":{"field":"country","precision_threshold":100}}
  }
}

1.3、最大值聚合

此聚合为单值聚合,记录和返回从聚合的文档中提取的数字型值中的最大值,值可以从特定字段提取或通过脚本生成。
示例:

GET /city/_doc/_search
{
  "aggs":{
    "max_population":{"max":{"field":"population"}}
  }
}

1.4、最小值聚合

此聚合为单值聚合,记录和返回从聚合的文档中提取的数字型值中的最小值,值可以从特定字段提取或通过脚本生成。
示例:

GET /city/_doc/_search
{
  "aggs":{
    "min_population":{"min":{"field":"population"}}
  }
}

1.5、和聚合

此聚合为单值聚合,其对聚合文档中提取的数值型值进行求和,值可以从特定字段提取或通过脚本生成。
示例:

GET /city/_doc/_search
{
  "aggs":{
    "sum_population":{"sum":{"field":"population"}}
  }
}

1.6、值计数聚合

此聚合为单值聚合,其对聚合文档中提取的值进行计数,值可以从特定字段提取或通过脚本生成。
示例:

GET /city/_doc/_search
{
  "aggs":{
    "population_count":{"value_count":{"field":"population"}}
  }
}

1.7、统计聚合

此聚合为多值聚合,其对聚合文档中提取的数值型值进行统计计算,值可以从特定字段提取或通过脚本生成。统计值包含:最小值,最大值,和,平均值,计数值。
示例:

GET /city/_doc/_search
{
  "aggs":{
    "population_stats":{"stats":{"field":"population"}}
  }
}

1.8、百分比聚合

此聚合是个多值聚合,对聚合文档中的数值型计算一个或多个百分比,我们可以通过百分比聚合结果评估数据分布,判断数据是否符合预期等。默认百分比为:[1,5,25,50,75,95,99]。
示例:

GET /city/_doc/_search
{
  "aggs":{
    "population_liner":{"percentiles":{"field":"population"}}
  }
}

1.9、百分比分级聚合

此聚合为多值聚合,对聚合文档中的数值型计算一个或多个级别的百分比。
示例:

GET /city/_doc/_search
{
  "aggs":{
    "population_rank":{"percentile_ranks":{"field":"population","values":[1000,2000]}}
  }
}

1.10、地理边界聚合

此聚合是一个度量聚合,为字段计算包含所有地点点值的边界框。
示例:

GET /city/_doc/_search
{
  "query":{
    "match":{"country":"中国"}
  },
  "aggs":{
    "viewport":{"geo_bounds":{"field":"location"}}
  }
}

1.11、地理重心聚合

此聚合为度量聚合,从文档中的地理点数据中获取所有坐标值找那个计算出有力的矩心。
示例:

GET /city/_doc/_search
{
  "query":{
    "match":{"country":"中国"}
  },
  "aggs":{
    "center":{"geo_centroid":{"field":"location"}}
  }
}

2、分组聚合

2.1、直方图聚合

此聚合为多分组聚合,可以应用于从文档中提取数值,并在数值上动态创建固定大小的分组。
示例:

GET /city/_doc/_search
{
  "aggs":{
    "population_hist":{"histogram":{"field":"population","interval":500}}
  }
}

最小文档计数:
默认情况响应会用空分组填补直方图中的空白,可以利用min_doc_count设置类修改分组,要求一个更高的最低计数。
示例:

GET /city/_doc/_search
{
  "aggs":{
    "population_hist":{"histogram":{"field":"population","interval":500,"min_doc_count":1}}
  }
}

分组起始结束值:
分组默认的起始/结束数值为所有命中文档对应值的最小值/最大值,但有时我们需要的是一个自定义的范围。此时可通过extended_bounds进行设置,强制直方图的聚合从给定的最小值/最大值进行分组。当extended_bounds.min比文档最小值大的时候,依然使用文档的最小值,当extended_bounds.max比文档最大值小的时候,依然使用文档的最大值。
示例:
GET /city/_doc/_search
{
"aggs":{
"population_hist":{"histogram":{"field":"population","interval":500,"extended_bounds":{"min":1000,"max":5000}}}
}
}

排序:
分组默认按照键升序排序,可以通过order设置来控制排序行为。

GET /city/_doc/_search
{
  "aggs":{
    "population_hist":{
      "histogram":{
        "field":"population",
        "interval":500,
        "extended_bounds":{"min":1000,"max":5000},
        "order":{"_key":"desc"}
        
      }
      
    }
  }
}


GET /city/_doc/_search
{
  "aggs":{
    "population_hist":{
      "histogram":{
        "field":"population",
        "interval":500,
        "extended_bounds":{"min":1000,"max":5000},
        "order":{"_count":"desc"}
        
      }
      
    }
  }
}

2.2、日期直方图聚合

日期直方图聚合是一个多分组聚合,是专门应用于日期类型的直方图。
示例:

GET /people/_doc/_search
{
  "aggs":{
    "date_over_time":{
      "date_histogram":{
        "field":"date",
        "interval":"month",
        "format":"yyyy-mm-dd"
      }
    }
  }
}

2.3、时间范围聚合

此聚合专门用于时间型数据的范围聚合,其form和to参数可以指定日期或日期数学表达式,同时可指定form和to的日期格式,时间范围包含from但排除同。
示例:

GET /people/_doc/_search
{
  "aggs":{
    "date_range":{
      "date_range":{
        "field":"date",
        "format":"yyyy-mm-dd",
        "ranges":{
          "from":"2010-01-01",
          "to":"2012-12-30"
        }
      }
    }
  }
}

2.4、范围聚合

此聚合基于多组范围值来聚合,可设定一系列范围,每个范围代表一个分组,文档值会检查每个分组范围,并使相关文档落入分组中。
示例:

GET /city/_doc/_search
{
  "aggs":{
    "popu_range":{
      "range":{
        "field":"population",
        "ranges":[
          {"from":0,"to":500},
          {"from":500,"to":1000},
          {"from":1000,"to":2000},
          {"from":2000,"to":3000}
          ]
      }
    }
  }
}

2.5、过滤聚合

此聚合是单分组聚合,包含文档集中所有匹配指定的过滤条件的文档。
示例:

GET /city/_doc/_search
{
  "aggs":{
    "population_china":{
      "filter":{
        "match":{"country":"中国"}
      },
      "aggs":{
          "pupo_avg":{
            "avg":{"field":"population"}
          }
        }
    }
  }
}

2.6、多重过滤聚合

此聚合定义多分组聚合,每个分组关联一个过滤条件,并收集所有满足自身过滤条件的文档。可以添加other_buket设置其他分组是否参与分组,并通过other_bucket_key设置其他分组的名称。
示例:

GET /city/_doc/_search
{
  "aggs":{
    "population_china":{
      "filters":{
        "other_bucket_key":"other_msg",
        "filters":{
          "country":{"match":{"country":"中国"}},
          "descirbe":{"match":{"describe":"中国"}}
        }
      },
      "aggs":{
          "pupo_avg":{
            "avg":{"field":"population"}
          }
        }
    }
  }
}

2.7、空值聚合

此聚合是一个基于字段数据的分组聚合,在当前文档集中对所有缺失字段值的文档创建一个分组,这个聚合通常和其他字段数据分组聚合一起使用,返回由于缺少字段值而不能放入其他任何分组中的所有文档的信息。
示例:

GET /city/_doc/_search
{
  "aggs":{
    "population_stats":{"missing":{"field":"population"}}
  }
}

2.8、地理点距离聚合

作用于地理点类型字段上的多组聚合,原理同范围聚合类似,可以设定一个圆点和一系列距离范围分组。聚合评估每个文档的值和原点之间的距离,然后基于范围决定文档属于哪个分组。
示例:

GET /city/_doc/_search
{
  "aggs":{
    "city_dist":{
      "geo_distance":{
        "field":"location",
        "origin":"39.1233,116.2424",
        "ranges":[
          {"to":1000},
          {"from":1000,"to":5000},
          {"to":10000}
        ]
    
      }
    }
  }
}

3、管道聚合

管道聚合工作与其他聚合的输出结果而不是文档集,用于向输出树添加信息,通过bucket_path参数指定请求的路径来引用数据的来源。管道聚合不能拥有子聚合,但可以在bucket_path参数中引入另一个管道聚合,使管道聚合连接起来。
管道聚合分类:

  • 父类聚合:在父聚合输出的基础上进行管道聚合,可以在现有分组的基础上计算新的分组或聚合。
  • 兄弟聚合:在兄弟聚合输出结果的基础上进行管道聚合,可以计算与兄弟聚合相同等级的新聚合。

bucket_path语法:

  • 聚合分隔符为“>”;
  • 指标分隔符为".";
  • 聚合名为<聚合名称>;
  • 指标为<指标的名称>;
  • 路径为:<聚合名>[<聚合分隔符><聚合名>]*[<指标分隔符><指标>]

特殊路径:
bucket_path可以使用特殊路径如“_count”,让管道聚合使用文档计数作为输入参数。

3.1、平均分组聚合

此聚合会计算在一组聚合中指定指标的平均值,指定的指标必须是数字型而且这组聚合必须是多组聚合。
参数:

  • bucket_path:要计算平均值的分组路径;
  • gap_policy:当数据缺口出现时应用的策略(默认跳过);
  • format:规范聚合输出的格式(默认为null);

示例:

GET /people/_doc/_search
{
  "aggs":{
    "country_term":{
      "terms":{"field":"country"},
      "aggs":{
        "age_avg":{"avg":{"field":"age"}}
      }
    },
    "avg_country_popu":{
      "avg_bucket":{"buckets_path":"country_term>age_avg"}
    }
  }
}

3.2、移动平均聚合

对一组有序的数据,移动平均聚合会在数据上滑动一个固定大小的窗口并给出窗口的平均值。
参数:

  • buckets_path:指标路径(必填);
  • model:移动平均加权模型;
  • gap_policy:数据缺口时的行为(默认插入零);
  • window:在直方图上滑动的窗口大小(默认为5);
  • settings:模型的具体设置,根据指定的模型有不同的内容;

示例:

GET /people/_doc/_search
{
 "aggs":{
    "date_over_time":{
      "date_histogram":{
        "field":"date",
        "interval":"month",
        "format":"yyyy-mm-dd"
      },
      "aggs":{
        "age_sum":{"sum":{"field":"age"}},
        "age_moving":{
          "moving_avg":{
            "buckets_path":"age_sum",
            "model":"holt",
            "window":5,
            "gap_policy":"insert_zeros",
            "settings":{"alpha":0.8}
        }
        
      }
    }
  }
  }
}

3.3、总和分组聚合

计算所有分组中指定指标的和。
示例:

GET /people/_doc/_search
{
  "aggs":{
    "country_term":{
      "terms":{"field":"country"}
      },
      
    "sum_country":{
     "sum_bucket":{"buckets_path":"country_term._count"}
    }
  }
}

3.4、最大/小分组聚合

获取一组聚合指标中的最大/小值。
示例:

GET /people/_doc/_search
{
  "aggs":{
    "country_count":{
      "terms":{"field":"country"},
      "aggs":{
        "avg_age":{
          "avg":{"field":"age"}
        }
      }
    },
      
    "max_avg_age":{
     "max_bucket":{"buckets_path":"country_count>avg_age"}
    },
    "min_avg_age":{
     "min_bucket":{"buckets_path":"country_count>avg_age"}
    }
  }
}

3.5、统计分组聚合

统计所有分组中某个指标的各种统计值。
示例:

GET /people/_doc/_search
{
 "aggs":{
    "date_over_time":{
      "date_histogram":{
        "field":"date",
        "interval":"month",
        "format":"yyyy-mm-dd"
      },
      "aggs":{
        "age_avg":{"avg":{"field":"age"}}
    }
  },
  "avg_stat":{
    "stats_bucket":{"buckets_path":"date_over_time>age_avg"}
  }
  }
}

3.6、百分位分组聚合

在所有分组中对指定的指标计算百分比。
示例:

GET /people/_doc/_search
{
 "aggs":{
    "country_term":{
      "terms":{"field":"country"  },
      "aggs":{
        "age_avg":{
          "avg":{"field":"age"}
        }
      }
    },
    
    "percent_age":{
      "percentiles_bucket":{"buckets_path":"country_term>age_avg"}
    }
  }
}

4、DocValue

DocValue原理:
聚合的场景是遍历文档,并收集对应字段的唯一词项,对这些词项做聚合处理。而使用倒排索引做这件事情代价会很高。DocValue是倒排索引的转置,其保存的是文档与其包含的词项的映射。这个数据结构可以使聚合更快、更高效并且内存友好。
DocValue是在索引时与倒排索引同时创建的,其也是基于段生成并不可改变,并会被序列化存储到磁盘中。我们可以充分利用操作系统的内存,而不是 JVM 的 Heap 。 当 working set 远小于系统的可用内存,系统会自动将 Doc Values 驻留在内存中,使得其读写十分快速;不过,当其远大于可用内存时,系统会根据需要从磁盘读取 Doc Values,然后选择性放到分页缓存中。很显然,这样性能会比在内存中差很多,但是它的大小就不再局限于服务器的内存了。

DocValue存储:
因为 Doc Values 不是由 JVM 来管理,所以 Elasticsearch 实例可以配置一个很小的 JVM Heap,这样给系统留出来更多的内存。同时更小的 Heap 可以让 JVM 更加快速和高效的回收。之前,我们会建议分配机器内存的 50% 来给 JVM Heap。但是对于 Doc Values,这样可能不是最合适的方案了。 以 64gb 内存的机器为例,可能给 Heap 分配 4-16gb 的内存更合适,而不是 32gb。
Doc Values 本质上是一个序列化的 列式存储,这种存储方式也非常便于压缩,特别是数字类型。这样可以减少磁盘空间并且提高访问速度。

DocValue启用:
Doc Values 默认对所有字段启用,除了 analyzed strings。也就是说所有的数字、地理坐标、日期、IP 和不分析( not_analyzed )字符类型都会默认开启。故可以对这些字段很高效的聚合和排序操作,当确定某些字段不会用于聚合或排序等操作,可以禁用DocValue,这样不仅节约磁盘,也会提升索引的速度。
要禁用 Doc Values ,在字段的映射(mapping)设置 doc_values: false 即可。

5、分析字符串和FieldData

Doc values 不支持 analyzed 字符串字段,因为它们不能很有效的表示多值字符串。 Doc values 最有效的是,当每个文档都有一个或几个 tokens 时, 但不是无数的,分析字符串(想象一个 PDF ,可能有几兆字节并有数以千计的独特 tokens)。
与 doc values 不同,fielddata 构建和管理 100% 在内存中,常驻于 JVM 内存堆。这意味着它本质上是不可扩展的,有很多边缘情况下要提防。
避免分析字段的另外一个原因就是:高基数字段在加载到 fielddata 时会消耗大量内存。 分析的过程会经常(尽管不总是这样)生成大量的 token,这些 token 大多都是唯一的。 这会增加字段的整体基数并且带来更大的内存压力。
一旦分析字符串被加载到 fielddata ,他们会一直在那里,直到被驱逐(或者节点崩溃)。由于这个原因,留意内存的使用情况,了解它是如何以及何时加载的,怎样限制对集群的影响是很重要的。
Fielddata 是 延迟 加载。如果你从来没有聚合一个分析字符串,就不会加载 fielddata 到内存中。此外,fielddata 是基于字段加载的, 这意味着只有很活跃地使用字段才会增加 fielddata 的负担。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349