ElasticSearch聚合分析API

标签: 搜索 Elasticsearch 分析 聚合 | 发表时间:2016-04-11 03:18 | 作者:migrant620
分享到:
出处:http://www.tianyiqingci.com
  aggs

前言

说完了ES的索引与检索,接着再介绍一个ES高级功能API – 聚合(Aggregations),聚合功能为ES注入了统计分析的血统,使用户在面对大数据提取统计指标时变得游刃有余。同样的工作,你在hadoop中可能需要写mapreduce或hive,在mongo中你必须得用大段的mapreduce脚本,而在ES中仅仅调用一个API就能实现了。

开始之前,提醒老司机们注意,ES原有的聚合功能Facets在新版本中将被正式被移除,抓紧时间用Aggregations替换Facets吧。Facets真的很慢!

1 关于Aggregations

Aggregations的部分特性类似于SQL语言中的group by,avg,sum等函数。但Aggregations API还提供了更加复杂的统计分析接口。

掌握Aggregations需要理解两个概念:

  • 桶(Buckets):符合条件的文档的集合,相当于SQL中的group by。比如,在users表中,按“地区”聚合,一个人将被分到北京桶或上海桶或其他桶里;按“性别”聚合,一个人将被分到男桶或女桶
  • 指标(Metrics):基于Buckets的基础上进行统计分析,相当于SQL中的count,avg,sum等。比如,按“地区”聚合,计算每个地区的人数,平均年龄等

对照一条SQL来加深我们的理解:

SELECT COUNT(color) FROM table GROUP BY color

GROUP BY相当于做分桶的工作,COUNT是统计指标。

下面介绍一些常用的Aggregations API。

2 Metrics

2.1 AVG

求均值。

GET /company/employee/_search
{
    "aggs" : {
        "avg_grade" : { "avg" : { "field" : "grade" } }
    }
}

执行结果

{
    "aggregations": {
        "avg_grade": {"value": 75}
    }
}

其他的简单统计API,如valuecount, max,min,sum作用与SQL中类似,就不一一解释了。

2.2 Cardinality

cardinality的作用是先执行类似SQL中的distinct操作,然后再统计排重后集合长度。得到的结果是一个近似值,因为考虑到在大量分片中排重的性能损耗Cardinality算法并不会load所有的数据。
{
    "aggs" : {
	"author_count" : {
	    "cardinality" : {"field" : "author"}
	}
    }
}

2.3 Stats

返回聚合分析后所有有关stat的指标。具体哪些是stat指标是ES定义的,共有5项。

{
    "aggs" : {
	"grades_stats" : { "stats" : { "field" : "grade" } }
    }
}

执行结果

{
    "aggregations": {
	"grades_stats": {
	    "count": 6,
	    "min": 60,
	    "max": 98,
	    "avg": 78.5,
	    "sum": 471
	}
    }
}

2.4 Extended Stats

返回聚合分析后所有指标,比Stats多三个统计结果:平方和、方差、标准差

{
    "aggs" : {
	"grades_stats" : { "extended_stats" : { "field" : "grade" } }
    }
}

执行结果

{
    "aggregations": {
	"grade_stats": {
	    "count": 9,
	    "min": 72,
	    "max": 99,
	    "avg": 86,
	    "sum": 774,
	    # 平方和
	    "sum_of_squares": 67028,
	    # 方差
	    "variance": 51.55555555555556,
	    # 标准差
	    "std_deviation": 7.180219742846005,
	    #平均加/减两个标准差的区间,用于可视化你的数据方差
	    "std_deviation_bounds": {
		"upper": 100.36043948569201,
		"lower": 71.63956051430799
	    }
	}
    }
}

2.5 Percentiles

百分位法统计,举例,运维人员记录了每次启动系统所需要的时间,或者,网站记录了每次用户访问的页面加载时间,然后对这些时间数据进行百分位法统计。我们在测试报告中经常会看到类似的统计数据

{
    "aggs" : {
	"load_time_outlier" : {
	    "percentiles" : {"field" : "load_time"}
	}
    }
}

结果是

{
    "aggregations": {
	"load_time_outlier": {
	    "values" : {
		"1.0": 15,
		"5.0": 20,
		"25.0": 23,
		"50.0": 25,
		"75.0": 29,
		"95.0": 60,
		"99.0": 150
	    }
	}
    }
}

