一、Elasticsearch的聚合

ES的聚合相当于关系型数据库里面的group by,例如查找在性别字段男女人数的多少并且按照人数的多少进行排序,在使用mysql的时候,可以使用如下的句子

select sex,count(*) from table_name group by sex order by count(*)

在ES里面想要实现这种的语句,就叫做聚合,比如这种的聚合使用DSL语句的话如下所示:

  1. GET /index/type/_search

  2. {

  3. "size" : 0,

  4. "aggs" : {

  5. "agg_sex" : {

  6. "terms" : {

  7. "field" : "sex"

  8. }

  9. }

  10. }

  11. }

这样就可以实现最以上例子中的group by的功能,当然这只是最简单的聚合的使用,在ES里面的聚合有多重多样的,比如说有度量聚合,可以用来计算某一个字段的平均值最大值等,在此给出一个简单的度量聚合的例子

  1. GET /index/type/_search

  2. {

  3. "size" : 0,

  4. "aggs": {

  5. "agg_sex": {

  6. "terms": {

  7. "field": "sex"

  8. },

  9. "agg_age": {

  10. "avg_age": {

  11. "avg": {

  12. "field": "age"

  13. }

  14. }

  15. }

  16. }

  17. }

  18. }

这个DSL语句就是将先按照性别进行聚合,并且对不同的性别给出一个平均的年龄,使用之后ES的给出结果如下所示:

  1. {

  2. ...

  3. "aggregations": {

  4. "agg_sex": {

  5. "buckets": [

  6. {

  7. "key": "male",

  8. "doc_count": 4,

  9. "avg_age": {

  10. "value": 25

  11. }

  12. },

  13. {

  14. "key": "female",

  15. "doc_count": 2,

  16. "avg_age": {

  17. "value": 23

  18. }

  19. }

  20. ]

  21. }

  22. }

  23. ...

  24. }

在度量聚合里面有min,max,sum,avg聚合等,还有stats,extern_stats等聚合,其中stats的聚合给出的信息会包括min,max,count等基本的信息,更多详细的细节请参考ES官网给出的指导https://www.elastic.co/guide/en/elasticsearch/guide/current/aggregations.html

以上只是给出的度量聚合,但是在实际中我们经常使用的是桶聚合,什么是桶聚合呢,个人理解就是将符合某一类条件的文档选出来,所有的某一类的聚合就称为桶,例如你可以按照某一个分类将所有的商品聚合起来,这种情况下就可以认为某一个分类的商品称为一个桶,下面将详细介绍几个常用的桶聚合,并且会给出java使用时候的代码

二、桶聚合

桶聚合是在实际使用时候用处比较多的一种聚合,简单的桶聚合包括term聚合,range聚合,date聚合,IPV4聚合等聚合,因为自己使用的仅仅是其中的三个,在此就简单的介绍三个,分别是term聚合,range聚合,以及date聚合

1、term聚合

term聚合就是第一部分给出的简单的例子,按照不同的字段进行聚合

2、range聚合

range聚合为按照自定义的范围来创造桶,将每一个范围的数据进行聚合,并且这个聚合一般适用于字段类型为long或者int,double的字段,可以进行直接的聚合,例如,我们想统计不同年龄段的人的个数,DSL如下所示:

  1. GET /index/type/_search

  2. {

  3. "aggs" : {

  4. "agg_age" : {

  5. "field":"age"

  6. "ranges" : [

  7. { "to" : 18},

  8. { "from" : 19,"to" : 50},

  9. {"from" : 51}

  10. ]

  11. }

  12. }

  13. }

3、daterange聚合

date range聚合和range聚合类似,但是所使用的类型是datetime这种类型,使用的时候与range有些区别,给出一个简单的使用date range聚合的DSL例子,如下所示:

  1. GET /index/type/_search

  2. {

  3. "aggs" : {

  4. "agg_year" : {

  5. "field":"date"

  6. "ranges" : [

  7. { "to" : "2008-08-08"},

  8. { "from" : "2008-08-09","to" : "2012-09-01"},

  9. {"from" : "2012-09-02"}

  10. ]

  11. }

  12. }

  13. }

