Elasticsearch强大的聚合功能Facet
在常规数据库中,我们都知道有一个sql就是group,分组。如果主表只有对应的一个列记录的分组的ID,那么还好统计,比如说每本书book表,有一个分类catId,记录是属于哪一类的书,那么直接按照catId进行分组即可。可是在实际应用种,并非如此简单。一本书往往属于多个分类,比如:某本书既属于科技类书,又属于儿童类书,要求按照这两种条件进行筛选,都能筛选出来,如果要求按照分类进行统计数量,数据库怎么group?我们且抛开种种解决方案,来看看Elasticsearch里面对这种需求,是多么的容易统计。
首先,我们需要造些数据,需要用到一个模型,这个模型定义了一个type,就算类型吧,我们用这个属性来演示常规的group。还有一个catIds的列表模型,这个来解决我们上面描述的一本书对应多个分类的需求。模型定义如下:
- import java.io.Serializable;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.Random;
- import com.donlianli.es.ESUtils;
- /**
- * 这个是为分组定义的一个模型
- * catIds通常为一对多的分类ID
- * @author donlian
- */
- public class FacetTestModel implements Serializable {
- private static final long serialVersionUID = 3174577828007649745L;
- /**
- * 随便编写的一些值,type属性只能取这里面的其中一个
- */
- private String[] types= new String[]{
- "type1","type2","type3","type4","type5","type6","type7",
- "type11","type12","type13","type14","type15","type16","type17"
- };
- //主ID
- private long id;
- //类型,为types之一
- private String type;
- /**
- * 所属分类,范围为1-50
- */
- private List<Integer> catIds;
- public FacetTestModel(){
- Random r = new Random();
- int n = Math.abs(r.nextInt());
- int index = n%14;
- this.type = types[index];
- this.id = Math.abs(r.nextLong());
- n = n%50;
- catIds = new ArrayList<Integer>();
- catIds.add(n);
- int ys = n%3;
- if(ys!=0){
- for(int i=1;i<ys+1;i++){
- catIds.add(n+i);
- }
- }
- }
- public static void main(String[] argv){
- for(int i=0;i<10;i++){
- FacetTestModel f = new FacetTestModel();
- System.out.println(ESUtils.toJson(f));
- }
- }
- set,get方法,自己写吧
- }
接着就是初始化数据。
- import org.elasticsearch.action.bulk.BulkRequestBuilder;
- import org.elasticsearch.action.bulk.BulkResponse;
- import org.elasticsearch.action.index.IndexRequestBuilder;
- import org.elasticsearch.client.Client;
- import com.donlianli.es.ESUtils;
- import com.donlianli.es.model.FacetTestModel;
- public class BulkIndexTest {
- public static void main(String[] args) {
- Client client = ESUtils.getClient();
- BulkRequestBuilder bulkRequest = client.prepareBulk();
- for(int i=0;i<10;i++){
- String json = ESUtils.toJson(new FacetTestModel());
- IndexRequestBuilder indexRequest = client.prepareIndex("test", "test")
- //指定不重复的ID
- .setSource(json).setId(String.valueOf(i));
- //添加到builder中
- bulkRequest.add(indexRequest);
- }
- BulkResponse bulkResponse = bulkRequest.execute().actionGet();
- if (bulkResponse.hasFailures()) {
- System.out.println(bulkResponse.buildFailureMessage());
- }
- }
- }
接下来,我们首先对type进行统计。在elasticsearch中,分组的功能叫facet,不知道为啥起这个名称。总之,就是对type的每一个值的数量进行统计,注意,要设置里面的size条件,否则默认只返回10个。
- import org.elasticsearch.action.search.SearchResponse;
- import org.elasticsearch.client.Client;
- import org.elasticsearch.index.query.FilterBuilders;
- import org.elasticsearch.search.facet.FacetBuilders;
- import org.elasticsearch.search.facet.Facets;
- import org.elasticsearch.search.facet.terms.TermsFacet;
- import org.elasticsearch.search.facet.terms.TermsFacetBuilder;
- import com.donlianli.es.ESUtils;
- public class GroupTest {
- public static void main(String[] argv){
- Client client = ESUtils.getClient();
- TermsFacetBuilder facetBuilder = FacetBuilders.termsFacet("typeFacetName");
- facetBuilder.field("type").size(Integer.MAX_VALUE);
- facetBuilder.facetFilter(FilterBuilders.matchAllFilter());
- SearchResponse response = client.prepareSearch("test")
- .setTypes("test")
- .addFacet(facetBuilder)
- .setFilter(FilterBuilders.matchAllFilter())
- .execute()
- .actionGet();
- Facets f = response.facets();
- //跟上面的名称一样
- TermsFacet facet = (TermsFacet)f.getFacets().get("typeFacetName");
- for(TermsFacet.Entry tf :facet.entries()){
- System.out.println(tf.getTerm()+"\t:\t" + tf.getCount());
- }
- client.close();
- }
- }
运行程序后,大概得到如下结果:
- type3 : 4
- type7 : 1
- type6 : 1
- type4 : 1
- type13 : 1
- type12 : 1
- type11 : 1
正好10个。初始化代码能对的上。
下面,我们就要对catIds进行统计了,再统计之前,我们先看看es里面都存储的是那些数据。
- {id=3683174899323317453, catIds=[4, 5], type=type3}
- {id=271209313870366004, catIds=[26, 27, 28], type=type3}
- {id=348654892174153835, catIds=[41, 42, 43], type=type4}
- {id=6826187683023110944, catIds=[46, 47], type=type7}
- {id=3437591661789488747, catIds=[22, 23], type=type3}
- {id=6365837443081614150, catIds=[37, 38], type=type11}
- {id=2387331048448677498, catIds=[20, 21, 22], type=type3}
- {id=5595404824923951817, catIds=[31, 32], type=type13}
- {id=3593797446463621044, catIds=[30], type=type12}
- {id=5824112111832084165, catIds=[1, 2], type=type6}
怎么对catIds进行统计呢,代码跟上面进行单个统计一样。
- import org.elasticsearch.action.search.SearchResponse;
- import org.elasticsearch.client.Client;
- import org.elasticsearch.index.query.FilterBuilders;
- import org.elasticsearch.search.facet.FacetBuilders;
- import org.elasticsearch.search.facet.Facets;
- import org.elasticsearch.search.facet.terms.TermsFacet;
- import org.elasticsearch.search.facet.terms.TermsFacetBuilder;
- import com.donlianli.es.ESUtils;
- public class GroupTest2 {
- public static void main(String[] argv){
- Client client = ESUtils.getClient();
- TermsFacetBuilder facetBuilder = FacetBuilders.termsFacet("catIdName");
- facetBuilder.field("catIds").size(Integer.MAX_VALUE);
- facetBuilder.facetFilter(FilterBuilders.matchAllFilter());
- SearchResponse response = client.prepareSearch("test")
- .setTypes("test")
- .addFacet(facetBuilder)
- .setFilter(FilterBuilders.matchAllFilter())
- .execute()
- .actionGet();
- Facets f = response.facets();
- //跟上面的名称一样
- TermsFacet facet = (TermsFacet)f.getFacets().get("catIdName");
- for(TermsFacet.Entry tf :facet.entries()){
- System.out.println("键:"+tf.getTerm()+"\t;数量:\t" + tf.getCount());
- }
- client.close();
- }
- }
运行结果:
- 键:22 ;数量: 2
- 键:47 ;数量: 1
- 键:46 ;数量: 1
- 键:43 ;数量: 1
- 键:42 ;数量: 1
- 键:41 ;数量: 1
- 键:38 ;数量: 1
- 键:37 ;数量: 1
- 键:32 ;数量: 1
- 键:31 ;数量: 1
- 键:30 ;数量: 1
- 键:28 ;数量: 1
- 键:27 ;数量: 1
- 键:26 ;数量: 1
- 键:23 ;数量: 1
- 键:21 ;数量: 1
- 键:20 ;数量: 1
- 键:5 ;数量: 1
- 键:4 ;数量: 1
- 键:2 ;数量: 1
- 键:1 ;数量: 1
再和上面的数据对对,是不是除了22,其他的都是一个?
在分组这方面,ES真的很强大,除了上面的支持列表分组外,还支持范围分组rangeFacet,多个分组可以一次全部发送给ES等等,更多功能,大家还是自己多多验证。

