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

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

一、Elasticsearch的聚合

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

  1. 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.   
  5.         SearchRequestBuilder responsebuilder = client.prepareSearch("iktest")  
  6.                 .setTypes("iktest").setFrom(0).setSize(250);  
  7.         AggregationBuilder aggregation = AggregationBuilders  
  8.                 .terms("agg")  
  9.                 .field("category_id")  
  10.                 .subAggregation(  
  11.                         AggregationBuilders.topHits("top").setFrom(0)  
  12.                                 .setSize(10)).size(100);  
  13.         response = responsebuilder.setQuery(QueryBuilders.boolQuery()  
  14.   
  15.         .must(QueryBuilders.matchPhraseQuery("name", "中学历史")))  
  16.                 .addSort("category_id", SortOrder.ASC)  
  17.                 .addAggregation(aggregation)// .setSearchType(SearchType.DFS_QUERY_THEN_FETCH)  
  18.                 .setExplain(true).execute().actionGet();  
  19.   
  20.         SearchHits hits = response.getHits();  
  21.   
  22.         Terms agg = response.getAggregations().get("agg");  
  23.         System.out.println(agg.getBuckets().size());  
  24.         for (Terms.Bucket entry : agg.getBuckets()) {  
  25.             String key = (String) entry.getKey(); // bucket key  
  26.             long docCount = entry.getDocCount(); // Doc count  
  27.             System.out.println("key " + key + " doc_count " + docCount);  
  28.   
  29.             // We ask for top_hits for each bucket  
  30.             TopHits topHits = entry.getAggregations().get("top");  
  31.             for (SearchHit hit : topHits.getHits().getHits()) {  
  32.                 System.out.println(" -> id " + hit.getId() + " _source [{}]"  
  33.                         + hit.getSource().get("category_name"));  
  34.                 ;  
  35.             }  
  36.         }  
  37.         System.out.println(hits.getTotalHits());  
  38.         int temp = 0;  
  39.         for (int i = 0; i < hits.getHits().length; i++) {  
  40.             // System.out.println(hits.getHits()[i].getSourceAsString());  
  41.             System.out.print(hits.getHits()[i].getSource().get("product_id"));  
  42.             // if(orderfield!=null&&(!orderfield.isEmpty()))  
  43.             // System.out.print("\t"+hits.getHits()[i].getSource().get(orderfield));  
  44.             System.out.print("\t"  
  45.                     + hits.getHits()[i].getSource().get("category_id"));  
  46.             System.out.print("\t"  
  47.                     + hits.getHits()[i].getSource().get("category_name"));  
  48.             System.out.println("\t"  
  49.                     + hits.getHits()[i].getSource().get("name"));  
  50.         }  
  51.     }  
  52. }  

以上的例子实现的是按照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.   
  3.         .must(QueryBuilders.matchPhraseQuery("name", "中学历史")))  
  4.                 .addSort("category_id", SortOrder.ASC)  
  5.                 .addAggregation(aggregation)  
  6.                                 .setPostFilter(QueryBuilders.rangeQuery("price").gt(1000).lt(5000))  
  7.                 .setExplain(true).execute().actionGet();  

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

 

五、后续学习

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

转载于:https://my.oschina.net/u/2429470/blog/795309

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/542160.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

js手机号中间四位_11位手机号码隐藏中间四位数,学会Substitute函数一键搞定!...

相信许多朋友都有见过手机号码被*号隐藏中间四位数的情况。许多地方为了保护个人信息&#xff0c;都会将手机号的中间四位数用星号代替。如上图所示&#xff0c;我们需要将原来的手机号码&#xff0c;通过*号的方式变为隐藏后的加密模式。下面我们就来学习一下如何利用substitu…

python 整数最大_Python程序使用floor()方法查找最大整数

python 整数最大The greatest integer function is a function (real numbers function) to itself that is defined as follows: it sends any real number to the largest integer that is less than or equal to it. 最大整数函数是一个对其自身定义的函数(实数函数)&#x…

selinux对ftp的影响

1.啥是selinux 安全增强型Linux&#xff08;Security-Enhanced Linux&#xff09;简称selinux&#xff0c;它是一个Linux内核模块&#xff0c;也是Linux的一个安全子系统。 selinux的状态&#xff1a; Enforcing:强制模式&#xff0c;在selinux运作时&#xff0c;已经开始限制d…

ES6的class方法基本用法

为什么80%的码农都做不了架构师&#xff1f;>>> 在ES5中我们通常通过构造函数&#xff0c;定义并生成新对象。 例如: function Point(name,age){this.namename;this.ageage;}Point.prototype{Who:function(){return "My name is "this.name",My age…

celery的中文_celery异步任务框架

目录Celery一、官方二、Celery异步任务框架Celery架构图消息中间件任务执行单元任务结果存储三、使用场景四、Celery的安装配置五、两种celery任务结构&#xff1a;提倡用包管理&#xff0c;结构更清晰七、Celery执行异步任务包架构封装八、基本使用celery.py 基本配置tasks.py…

关于linux mv指令机制

最近在mv文件的时候&#xff0c;操作失误将生产服务器一个1TB的文件夹mv到了/opt/test目录&#xff0c;因为最后/opt/目录被沾满所以1TB的文件夹没有迁移过来&#xff0c;写入了30GB数据到了/opt/test目录&#xff0c;因为系统分区被沾满&#xff0c;所以把test目录给删除了。 …