上面的DSL是简单的按照时间格式进行区间的聚合,但是有些时候我们可能想要一些按照年份聚合或者月份聚合的情况,这个时候应该怎么办呢?在date range里面可以指定日期的格式,例如下面给出一个按照年份进行聚合的例子:

  1. GET /index/type/_search

  2. {

  3. "aggs" : {

  4. "agg_year" : {

  5. "field":"date"

  6. "format":"YYYY",

  7. "ranges" : [

  8. { "to" : "1970"},

  9. { "from" : "1971","to" : "2012"},

  10. {"from" : "2013"}

  11. ]

  12. }

  13. }

  14. }

我们可以指定格式来进行聚合

三、对于上述三种聚合java的实现

首先先给出一个具体的使用ES java api实现搜索并且聚合的完整例子,例子中使用的是terms聚合,按照分类id,将所有的分类进行聚合

  1. public void aggsearch() {

  2. init();

  3. SearchResponse response = null;

  4. SearchRequestBuilder responsebuilder = client.prepareSearch("iktest")

  5. .setTypes("iktest").setFrom(0).setSize(250);

  6. AggregationBuilder aggregation = AggregationBuilders

  7. .terms("agg")

  8. .field("category_id")

  9. .subAggregation(

  10. AggregationBuilders.topHits("top").setFrom(0)

  11. .setSize(10)).size(100);

  12. response = responsebuilder.setQuery(QueryBuilders.boolQuery()

  13. .must(QueryBuilders.matchPhraseQuery("name", "中学历史")))

  14. .addSort("category_id", SortOrder.ASC)

  15. .addAggregation(aggregation)// .setSearchType(SearchType.DFS_QUERY_THEN_FETCH)

  16. .setExplain(true).execute().actionGet();

  17. SearchHits hits = response.getHits();

  18. Terms agg = response.getAggregations().get("agg");

  19. System.out.println(agg.getBuckets().size());

  20. for (Terms.Bucket entry : agg.getBuckets()) {

  21. String key = (String) entry.getKey(); // bucket key

  22. long docCount = entry.getDocCount(); // Doc count

  23. System.out.println("key " + key + " doc_count " + docCount);

  24. // We ask for top_hits for each bucket

  25. TopHits topHits = entry.getAggregations().get("top");

  26. for (SearchHit hit : topHits.getHits().getHits()) {

  27. System.out.println(" -> id " + hit.getId() + " _source [{}]"

  28. + hit.getSource().get("category_name"));

  29. ;

  30. }

  31. }

  32. System.out.println(hits.getTotalHits());

  33. int temp = 0;

  34. for (int i = 0; i < hits.getHits().length; i++) {

  35. // System.out.println(hits.getHits()[i].getSourceAsString());

  36. System.out.print(hits.getHits()[i].getSource().get("product_id"));

  37. // if(orderfield!=null&&(!orderfield.isEmpty()))

  38. // System.out.print("\t"+hits.getHits()[i].getSource().get(orderfield));

  39. System.out.print("\t"

  40. + hits.getHits()[i].getSource().get("category_id"));

  41. System.out.print("\t"

  42. + hits.getHits()[i].getSource().get("category_name"));

  43. System.out.println("\t"

  44. + hits.getHits()[i].getSource().get("name"));

  45. }

  46. }

  47. }

以上的例子实现的是按照category_id字段进行分类的聚合,并且将在name字段查找包含“中学历史”的这个词,并且按照category_id进行排序,在此给出的只是一个搜索实现的函数,里面的字段名字,以及index,type等很多字段均为自己定义的index里面的名字,上面给出的是terms聚合时候的代码,如果使用的是range聚合或者date range聚合,只需要改变aggregation就可以