Elasticsearch强大的聚合功能Facet的更多相关文章
- SSRS 系列 - 使用带参数的 MDX 查询实现一个分组聚合功能的报表
SSRS 系列 - 使用带参数的 MDX 查询实现一个分组聚合功能的报表 SSRS 系列 - 使用带参数的 MDX 查询实现一个分组聚合功能的报表 2013-10-09 23:09 by BI Wor ...
- 点聚合功能---基于ARCGIS RUNTIME SDK FOR ANDROID
一直不更新博客的原因,如果一定要找一个,那就是忙,或者说懒癌犯了. 基于ArcGIS RunTime SDK for Android的点聚合功能,本来是我之前做过的一个系统里面的一个小部分,今天抽出一 ...
- MongoCola使用教程 1 - MongoDB的基本操作和聚合功能---Mongdb客户端软件操作说明
前言 在开始正文之前,感谢博客园的Nosql爱好者对于MongoCola工具的试用(使用).特别感谢 呆呆 这位朋友的Bug报告,让我纠正了一个很严重的Bug.同时也感谢以前的多个网友在博客留言中给我 ...
- jQuery Validate 插件为表单提供了强大的验证功能
之前项目开发中,表单校验用的jQuery Validate 插件,这个插件为表单提供了强大的验证功能,让客户端表单验证变得更简单,同时提供了大量的定制选项,满足应用程序各种需求.该插件捆绑了一套有用的 ...
- php图像处理(thinkphp框架有相对强大的图像处理功能)
php图像处理(thinkphp框架有相对强大的图像处理功能) 一.总结 1.php处理图像:php处理图像需要安装外库(gd库) 2.gd库函数可以非常完美的操作图像:安装好库之后,这个库里面的函数 ...
- 借助Mac自带的强大的搜索功能,如何快速搜索打开Tuxera Disk Manager
现在很多小伙伴们在遇到Mac读写NTFS格式硬盘问题的时候,都会选择使用Tuxera NTFS这个磁盘读写工具.因为这款读写工具不仅可以帮助我们进行读写工作,还具有一个磁盘管理工具Disk Manag ...
- 小试牛刀ElasticSearch大数据聚合统计
ElasticSearch相信有不少朋友都了解,即使没有了解过它那相信对ELK也有所认识E即是ElasticSearch.ElasticSearch最开始更多用于检索,作为一搜索的集群产品简单易用绝对 ...
- Django之强大的Form功能
转载: http://www.cnblogs.com/0820-zq/p/5807980.html Form Form的验证思路 前端:form表单 后台:创建form类,当请求到来时,先匹配,匹配出 ...
- java使用elasticsearch分组进行聚合查询(group by)-项目中实际应用
java连接elasticsearch 进行聚合查询进行相应操作 一:对单个字段进行分组求和 1.表结构图片: 根据任务id分组,分别统计出每个任务id下有多少个文字标题 .SQL:select id ...
随机推荐
- IP地址,子网掩码划分(转)
IP地址划分教程 IP和子网掩码我们都知道,IP是由四段数字组成,在此,我们先来了解一下3类常用的IP A类IP段 0.0.0.0 到127.255.255.255 B类IP段 128.0.0.0 到 ...
- wordpress 提取头像的src
获取用户头像,可以通过 $avatar_html = get_avatar( $email ); 获取到头像的html /** * Retrieve the avatar url for a user ...
- PHP 点滴疑惑
在数据库中,字段为NULL,可以使用empty()进行判断 <?php $CONFIG['hostname'] = 'localhost'; $CONFIG['username'] = 'roo ...
- dirname(__FILE__) 的使用总结
dirname(__FILE__) php中定义了一个很有用的常数,即 __file__ 这个内定常数是当前php程序的就是完整路径(路径+文件名). 即使这个文件被其他文件引用(include或re ...
- (译文)12个简单(但强大)的JavaScript技巧(二)
原文链接: 12 Simple (Yet Powerful) JavaScript Tips 其他链接: (译文)12个简单(但强大)的JavaScript技巧(一) 强大的立即调用函数表达式 (什么 ...
- js中 this篇
以下文案皆来自<你不知道的JavaScript 上卷>——读书笔记摘要 this 到底是什么? 排除了一些错误理解之后,我们来看看 this 到底是一种什么样的机制. 之前我们说过 thi ...
- scala学习笔记:集合
scala> 1 to 10 res9: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3, 4, 5, 6, 7, 8, 9 ...
- 通过公网连接云数据库Memcache--ECS Windows篇
目前云数据库Memcache是需要通过ECS的内网进行连接访问,如果用户本地需要通过公网访问云数据库Memcache,可以在ECS Windows云服务器中通过netsh进行端口映射实现. 一.搭建要 ...
- 知乎 zhihu
知乎上关于美食的精彩问答有哪些? http://www.zhihu.com/question/22744751/answer/22473212 知乎上关于乐队的精彩问答有哪些? http://www. ...
- XMPP即时通讯(代码实现)
1.配置XMPP(XMPPConfig.m) 2.配置XMPPFramework框架 3.创建单例类(XMPPManager.h/XMPPManager.m)管理器 XMPPManager.m: #i ...