数据库的管理

1. 数据库的简介 定义&#xff1a;数据库&#xff08;Database&#xff09;就是一种按数据结构来组织&#xff0c;存储和管理数据的仓库&#xff0c;其中包含数据挖掘&#xff0c;大数据信息的推送。 mariadb数据库管理系统是mysql的一个分支&#xff0c;主要由开源社区在维护&…

C#中的Dictionary字典类介绍(转载)

C#中的Dictionary字典类介绍 关键字&#xff1a;C# Dictionary 字典 作者&#xff1a;txw1958原文&#xff1a;http://www.cnblogs.com/txw1958/archive/2012/11/07/csharp-dictionary.html 说明 必须包含名空间System.Collection.Generic Dictionary里面的每一个元素都…

高速缓存dns

1. DNS&#xff1a; Domain Name System&#xff0c;域名系统。 万维网上作为域名和IP地址相互映射的一个分布式数据库&#xff0c;能够使用户更方便的访问互联网。他主要负责把域名和IP的相互转换&#xff0c;DNS运行与TCP|UDP的53端口上。 2. 高速缓存DNS&#xff1a;DNS服务…

Apache服务配置

1. apache 企业中常用的web服务。用来提供http&#xff1a;//&#xff08;超文本传输协议&#xff09; 基础信息&#xff1a; 主配置目录&#xff1a; /etc/httpd/conf 主配置文件&#xff1a; /etc/httpd/conf/httpd.conf 子配置目录&#xff1a; /etc/httpd/conf.d/ 子配置文…

如何安装Genymotion虚拟机以及Genmotion的eclipse插件

---内容开始--- - 首先去genymotion的官网去下载其安装文件 资源下载 Genymotion官网必须注册一个账号这个账号安装之后还有用的&#xff0c;用户名最好用网易126邮箱注册----我下载的是2.8.0的版本(注&#xff1a;注册前先开个代理服务器不然页面打不开下载时最好用迅雷下载这…

squid服务配置(正向、反向代理)

代理&#xff1a; 就是代理网络用户去取得网络信息。 Squid是一种用来缓冲Internet数据的软件。安装Squid服务实现代理缓存服务器功能。 正向代理&#xff1a;意思是一个位于客户端和原始服务器之间的服务器&#xff0c;为了从原始服务器取得内容&#xff0c;客户端向代理发送一…

c语言getchar函数_C语言中带有示例的getchar()函数

c语言getchar函数C语言中的getchar()函数 (getchar() function in C) The getchar() function is defined in the <stdio.h> header file. getchar()函数在<stdio.h>头文件中定义。 Prototype: 原型&#xff1a; int getchar(void);Parameters: FILE *filename(f…

python及pycharm

1.python简介&#xff1a; Python是一种计算机程序设计语言。是一种动态的、面向对象的脚本语言&#xff0c;最初被设计用于编写自动化脚本(shell)&#xff0c;随着版本的不断更新和语言新功能的添加&#xff0c;越来越多被用于独立的、大型项目的开发。 python最重要的功能&am…

移动端适配方案(上)

转载自:https://github.com/riskers/blog/issues/17 要搞懂移动端的适配问题&#xff0c;就要先搞明白像素和视口。 像素 在移动端给一个元素设置 width:200px 时发生了什么&#xff1f;这里的px到底是多长呢&#xff1f;像素是网页布局的基础&#xff0c;但是我们一直在用直觉…

oracle sql 语句如何插入全年日期?

为什么80%的码农都做不了架构师&#xff1f;>>> oracle sql 语句如何插入全年日期&#xff1f; create table BSYEAR (d date); insert into BSYEAR select to_date(20030101,yyyymmdd)rownum-1 from all_objects where rownum < to_char(to_date(20031231,…

java基础——java基本运算

java基本运算 转载于:https://www.cnblogs.com/zhouj/p/6132535.html

【Java】MybatisPlus

MybatisPlus MybatisPlus是在mybatis基础上的一个增强型工具。它对mybatis的一些操作进行了简化&#xff0c;能够提高开发的效率。 springboot整合了mybatis之后&#xff0c;其实已经非常方便了&#xff0c;只需要导入mybatis的包后&#xff0c;在配置文件中编写数据源信息&a…

更新SQL Server实例所有数据库表统计信息

引出问题 自从上次菜鸟为老鸟解决了《RDS SQL SERVER 解决中文乱码问题》问题&#xff0c;老鸟意犹未尽&#xff0c;决定再想个招来刁难刁难菜鸟&#xff1a;“我最近做T-SQL性能调优的时候&#xff0c;经常发现执行计划中的统计信息不准确&#xff0c;导致SQL Server查询性能低…

从0开始搭建SQL Server AlwaysOn 第四篇(配置异地机房节点)

从0开始搭建SQL Server AlwaysOn 第四篇&#xff08;配置异地机房节点&#xff09; 第一篇http://www.cnblogs.com/lyhabc/p/4678330.html第二篇http://www.cnblogs.com/lyhabc/p/4682028.html第三篇http://www.cnblogs.com/lyhabc/p/4682986.html第四篇http://www.cnblogs.com…