使用range聚合的时候:

  1. aggregation = AggregationBuilders.range("agg")

  2. .field("price").addUnboundedTo(50)

  3. .addRange(51, 100).addRange(101, 1000)

  4. .addUnboundedFrom(1001);

使用date range聚合的时候:

  1. aggregation = AggregationBuilders.dateRange("agg")

  2. .field("date").format("yyyy")

  3. .addUnboundedTo("1970").addRange("1970", "2000")

  4. .addRange("2000", "2010").addUnboundedFrom("2009");

以上所有的聚合均是先过滤搜索,然后对于召回得到的结果进行一个聚合,例如我们在name字段搜索中学历史这个词,最终得到四个分类分别为1,2,3,4那么聚合的时候就是这四个分类,但是有时候我们可能会需要对于搜索的结果进行一个过滤,但是我们不想对聚合的结果进行过滤,那么我们就要使用一下的部分了

四、先聚合再过滤

以上将的简单的聚合都是先过滤或者搜索,然后对结果进行聚合,但是有时候我们需要先进行聚合,然后再对结果进行一次过滤,但是我们不希望这个时候聚合会发生变化,什么时候会遇到这种情况呢,我们以美团为例做一个说明,在主页我们直接点解美食,得到如下所示的图

点美食之后出现全部的分类,包括各种的菜系,下面我们点一个具体的菜系

从程序上来说,我们点第二次菜系的时候,出现的所有的菜品均是烤串之类的菜品了,但是在分类里面还是所有的分类都会有,如果按照之前的ES的聚合,会将所有搜索出来的品的分类进行一个聚合,但是点完烤串之后,所有的分类都是烤串了,那么就应该所有的分类只有一个烤串了,不应该有其他的,这样的话肯定是不可以的,那么如何才能实现这种聚合的,这个时候我们就需要先聚合,然后进行再次的过滤,但是过滤的时候并不影响之前的聚合结果,这就是先聚合再过滤,在ES里面也有这种情况的考虑,这个时候使用的是postfilter

postfilter解决了仅仅过滤搜索结果,但是并不影响聚合结果,下面给出一个java使用时候的例子以及比较

函数一为第三部分给出的完整的搜索函数,按照分类聚合

函数二的改变只是对于一的

  1. response = responsebuilder.setQuery(QueryBuilders.boolQuery()

  2. .must(QueryBuilders.matchPhraseQuery("name", "中学历史")))

  3. .addSort("category_id", SortOrder.ASC)

  4. .addAggregation(aggregation)

  5. .setPostFilter(QueryBuilders.rangeQuery("price").gt(1000).lt(5000))

  6. .setExplain(true).execute().actionGet();

添加了按照price进行过滤,最后结果显示,聚合的结果两次完全一样,但是函数二召回的结果为函数一结果的子集。

五、后续学习

如何多次的过滤以及召回,比如先过滤后聚合再过滤再次聚合然后再次过滤这种的应该如何实现,需要学习。