加载时间在15ms内的占1%,20ms内的占5%,等等。

我们还可以指定百分位的指标,比如只想统计95%、99%、99.9%的加载时间

{
    "aggs" : {
	"load_time_outlier" : {
	    "percentiles" : {
		"field" : "load_time",
		"percents" : [95, 99, 99.9]
	    }
	}
    }
}

2.6 Percentile Ranks

Percentile API中,返回结果values中的key是固定的0-100间的值,而Percentile Ranks返回值中的value才是固定的,同样也是0到100。例如,我想知道加载时间是15ms与30ms的数据,在所有记录中处于什么水平,以这种方式反映数据在集合中的排名情况。

{
    "aggs" : {
	"load_time_outlier" : {
	    "percentile_ranks" : {
		"field" : "load_time",
		"values" : [15, 30]
	    }
	}
    }
}

执行结果

{
    "aggregations": {
	"load_time_outlier": {
	    "values" : {
		"15": 92,
		"30": 100
	    }
	}
    }
}

3 Bucket

3.1 Filter

先过滤后聚合,类似SQL中的where,也有点象group by后加having。比如

{
    "aggs" : {
	"red_products" : {
	    "filter" : { "term": { "color": "red" } },
	    "aggs" : {
		"avg_price" : { "avg" : { "field" : "price" } }
	    }
	}
    }
}

只统计红色衣服的均价。

3.2 Range

反映数据的分布情况,比如我想知道小于50,50到100,大于100的数据的个数。

{
    "aggs" : {
	"price_ranges" : {
	    "range" : {
		"field" : "price",
		"ranges" : [
		    { "to" : 50 },
		    { "from" : 50, "to" : 100 },
		    { "from" : 100 }
		]
	    }
	}
    }
}

执行结果

{
    "aggregations": {
	"price_ranges" : {
	    "buckets": [
		{"to": 50, "doc_count": 2},
		{"from": 50, "to": 100, "doc_count": 4},
		{"from": 100, "doc_count": 4}
	    ]
	}
    }
}

3.3 Missing

我们想找出price字段值为空的文档的个数。

{
    "aggs" : {
	"products_without_a_price" : {
	    "missing" : { "field" : "price" }
	}
    }
}

执行结果

{
    "aggs" : {
	"products_without_a_price" : {
	    "doc_count" : 10
	}
    }
}

3.4 Terms

针对某个字段排重后统计个数。

{
    "aggs" : {
	"genders" : {
	    "terms" : { "field" : "gender" }
	}
    }
}

执行结果

{
    "aggregations" : {
	"genders" : {
	    "doc_count_error_upper_bound": 0,
	    "sum_other_doc_count": 0,
	    "buckets" : [
		{"key" : "male","doc_count" : 10},
		{"key" : "female","doc_count" : 10},
	    ]
	}
    }
}

3.5 Date Range

针对日期型数据做分布统计。

{
    "aggs": {
	"range": {
	    "date_range": {
		"field": "date",
		"format": "MM-yyy",
	        "ranges": [
		    { "to": "now-10M/M" },
		    { "from": "now-10M/M" }
		]
	    }
	}
    }
}

这里的format参数是指定返回值的日期格式。

执行结果

{
    "aggregations": {
	"range": {
	    "buckets": [
		{"to": 1.3437792E+12, "to_as_string": "08-2012","doc_count": 7},
		{"from": 1.3437792E+12, "from_as_string": "08-2012","doc_count": 2}
	    ]
	}
    }
}

3.6 Global Aggregation

指定聚合的作用域与查询的作用域没有关联。因此返回结果中query命中的文档,与聚合的的统计结果是没有关系的。

{
    "query" : {
	"match" : { "title" : "shirt" }
    },
    "aggs" : {
	"all_products" : {
	    "global" : {},
	    "aggs" : {
		"avg_price" : { "avg" : { "field" : "price" } }
	    }
	}
    }
}

3.7 Histogram

跟range类似,不过Histogram不需要你指定统计区间,只需要提供一个间隔区间的值。好象不太好理解,看个例子就全明白了。

比如,以50元为一个区间,统计每个区间内的价格分布

{
    "aggs" : {
	"prices" : {
	    "histogram" : {
		"field" : "price",
		"interval" : 50
	    }
	}
    }
}

执行结果

