在常规数据库中,我们都知道有一个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等等,更多功能,大家还是自己多多验证。

对这类话题感兴趣?欢迎发送邮件至donlianli@126.com;或者关注我的微信公众号“猿界汪汪队”
关于我:邯郸人,擅长Java,Javascript,Extjs,oracle sql。

Elasticsearch强大的聚合功能Facet的更多相关文章

  1. SSRS 系列 - 使用带参数的 MDX 查询实现一个分组聚合功能的报表

    SSRS 系列 - 使用带参数的 MDX 查询实现一个分组聚合功能的报表 SSRS 系列 - 使用带参数的 MDX 查询实现一个分组聚合功能的报表 2013-10-09 23:09 by BI Wor ...

  2. 点聚合功能---基于ARCGIS RUNTIME SDK FOR ANDROID

    一直不更新博客的原因,如果一定要找一个,那就是忙,或者说懒癌犯了. 基于ArcGIS RunTime SDK for Android的点聚合功能,本来是我之前做过的一个系统里面的一个小部分,今天抽出一 ...

  3. MongoCola使用教程 1 - MongoDB的基本操作和聚合功能---Mongdb客户端软件操作说明

    前言 在开始正文之前,感谢博客园的Nosql爱好者对于MongoCola工具的试用(使用).特别感谢 呆呆 这位朋友的Bug报告,让我纠正了一个很严重的Bug.同时也感谢以前的多个网友在博客留言中给我 ...

  4. jQuery Validate 插件为表单提供了强大的验证功能

    之前项目开发中,表单校验用的jQuery Validate 插件,这个插件为表单提供了强大的验证功能,让客户端表单验证变得更简单,同时提供了大量的定制选项,满足应用程序各种需求.该插件捆绑了一套有用的 ...

  5. php图像处理(thinkphp框架有相对强大的图像处理功能)

    php图像处理(thinkphp框架有相对强大的图像处理功能) 一.总结 1.php处理图像:php处理图像需要安装外库(gd库) 2.gd库函数可以非常完美的操作图像:安装好库之后,这个库里面的函数 ...

  6. 借助Mac自带的强大的搜索功能,如何快速搜索打开Tuxera Disk Manager

    现在很多小伙伴们在遇到Mac读写NTFS格式硬盘问题的时候,都会选择使用Tuxera NTFS这个磁盘读写工具.因为这款读写工具不仅可以帮助我们进行读写工作,还具有一个磁盘管理工具Disk Manag ...

  7. 小试牛刀ElasticSearch大数据聚合统计

    ElasticSearch相信有不少朋友都了解,即使没有了解过它那相信对ELK也有所认识E即是ElasticSearch.ElasticSearch最开始更多用于检索,作为一搜索的集群产品简单易用绝对 ...

  8. Django之强大的Form功能

    转载: http://www.cnblogs.com/0820-zq/p/5807980.html Form Form的验证思路 前端:form表单 后台:创建form类,当请求到来时,先匹配,匹配出 ...

  9. java使用elasticsearch分组进行聚合查询(group by)-项目中实际应用

    java连接elasticsearch 进行聚合查询进行相应操作 一:对单个字段进行分组求和 1.表结构图片: 根据任务id分组,分别统计出每个任务id下有多少个文字标题 .SQL:select id ...

随机推荐

  1. java基础学习总结三(jdk7新特性、变量(局部变量和成员变量)、常量以及运算符)

    一:jdk7新特性 可以表示二进制数值,以0b开头,中间可以使用下划线_分隔符.如下: @Test /** * 测试jdk新特性 */ public void testJdk7(){ int a=0b ...

  2. JAXB - Annotations, Annotations for the Schema: XmlSchema

    This annotation can only be used with a package. It defines parameters that are derived from the xsd ...

  3. .net MVC中JsonResult 返回类

    /// <summary> /// 返回消息类 /// </summary> public class ReturnMessage { private IDictionary& ...

  4. PHP与Java使用des加密通讯

    http://www.pocketdigi.com/20121112/940.html 原文:http://toptulip.iteye.com/blog/780309 使用php加密字符串,生成密文 ...

  5. 鼠标点击input时,placeholder中的提示信息消失

    html代码: <input type="text" placeholder="多个关键词空格隔开"> 鼠标点击input时,placeholder ...

  6. 一篇关于学C++的感想(拿来与大家分享)

    学计算机的如果你有耐心看下去,我敢保证这绝对是一种收获 期待爱 大师提醒: 计算机专业不是学编程,而是懂得计算机的工作原理,以及和计算机相关的学科技术.一个高手不必懂得编程,coder是最底层的人物, ...

  7. MySql事务及JDBC对事务的使用

    一 .事务的几个重要特性 1. 原子性 事务内的每个内容不可分割,是一个统一的整体.或同时进行或同时消亡. 2.一致性 事务执行前和事务执行后,状态都是统一的.如A转B 100元,A和B数据总额度没有 ...

  8. 英语中的 姓氏/Surname

    .Chomsky (Belarusian: Хомскі, Russian: Хомский, Ukrainian: Хомський, Hebrew: חומסקי‎‎, "from (V ...

  9. WPF 程序中启动和关闭外部.exe程序

    当需要在WPF程序启动时,启动另一外部程序(.exe程序)时,可以按照下面的例子来: C#后台代码如下: using System; using System.Collections.Generic; ...

  10. 使用XmlPullParser对xml进行读取

    XML文件是一种标记性语言;在开发中经常在接口交互时被用作报文传输或者把自定义的类序列化为XML的形式存储到数据库.正因为XML文件这么常用,使用JAVA对XML文件进行读写操作是每一个开发人员必须掌 ...