Elasticsearch过滤与聚合的先后顺序java实现相关推荐

  1. es 时间过滤java,Elasticsearch过滤与聚合的先后顺序java实现

    一.Elasticsearch的聚合 ES的聚合相当于关系型数据库里面的group by,例如查找在性别字段男女人数的多少并且按照人数的多少进行排序,在使用MySQL的时候,可以使用如下的句子 sel ...

  2. 深耕ElasticSearch - 过滤和聚合/多桶排序

    文章目录 1. 数据准备 2. 过滤和聚合 2.1 过滤 2.2 过滤桶 3. 多桶排序 3.1 内置排序 3.2 按度量排序 4. 近似聚合 1. 数据准备 1.创建索引映射mapping : PU ...

  3. java操作es聚合操作并显示其他字段_深入浅析Elasticsearch中的聚合操作

    如果写过Elasticsearch的聚合操作DSL,都知道它非常的繁琐,很简单的业务就导致异常复杂的json.因为它的聚合操作是嵌套的,一个聚合的输出可以是另一个聚合的输入,并且聚合还支持pipeli ...

  4. java操作es聚合操作并显示其他字段_java使用elasticsearch分组进行聚合查询过程解析...

    这篇文章主要介绍了java使用elasticsearch分组进行聚合查询过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 java连接elas ...

  5. [Elasticsearch] 过滤查询以及聚合(Filtering Queries and Aggregations)

    原文地址为: [Elasticsearch] 过滤查询以及聚合(Filtering Queries and Aggregations) 本章翻译自Elasticsearch官方指南的Filtering ...

  6. Elasticsearch查询和聚合基本语法

    1.概述 Elasticsearch主要的查询语法包括URI查询和body查询,URI比较轻便快速,而body查询作为一种json的格式化查询,可以有许多限制条件.本文主要介绍结构化查询的query, ...

  7. Java前端顺序,java种初始化顺序

    java类初始化顺序 java类初始化顺序 先父类的static-->父类的字段或对象-->父类的构造函数-->子类的static-->子类的字段或对象-->子类的构造函 ...

  8. 敏感词过滤 - DFA算法[确定有穷自动机]的Java 实现

    文章目录 敏感词过滤 - DFA算法[确定有穷自动机]的Java 实现 敏感词过滤 - DFA算法[确定有穷自动机]的Java 实现 代码如下 package utils;import com.goo ...

  9. ElasticSearch查询所有数据restful api以及java代码实现

    elasticsearch查询所有数据restful api以及java代码实现 restful api实现如下: get http://192.168.1.111:9200/film/dongzuo ...

最新文章

  1. linux磁盘i o跟踪,利用zabbix动态监控磁盘I/O
  2. TabLayout和ViewPager
  3. C#ASP.NET执行BAT批处理代码
  4. 记一次SAP开发工程师给微软Azure报incident的体验
  5. Django的View(视图)
  6. 【论文写作】毕业论文写作套路之参考文献
  7. activiti 学习由浅入深
  8. H5商城与小程序商城哪个好_应该怎么选择_OctShop
  9. 安装VS2008 SP1
  10. android国家代码/国际电话区号选择器
  11. ASP.NET 氚云平台集成Dome
  12. android 平板怎么截图,小米平板4怎么截图 小米平板4截屏的三种方法
  13. android模拟器字体,真正免root的ifont字体软件详细使用教程
  14. 看看月光blog2014年都搞些啥
  15. SEO又一新站Cosplay网站
  16. 从零开始画自己的DAG作业依赖图(三)--节点连线简单版
  17. TranUnet 复现[Errno 2] No such file or directory: ‘./model/TU_Synapse224/TU_pretrain_ViT-B_16_skip3_ep
  18. Java选择题(七)
  19. 问题 C: 网格涂色
  20. 网络视频教程(共57个)全实战过程

热门文章

  1. java吧王者_java单排上王者!(一) java内存
  2. scrapy框架_入门Scrapy框架看这一篇文章就够了
  3. 分享一个学习git的图形化学习网站-Learn Git Branching参考答案整理
  4. 又见程序员精神——有感于谷歌一天一夜开发春运交通图
  5. linux多线程计算pi,使用蒙特卡洛方法多线程计算pi值
  6. 刘子佼 mysql 下载_MySQL数据管理之备份恢复案例解析 23讲 Mysql备份恢复实战 视频教程...
  7. pb公共变量怎么找_阿迪达斯的4D怎么就火不起来呢?
  8. 2021年高考成绩查询贵州分数线,2021年贵州省高考分数线
  9. html文字超链接不让变色,css不让超链接变色怎么设置?
  10. 12天背诵楞严咒的技巧_背诵楞严咒的技巧