{
    "aggregations": {
	"prices" : {
	    "buckets": [
		{"key": 0, "doc_count": 2},
		{"key": 50, "doc_count": 4},
		{"key": 100, "doc_count": 0},
		{"key": 150, "doc_count": 3}
	    ]
	}
    }
}

由于最高的价格没超过200元,因此最后的结果自动分为小于50,50到100,100到150,大于150共四个区间的值。

100到150区间的文档数为0个,我们想在返回结果中自动过滤该值,或者过滤偏小的值,可以添加一个参数”min_doc_count”,比如

{
    "aggs" : {
	"prices" : {
	    "histogram" : {
		"field" : "price",
		"interval" : 50,
		"min_doc_count" : 1
	    }
	}
    }
}

返回结果会自动将你设定的值以下的统计结果过滤出去。

3.8 Date Histogram

使用方法与Histogram类似,只是聚合的间隔区间是针对时间类型的字段。

{
    "aggs" : {
	"articles_over_time" : {
	    "date_histogram" : {
		"field" : "date",
		"interval" : "1M",
		"format" : "yyyy-MM-dd"
	    }
	}
    }
}

执行结果

{
    "aggregations": {
	"articles_over_time": {
	    "buckets": [
		{"key_as_string": "2013-02-02","key": 1328140800000, "doc_count": 1},
		{"key_as_string": "2013-03-02","key": 1330646400000, "doc_count": 2},
		...
	    ]
	}
    }
}

3.9 IPv4 range

由于ES是一个企业级的搜索和分析的解决方案,在做大量数据统计分析时比如用户访问行为数据,会采集用户的IP地址,类似这样的数据(还有地理位置数据等),ES也提供了最直接的统计接口。

{
    "aggs" : {
	"ip_ranges" : {
	    "ip_range" : {
		"field" : "ip",
		"ranges" : [
		    { "to" : "10.0.0.5" },
		    { "from" : "10.0.0.5" }
		]
	    }
	}
    }
}

执行结果

{
    "aggregations": {
	"ip_ranges": {
	    "buckets" : [
		{"to": 167772165, "to_as_string": "10.0.0.5","doc_count": 4},
		{"from": 167772165,"from_as_string": "10.0.0.5","doc_count": 6}
	    ]
	}
    }
}

3.10 Return only aggregation results

在统计分析时我们有时候并不需要知道命中了哪些文档,只需要将统计的结果返回给我们。因此我们可以在request body中添加配置参数size。

curl -XGET 'http://localhost:9200/twitter/tweet/_search' -d '{
    "size": 0,
        "aggregations": {
	    "my_agg": {
	        "terms": {"field": "text"}
            }
    }
}
'

4 聚合缓存

ES中经常使用到的聚合结果集可以被缓存起来,以便更快速的系统响应。这些缓存的结果集和你掠过缓存直接查询的结果是一样的。因为,第一次聚合的条件与结果缓存起来后,ES会判断你后续使用的聚合条件,如果聚合条件不变,并且检索的数据块未增更新,ES会自动返回缓存的结果。

注意聚合结果的缓存只针对size=0的请求(参考3.10章节),还有在聚合请求中使用了动态参数的比如Date Range中的now(参考3.5章节),ES同样不会缓存结果,因为聚合条件是动态的,即使缓存了结果也没用了。

 

写在最后,截止到这篇文章,我们对ES的基础功能有了一个大概的认识了,作为一个进阶式的技术文章,我忽略了ES很多高级的功能(比如之前提到过的地理位置数据的检索统计,搜索推荐等),留在以后慢慢补充吧。距离构建我们心目中的高级搜索平台仍有很长的路要走,让我们继续努力。

未完待续…

相关 [elasticsearch 聚合 分析] 推荐:

ElasticSearch聚合分析API

- - 大涌日志|智能金融唠叨
说完了ES的索引与检索,接着再介绍一个ES高级功能API – 聚合(Aggregations),聚合功能为ES注入了统计分析的血统,使用户在面对大数据提取统计指标时变得游刃有余. 同样的工作,你在hadoop中可能需要写mapreduce或hive,在mongo中你必须得用大段的mapreduce脚本,而在ES中仅仅调用一个API就能实现了.

关于Elasticsearch里面聚合group的坑

- - ITeye博客
原来知道Elasticsearch在分组聚合时有一些坑但没有细究,今天又看了遍顺便做个笔记和大家分享一下. 我们都知道Elasticsearch是一个分布式的搜索引擎,每个索引都可以有多个分片,用来将一份大索引的数据切分成多个小的物理索引,解决单个索引数据量过大导致的性能问题,另外每个shard还可以配置多个副本,来保证高可靠以及更好的抗并发的能力.

Elasticsearch 分片交互过程分析

- - 编程语言 - ITeye博客
一、Elasticseach如何将数据存储到分片中. 问题:当我们要在ES中存储数据的时候,数据应该存储在主分片和复制分片中的哪一个中去;当我们在ES中检索数据的时候,又是怎么判断要查询的数据是属于哪一个分片. 数据存储到分片的过程是一定规则的,并不是随机发生的. 规则:shard = hash(routing) % number_of_primary_shards.

elasticsearch原理之搜索与聚合之谜

- - 开源软件 - ITeye博客
满足海量数据实时聚合要求的数据库不多,比较常见的有这么几种:. Lucene构建的“搜索引擎”:. Elasticsearch,但是聚合逻辑是自己实现的),. 其中Elasticsearch是目前市场上比较很少有的,能够在检索加载和分布式计算三个方面都做得一流的数据库. 它使用了很多技术来达到飞一般的速度.

Elasticsearch过滤与聚合的先后顺序java实现

- - 开源软件 - ITeye博客
一、Elasticsearch的聚合. ES的聚合相当于关系型数据库里面的group by,例如查找在性别字段男女人数的多少并且按照人数的多少进行排序,在使用mysql的时候,可以使用如下的句子. 在ES里面想要实现这种的语句,就叫做聚合,比如这种的聚合使用DSL语句的话如下所示:. 这样就可以实现最以上例子中的group by的功能,当然这只是最简单的聚合的使用,在ES里面的聚合有多重多样的,比如说有度量聚合,可以用来计算某一个字段的平均值最大值等,在此给出一个简单的度量聚合的例子.

ELK(ElasticSearch, Logstash, Kibana)搭建实时日志分析平台

- - 编程语言 - ITeye博客
在搜索ELK资料的时候,发现这篇文章比较好,于是摘抄一小段:. 以下内容来自: http://baidu.blog.51cto.com/71938/1676798. 日志主要包括系统日志、应用程序日志和安全日志. 系统运维和开发人员可以通过日志了解服务器软硬件信息、检查配置过程中的错误及错误发生的原因.

使用ELK(Elasticsearch + Logstash + Kibana) 搭建日志集中分析平台实践

- - SegmentFault 最新的文章
Logstash:负责日志的收集,处理和储存. Elasticsearch:负责日志检索和分析. Kibana:负责日志的可视化. 2015年08月31日 - 初稿. 阅读原文 - http://wsgzao.github.io/post/elk/. CentOS 7.x安装ELK(Elasticsearch+Logstash+Kibana) - http://www.chenshake.com/centos-install-7-x-elk-elasticsearchlogstashkibana/.

分析聚合数据的SDK

- - Solidot
Aveline Swan上周发现聚合数据(juhe.cn)的 SDK会偷偷上传用户通讯录至服务器,虽然聚合数据随后更新了SDK关闭了上传用户通讯录,但Swan指出在产品端更新SDK是个漫长的过程,旧版的SDK仍然在收集用户通讯录,而且合数据服务器上用于接收上传的通讯录的接口并没有被删掉,仍然能正常处理数据.

聚合新闻Flipboard 、 ZAKER竞品分析

- - 人人都是产品经理
庞大的用户基础,移动互联时代的新闻传播方式依然发生着巨大变化. 对比杂志类APP分析中,可以看出Flipboard和Zaker占据着首席,一个是海归派,一个是本地通,UV表现不俗. Flipboard和Zaker同是杂志类新闻资讯类产品,面向用户对象类似,同时产品还是各有自己的特点. 注重的细节以及地域等因素各有千秋.

[译]elasticsearch mapping

- - an74520的专栏
es的mapping设置很关键,mapping设置不到位可能导致索引重建. 请看下面各个类型介绍^_^. 每一个JSON字段可以被映射到一个特定的核心类型. JSON本身已经为我们提供了一些输入,支持 string,  integer/ long,  float/ double,  boolean, and  null..