springboot实体映射到数据库_SpringBoot 操作 ElasticSearch 详解
本文来源:http://www.mydlq.club/article/64/
一、ElasticSearch 简介
. 1、简介
. 2、特性
. 3、使用场景
. 二、ElasticSearch 基础概念
. 1、ElaticSearch 和 DB 的关系
. 2、索引
. 3、文档
. 4、映射
. 三、SpringBoot 项目引入 ElasticSearch 依赖
. 1、Maven 引入相关依赖
. 2、ElasticSearch 连接配置
. 四、索引操作示例
. 1、Restful 操作示例
. 2、Java 代码示例
. 五、文档操作示例
. 1、Restful 操作示例
. 2、Java 代码示例
. 六、插入初始化数据
. 1、单条插入
. 2、批量插入
. 3、查询数据
. 七、查询操作示例
. 1、精确查询(term)
. 2、匹配查询(match)
. 3、模糊查询(fuzzy)
. 4、范围查询(range)
. 5、通配符查询(wildcard)
. 6、布尔查询(bool)
. 八、聚合查询操作示例
. 1、Metric 聚合分析
. 2、Bucket 聚合分析
. 3、Metric 与 Bucket 聚合分析
参考地址:
百度百科
博文示例项目 Github 地址:https://github.com/my-dlq/blog-example/tree/master/springboot/springboot-elasticsearch-example
系统环境:
SpringBoot 版本:2.2.4
ElasticSearch 版本:6.5.3
一、ElasticSearch 简介
1、简介
ElasticSearch 是一个基于 Lucene 的搜索服务器。它提供了一个分布式多员工能力的全文搜索引擎,基于 RESTful web 接口。Elasticsearch 是用 Java 语言开发的,并作为 Apache 许可条款下的开放源码发布,是一种流行的企业级搜索引擎。
ElasticSearch 用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。
2、特性
分布式的文档存储引擎
分布式的搜索引擎和分析引擎
分布式,支持PB级数据
3、使用场景
搜索领域: 如百度、谷歌,全文检索等。
门户网站: 访问统计、文章点赞、留言评论等。
广告推广: 记录员工行为数据、消费趋势、员工群体进行定制推广等。
信息采集: 记录应用的埋点数据、访问日志数据等,方便大数据进行分析。
二、ElasticSearch 基础概念
1、ElaticSearch 和 DB 的关系
在 Elasticsearch
中,文档归属于一种类型 type
,而这些类型存在于索引 index
中,我们可以列一些简单的不同点,来类比传统关系型数据库:
Relational DB -> Databases -> Tables -> Rows -> Columns
Elasticsearch -> Indices -> Types -> Documents -> Fields
Elasticsearch 集群可以包含多个索引 indices
,每一个索引可以包含多个类型 types
,每一个类型包含多个文档 documents
,然后每个文档包含多个字段 Fields
。而在 DB 中可以有多个数据库 Databases
,每个库中可以有多张表 Tables
,没个表中又包含多行Rows
,每行包含多列Columns
。
2、索引
索引基本概念(indices):
索引是含义相同属性的文档集合,是 ElasticSearch 的一个逻辑存储,可以理解为关系型数据库中的数据库,ElasticSearch 可以把索引数据存放到一台服务器上,也可以 sharding 后存到多台服务器上,每个索引有一个或多个分片,每个分片可以有多个副本。
索引类型(index_type):
索引可以定义一个或多个类型,文档必须属于一个类型。在 ElasticSearch
中,一个索引对象可以存储多个不同用途的对象,通过索引类型可以区分单个索引中的不同对象,可以理解为关系型数据库中的表。每个索引类型可以有不同的结构,但是不同的索引类型不能为相同的属性设置不同的类型。
3、文档
文档(document):
文档是可以被索引的基本数据单位。存储在 ElasticSearch 中的主要实体叫文档 document
,可以理解为关系型数据库中表的一行记录。每个文档由多个字段构成,ElasticSearch 是一个非结构化的数据库,每个文档可以有不同的字段,并且有一个唯一的标识符。
4、映射
映射(mapping):
ElasticSearch
的 Mapping
非常类似于静态语言中的数据类型:声明一个变量为 int 类型的变量,以后这个变量都只能存储 int
类型的数据。同样的,一个 number
类型的 mapping
字段只能存储 number
类型的数据。
同语言的数据类型相比,Mapping
还有一些其他的含义,Mapping
不仅告诉 ElasticSearch 一个 Field
中是什么类型的值, 它还告诉 ElasticSearch 如何索引数据以及数据是否能被搜索到。
ElaticSearch 默认是动态创建索引和索引类型的 Mapping 的。这就相当于无需定义 Solr
中的 Schema
,无需指定各个字段的索引规则就可以索引文件,很方便。但有时方便就代表着不灵活。比如,ElasticSearch 默认一个字段是要做分词的,但我们有时要搜索匹配整个字段却不行。如有统计工作要记录每个城市出现的次数。对于 name
字段,若记录 new york
文本,ElasticSearch 可能会把它拆分成 new
和 york
这两个词,分别计算这个两个单词的次数,而不是我们期望的 new york
。
三、SpringBoot 项目引入 ElasticSearch 依赖
下面介绍下 SpringBoot 如何通过 elasticsearch-rest-high-level-client
工具操作 ElasticSearch
,这里需要说一下,为什么没有使用 Spring 家族封装的 spring-data-elasticsearch
。
主要原因是灵活性和更新速度,Spring 将 ElasticSearch 过度封装,让开发者很难跟 ES 的 DSL 查询语句进行关联。再者就是更新速度,ES 的更新速度是非常快,但是 spring-data-elasticsearch 更新速度比较缓慢。
由于上面两点,所以选择了官方推出的 Java 客户端 elasticsearch-rest-high-level-client
,它的代码写法跟 DSL 语句很相似,懂 ES 查询的使用其上手很快。
示例项目地址:https://github.com/my-dlq/blog-example/tree/master/springboot/springboot-elasticsearch-example
1、Maven 引入相关依赖
lombok: lombok 工具依赖。
fastjson: 用于将 JSON 转换对象的依赖。
spring-boot-starter-web: SpringBoot 的 Web 依赖。
elasticsearch:ElasticSearch: 依赖,需要和 ES 版本保持一致。
elasticsearch-rest-high-level-client: 用于操作 ES 的 Java 客户端。
1<?xml version="1.0" encoding="UTF-8"?> 2<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4 <modelVersion>4.0.0modelVersion> 5 <parent> 6 <groupId>org.springframework.bootgroupId> 7 <artifactId>spring-boot-starter-parentartifactId> 8 <version>2.2.4.RELEASEversion> 9 <relativePath/> 10 parent>11 <groupId>club.mydlqgroupId>12 <artifactId>springboot-elasticsearch-exampleartifactId>13 <version>0.0.1-SNAPSHOTversion>14 <name>springboot-elasticsearch-examplename>15 <description>Demo project for Spring Boot ElasticSearchdescription>1617 <properties>18 <java.version>1.8java.version>19 properties>20 <dependencies>21 22 <dependency>23 <groupId>org.springframework.bootgroupId>24 <artifactId>spring-boot-starter-webartifactId>25 dependency>26 27 <dependency>28 <groupId>org.projectlombokgroupId>29 <artifactId>lombokartifactId>30 <optional>trueoptional>31 dependency>32 33 <dependency>34 <groupId>com.alibabagroupId>35 <artifactId>fastjsonartifactId>36 <version>1.2.61version>37 dependency>38 39 <dependency>40 <groupId>org.elasticsearch.clientgroupId>41 <artifactId>elasticsearch-rest-high-level-clientartifactId>42 <version>6.5.4version>43 dependency>44 <dependency>45 <groupId>org.elasticsearchgroupId>46 <artifactId>elasticsearchartifactId>47 <version>6.5.4version>48 dependency>49 dependencies>5051 <build>52 <plugins>53 <plugin>54 <groupId>org.springframework.bootgroupId>55 <artifactId>spring-boot-maven-pluginartifactId>56 plugin>57 plugins>58 build>5960project>
2、ElasticSearch 连接配置
(1)、application.yml 配置文件
为了方便更改连接 ES 的连接配置,所以我们将配置信息放置于 application.yaml 中:
1#base 2server: 3 port: 8080 4#spring 5spring: 6 application: 7 name: springboot-elasticsearch-example 8#elasticsearch 9elasticsearch:10 schema: http11 address: 127.0.0.1:920012 connectTimeout: 500013 socketTimeout: 500014 connectionRequestTimeout: 500015 maxConnectNum: 10016 maxConnectPerRoute: 100
(2)、java 连接配置类
这里需要写一个 Java 配置类读取 application 中的配置信息:
1import org.apache.http.HttpHost; 2import org.elasticsearch.client.RestClient; 3import org.elasticsearch.client.RestClientBuilder; 4import org.elasticsearch.client.RestHighLevelClient; 5import org.springframework.beans.factory.annotation.Value; 6import org.springframework.context.annotation.Bean; 7import org.springframework.context.annotation.Configuration; 8import java.util.ArrayList; 9import java.util.List;1011/**12 * ElasticSearch 配置13 */14@Configuration15public class ElasticSearchConfig {1617 /** 协议 */18 @Value("${elasticsearch.schema:http}")19 private String schema;2021 /** 集群地址,如果有多个用“,”隔开 */22 @Value("${elasticsearch.address}")23 private String address;2425 /** 连接超时时间 */26 @Value("${elasticsearch.connectTimeout:5000}")27 private int connectTimeout;2829 /** Socket 连接超时时间 */30 @Value("${elasticsearch.socketTimeout:10000}")31 private int socketTimeout;3233 /** 获取连接的超时时间 */34 @Value("${elasticsearch.connectionRequestTimeout:5000}")35 private int connectionRequestTimeout;3637 /** 最大连接数 */38 @Value("${elasticsearch.maxConnectNum:100}")39 private int maxConnectNum;4041 /** 最大路由连接数 */42 @Value("${elasticsearch.maxConnectPerRoute:100}")43 private int maxConnectPerRoute;4445 @Bean46 public RestHighLevelClient restHighLevelClient() {47 // 拆分地址48 List hostLists = new ArrayList<>();49 String[] hostList = address.split(",");50 for (String addr : hostList) {51 String host = addr.split(":")[0];52 String port = addr.split(":")[1];53 hostLists.add(new HttpHost(host, Integer.parseInt(port), schema));54 }55 // 转换成 HttpHost 数组56 HttpHost[] httpHost = hostLists.toArray(new HttpHost[]{});57 // 构建连接对象58 RestClientBuilder builder = RestClient.builder(httpHost);59 // 异步连接延时配置60 builder.setRequestConfigCallback(requestConfigBuilder -> {61 requestConfigBuilder.setConnectTimeout(connectTimeout);62 requestConfigBuilder.setSocketTimeout(socketTimeout);63 requestConfigBuilder.setConnectionRequestTimeout(connectionRequestTimeout);64 return requestConfigBuilder;65 });66 // 异步连接数配置67 builder.setHttpClientConfigCallback(httpClientBuilder -> {68 httpClientBuilder.setMaxConnTotal(maxConnectNum);69 httpClientBuilder.setMaxConnPerRoute(maxConnectPerRoute);70 return httpClientBuilder;71 });72 return new RestHighLevelClient(builder);73 }7475}
四、索引操作示例
这里示例会指出通过 Kibana 的 Restful 工具操作与对应的 Java 代码操作的两个示例。
1、Restful 操作示例
创建索引
创建名为 mydlq-user
的索引与对应 Mapping。
1PUT /mydlq-user 2{ 3 "mappings": { 4 "doc": { 5 "dynamic": true, 6 "properties": { 7 "name": { 8 "type": "text", 9 "fields": {10 "keyword": {11 "type": "keyword"12 }13 }14 },15 "address": {16 "type": "text",17 "fields": {18 "keyword": {19 "type": "keyword"20 }21 }22 },23 "remark": {24 "type": "text",25 "fields": {26 "keyword": {27 "type": "keyword"28 }29 }30 },31 "age": {32 "type": "integer"33 },34 "salary": {35 "type": "float"36 },37 "birthDate": {38 "type": "date",39 "format": "yyyy-MM-dd"40 },41 "createTime": {42 "type": "date"43 }44 }45 }46 }47}
删除索引
删除 mydlq-user 索引。
1DELETE /mydlq-user
2、Java 代码示例
1import lombok.extern.slf4j.Slf4j; 2import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; 3import org.elasticsearch.action.admin.indices.create.CreateIndexResponse; 4import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; 5import org.elasticsearch.action.support.master.AcknowledgedResponse; 6import org.elasticsearch.client.RequestOptions; 7import org.elasticsearch.client.RestHighLevelClient; 8import org.elasticsearch.common.settings.Settings; 9import org.elasticsearch.common.xcontent.XContentBuilder; 10import org.elasticsearch.common.xcontent.XContentFactory; 11import org.springframework.beans.factory.annotation.Autowired; 12import org.springframework.stereotype.Service; 13import java.io.IOException; 14 15@Slf4j 16@Service 17public class IndexService2 { 18 19 @Autowired 20 private RestHighLevelClient restHighLevelClient; 21 22 /** 23 * 创建索引 24 */ 25 public void createIndex() { 26 try { 27 // 创建 Mapping 28 XContentBuilder mapping = XContentFactory.jsonBuilder() 29 .startObject() 30 .field("dynamic", true) 31 .startObject("properties") 32 .startObject("name") 33 .field("type","text") 34 .startObject("fields") 35 .startObject("keyword") 36 .field("type","keyword") 37 .endObject() 38 .endObject() 39 .endObject() 40 .startObject("address") 41 .field("type","text") 42 .startObject("fields") 43 .startObject("keyword") 44 .field("type","keyword") 45 .endObject() 46 .endObject() 47 .endObject() 48 .startObject("remark") 49 .field("type","text") 50 .startObject("fields") 51 .startObject("keyword") 52 .field("type","keyword") 53 .endObject() 54 .endObject() 55 .endObject() 56 .startObject("age") 57 .field("type","integer") 58 .endObject() 59 .startObject("salary") 60 .field("type","float") 61 .endObject() 62 .startObject("birthDate") 63 .field("type","date") 64 .field("format", "yyyy-MM-dd") 65 .endObject() 66 .startObject("createTime") 67 .field("type","date") 68 .endObject() 69 .endObject() 70 .endObject(); 71 // 创建索引配置信息,配置 72 Settings settings = Settings.builder() 73 .put("index.number_of_shards", 1) 74 .put("index.number_of_replicas", 0) 75 .build(); 76 // 新建创建索引请求对象,然后设置索引类型(ES 7.0 将不存在索引类型)和 mapping 与 index 配置 77 CreateIndexRequest request = new CreateIndexRequest("mydlq-user", settings); 78 request.mapping("doc", mapping); 79 // RestHighLevelClient 执行创建索引 80 CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(request, RequestOptions.DEFAULT); 81 // 判断是否创建成功 82 boolean isCreated = createIndexResponse.isAcknowledged(); 83 log.info("是否创建成功:{}", isCreated); 84 } catch (IOException e) { 85 log.error("", e); 86 } 87 } 88 89 /** 90 * 删除索引 91 */ 92 public void deleteIndex() { 93 try { 94 // 新建删除索引请求对象 95 DeleteIndexRequest request = new DeleteIndexRequest("mydlq-user"); 96 // 执行删除索引 97 AcknowledgedResponse acknowledgedResponse = restHighLevelClient.indices().delete(request, RequestOptions.DEFAULT); 98 // 判断是否删除成功 99 boolean siDeleted = acknowledgedResponse.isAcknowledged();100 log.info("是否删除成功:{}", siDeleted);101 } catch (IOException e) {102 log.error("", e);103 }104 }105106}
五、文档操作示例
1、Restful 操作示例
增加文档信息
在索引 mydlq-user
中增加一条文档信息。
1POST /mydlq-user/doc 2{ 3 "address": "北京市", 4 "age": 29, 5 "birthDate": "1990-01-10", 6 "createTime": 1579530727699, 7 "name": "张三", 8 "remark": "来自北京市的张先生", 9 "salary": 10010}
获取文档信息
获取 mydlq-user
的索引 id=1 的文档信息。
1GET /mydlq-user/doc/1
更新文档信息
更新之前创建的 id=1 的文档信息。
1PUT /mydlq-user/doc/1 2{ 3 "address": "北京市海淀区", 4 "age": 29, 5 "birthDate": "1990-01-10", 6 "createTime": 1579530727699, 7 "name": "张三", 8 "remark": "来自北京市的张先生", 9 "salary": 10010}
删除文档信息
删除之前创建的 id=1 的文档信息。
1DELETE /mydlq-user/doc/1
2、Java 代码示例
1import club.mydlq.elasticsearch.model.entity.UserInfo; 2import com.alibaba.fastjson.JSON; 3import lombok.extern.slf4j.Slf4j; 4import org.elasticsearch.action.delete.DeleteRequest; 5import org.elasticsearch.action.delete.DeleteResponse; 6import org.elasticsearch.action.get.GetRequest; 7import org.elasticsearch.action.get.GetResponse; 8import org.elasticsearch.action.index.IndexRequest; 9import org.elasticsearch.action.index.IndexResponse; 10import org.elasticsearch.action.update.UpdateRequest; 11import org.elasticsearch.action.update.UpdateResponse; 12import org.elasticsearch.client.RequestOptions; 13import org.elasticsearch.client.RestHighLevelClient; 14import org.elasticsearch.common.xcontent.XContentType; 15import org.springframework.beans.factory.annotation.Autowired; 16import org.springframework.stereotype.Service; 17import java.io.IOException; 18import java.util.Date; 19 20@Slf4j 21@Service 22public class IndexService { 23 24 @Autowired 25 private RestHighLevelClient restHighLevelClient; 26 27 /** 28 * 增加文档信息 29 */ 30 public void addDocument() { 31 try { 32 // 创建索引请求对象 33 IndexRequest indexRequest = new IndexRequest("mydlq-user", "doc", "1"); 34 // 创建员工信息 35 UserInfo userInfo = new UserInfo(); 36 userInfo.setName("张三"); 37 userInfo.setAge(29); 38 userInfo.setSalary(100.00f); 39 userInfo.setAddress("北京市"); 40 userInfo.setRemark("来自北京市的张先生"); 41 userInfo.setCreateTime(new Date()); 42 userInfo.setBirthDate("1990-01-10"); 43 // 将对象转换为 byte 数组 44 byte[] json = JSON.toJSONBytes(userInfo); 45 // 设置文档内容 46 indexRequest.source(json, XContentType.JSON); 47 // 执行增加文档 48 IndexResponse response = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT); 49 log.info("创建状态:{}", response.status()); 50 } catch (Exception e) { 51 log.error("", e); 52 } 53 } 54 55 /** 56 * 获取文档信息 57 */ 58 public void getDocument() { 59 try { 60 // 获取请求对象 61 GetRequest getRequest = new GetRequest("mydlq-user", "doc", "1"); 62 // 获取文档信息 63 GetResponse getResponse = restHighLevelClient.get(getRequest, RequestOptions.DEFAULT); 64 // 将 JSON 转换成对象 65 if (getResponse.isExists()) { 66 UserInfo userInfo = JSON.parseObject(getResponse.getSourceAsBytes(), UserInfo.class); 67 log.info("员工信息:{}", userInfo); 68 } 69 } catch (IOException e) { 70 log.error("", e); 71 } 72 } 73 74 /** 75 * 更新文档信息 76 */ 77 public void updateDocument() { 78 try { 79 // 创建索引请求对象 80 UpdateRequest updateRequest = new UpdateRequest("mydlq-user", "doc", "1"); 81 // 设置员工更新信息 82 UserInfo userInfo = new UserInfo(); 83 userInfo.setSalary(200.00f); 84 userInfo.setAddress("北京市海淀区"); 85 // 将对象转换为 byte 数组 86 byte[] json = JSON.toJSONBytes(userInfo); 87 // 设置更新文档内容 88 updateRequest.doc(json, XContentType.JSON); 89 // 执行更新文档 90 UpdateResponse response = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT); 91 log.info("创建状态:{}", response.status()); 92 } catch (Exception e) { 93 log.error("", e); 94 } 95 } 96 97 /** 98 * 删除文档信息 99 */100 public void deleteDocument() {101 try {102 // 创建删除请求对象103 DeleteRequest deleteRequest = new DeleteRequest("mydlq-user", "doc", "1");104 // 执行删除文档105 DeleteResponse response = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);106 log.info("删除状态:{}", response.status());107 } catch (IOException e) {108 log.error("", e);109 }110 }111112}
六、插入初始化数据
执行查询示例前,先往索引中插入一批数据:
1、单条插入
POST mydlq-user/_doc
1{"name":"零零","address":"北京市丰台区","remark":"低层员工","age":29,"salary":3000,"birthDate":"1990-11-11","createTime":"2019-11-11T08:18:00.000Z"}
2、批量插入
POST _bulk
1{"index":{"_index":"mydlq-user","_type":"doc"}} 2{"name":"刘一","address":"北京市丰台区","remark":"低层员工","age":30,"salary":3000,"birthDate":"1989-11-11","createTime":"2019-03-15T08:18:00.000Z"} 3{"index":{"_index":"mydlq-user","_type":"doc"}} 4{"name":"陈二","address":"北京市昌平区","remark":"中层员工","age":27,"salary":7900,"birthDate":"1992-01-25","createTime":"2019-11-08T11:15:00.000Z"} 5{"index":{"_index":"mydlq-user","_type":"doc"}} 6{"name":"张三","address":"北京市房山区","remark":"中层员工","age":28,"salary":8800,"birthDate":"1991-10-05","createTime":"2019-07-22T13:22:00.000Z"} 7{"index":{"_index":"mydlq-user","_type":"doc"}} 8{"name":"李四","address":"北京市大兴区","remark":"高层员工","age":26,"salary":9000,"birthDate":"1993-08-18","createTime":"2019-10-17T15:00:00.000Z"} 9{"index":{"_index":"mydlq-user","_type":"doc"}}10{"name":"王五","address":"北京市密云区","remark":"低层员工","age":31,"salary":4800,"birthDate":"1988-07-20","createTime":"2019-05-29T09:00:00.000Z"}11{"index":{"_index":"mydlq-user","_type":"doc"}}12{"name":"赵六","address":"北京市通州区","remark":"中层员工","age":32,"salary":6500,"birthDate":"1987-06-02","createTime":"2019-12-10T18:00:00.000Z"}13{"index":{"_index":"mydlq-user","_type":"doc"}}14{"name":"孙七","address":"北京市朝阳区","remark":"中层员工","age":33,"salary":7000,"birthDate":"1986-04-15","createTime":"2019-06-06T13:00:00.000Z"}15{"index":{"_index":"mydlq-user","_type":"doc"}}16{"name":"周八","address":"北京市西城区","remark":"低层员工","age":32,"salary":5000,"birthDate":"1987-09-26","createTime":"2019-01-26T14:00:00.000Z"}17{"index":{"_index":"mydlq-user","_type":"doc"}}18{"name":"吴九","address":"北京市海淀区","remark":"高层员工","age":30,"salary":11000,"birthDate":"1989-11-25","createTime":"2019-09-07T13:34:00.000Z"}19{"index":{"_index":"mydlq-user","_type":"doc"}}20{"name":"郑十","address":"北京市东城区","remark":"低层员工","age":29,"salary":5000,"birthDate":"1990-12-25","createTime":"2019-03-06T12:08:00.000Z"}21{"index":{"_index":"mydlq-user","_type":"doc"}}22{"name":"萧十一","address":"北京市平谷区","remark":"低层员工","age":29,"salary":3300,"birthDate":"1990-11-11","createTime":"2019-03-10T08:17:00.000Z"}23{"index":{"_index":"mydlq-user","_type":"doc"}}24{"name":"曹十二","address":"北京市怀柔区","remark":"中层员工","age":27,"salary":6800,"birthDate":"1992-01-25","createTime":"2019-12-03T11:09:00.000Z"}25{"index":{"_index":"mydlq-user","_type":"doc"}}26{"name":"吴十三","address":"北京市延庆区","remark":"中层员工","age":25,"salary":7000,"birthDate":"1994-10-05","createTime":"2019-07-27T14:22:00.000Z"}27{"index":{"_index":"mydlq-user","_type":"doc"}}28{"name":"冯十四","address":"北京市密云区","remark":"低层员工","age":25,"salary":3000,"birthDate":"1994-08-18","createTime":"2019-04-22T15:00:00.000Z"}29{"index":{"_index":"mydlq-user","_type":"doc"}}30{"name":"蒋十五","address":"北京市通州区","remark":"低层员工","age":31,"salary":2800,"birthDate":"1988-07-20","createTime":"2019-06-13T10:00:00.000Z"}31{"index":{"_index":"mydlq-user","_type":"doc"}}32{"name":"苗十六","address":"北京市门头沟区","remark":"高层员工","age":32,"salary":11500,"birthDate":"1987-06-02","createTime":"2019-11-11T18:00:00.000Z"}33{"index":{"_index":"mydlq-user","_type":"doc"}}34{"name":"鲁十七","address":"北京市石景山区","remark":"高员工","age":33,"salary":9500,"birthDate":"1986-04-15","createTime":"2019-06-06T14:00:00.000Z"}35{"index":{"_index":"mydlq-user","_type":"doc"}}36{"name":"沈十八","address":"北京市朝阳区","remark":"中层员工","age":31,"salary":8300,"birthDate":"1988-09-26","createTime":"2019-09-25T14:00:00.000Z"}37{"index":{"_index":"mydlq-user","_type":"doc"}}38{"name":"吕十九","address":"北京市西城区","remark":"低层员工","age":31,"salary":4500,"birthDate":"1988-11-25","createTime":"2019-09-22T13:34:00.000Z"}39{"index":{"_index":"mydlq-user","_type":"doc"}}40{"name":"丁二十","address":"北京市东城区","remark":"低层员工","age":33,"salary":2100,"birthDate":"1986-12-25","createTime":"2019-03-07T12:08:00.000Z"}
3、查询数据
插入完成后再查询数据,查看之前插入的数据是否存在:
1GET mydlq-user/_search
执行后得到下面记录:
1{ 2 "took": 2, 3 "timed_out": false, 4 "_shards": { 5 "total": 1, 6 "successful": 1, 7 "skipped": 0, 8 "failed": 0 9 }, 10 "hits": { 11 "total": 20, 12 "max_score": 1, 13 "hits": [ 14 { 15 "_index": "mydlq-user", 16 "_type": "_doc", 17 "_id": "BeN0BW8B7BNodGwRFTRj", 18 "_score": 1, 19 "_source": { 20 "name": "刘一", 21 "address": "北京市丰台区", 22 "remark": "低层员工", 23 "age": 30, 24 "salary": 3000, 25 "birthDate": "1989-11-11", 26 "createTime": "2019-03-15T08:18:00.000Z" 27 } 28 }, 29 { 30 "_index": "mydlq-user", 31 "_type": "_doc", 32 "_id": "BuN0BW8B7BNodGwRFTRj", 33 "_score": 1, 34 "_source": { 35 "name": "陈二", 36 "address": "北京市昌平区", 37 "remark": "中层员工", 38 "age": 27, 39 "salary": 7900, 40 "birthDate": "1992-01-25", 41 "createTime": "2019-11-08T11:15:00.000Z" 42 } 43 }, 44 { 45 "_index": "mydlq-user", 46 "_type": "_doc", 47 "_id": "B-N0BW8B7BNodGwRFTRj", 48 "_score": 1, 49 "_source": { 50 "name": "张三", 51 "address": "北京市房山区", 52 "remark": "中层员工", 53 "age": 28, 54 "salary": 8800, 55 "birthDate": "1991-10-05", 56 "createTime": "2019-07-22T13:22:00.000Z" 57 } 58 }, 59 { 60 "_index": "mydlq-user", 61 "_type": "_doc", 62 "_id": "CON0BW8B7BNodGwRFTRj", 63 "_score": 1, 64 "_source": { 65 "name": "李四", 66 "address": "北京市大兴区", 67 "remark": "高层员工", 68 "age": 26, 69 "salary": 9000, 70 "birthDate": "1993-08-18", 71 "createTime": "2019-10-17T15:00:00.000Z" 72 } 73 }, 74 { 75 "_index": "mydlq-user", 76 "_type": "_doc", 77 "_id": "CeN0BW8B7BNodGwRFTRj", 78 "_score": 1, 79 "_source": { 80 "name": "王五", 81 "address": "北京市密云区", 82 "remark": "低层员工", 83 "age": 31, 84 "salary": 4800, 85 "birthDate": "1988-07-20", 86 "createTime": "2019-05-29T09:00:00.000Z" 87 } 88 }, 89 { 90 "_index": "mydlq-user", 91 "_type": "_doc", 92 "_id": "CuN0BW8B7BNodGwRFTRj", 93 "_score": 1, 94 "_source": { 95 "name": "赵六", 96 "address": "北京市通州区", 97 "remark": "中层员工", 98 "age": 32, 99 "salary": 6500,100 "birthDate": "1987-06-02",101 "createTime": "2019-12-10T18:00:00.000Z"102 }103 },104 {105 "_index": "mydlq-user",106 "_type": "_doc",107 "_id": "C-N0BW8B7BNodGwRFTRj",108 "_score": 1,109 "_source": {110 "name": "孙七",111 "address": "北京市朝阳区",112 "remark": "中层员工",113 "age": 33,114 "salary": 7000,115 "birthDate": "1986-04-15",116 "createTime": "2019-06-06T13:00:00.000Z"117 }118 },119 {120 "_index": "mydlq-user",121 "_type": "_doc",122 "_id": "DON0BW8B7BNodGwRFTRj",123 "_score": 1,124 "_source": {125 "name": "周八",126 "address": "北京市西城区",127 "remark": "低层员工",128 "age": 32,129 "salary": 5000,130 "birthDate": "1987-09-26",131 "createTime": "2019-01-26T14:00:00.000Z"132 }133 },134 {135 "_index": "mydlq-user",136 "_type": "_doc",137 "_id": "DeN0BW8B7BNodGwRFTRj",138 "_score": 1,139 "_source": {140 "name": "吴九",141 "address": "北京市海淀区",142 "remark": "高层员工",143 "age": 30,144 "salary": 11000,145 "birthDate": "1989-11-25",146 "createTime": "2019-09-07T13:34:00.000Z"147 }148 },149 {150 "_index": "mydlq-user",151 "_type": "_doc",152 "_id": "DuN0BW8B7BNodGwRFTRj",153 "_score": 1,154 "_source": {155 "name": "郑十",156 "address": "北京市东城区",157 "remark": "低层员工",158 "age": 29,159 "salary": 5000,160 "birthDate": "1990-12-25",161 "createTime": "2019-03-06T12:08:00.000Z"162 }163 }164 ]165 }166}
七、查询操作示例
1、精确查询(term)
(1)、Restful 操作示例
精确查询
精确查询,查询地址为 北京市通州区
的人员信息:
查询条件不会进行分词,但是查询内容可能会分词,导致查询不到。之前在创建索引时设置 Mapping 中 address 字段存在 keyword 字段是专门用于不分词查询的子字段。
1GET mydlq-user/_search 2{ 3 "query": { 4 "term": { 5 "address.keyword": { 6 "value": "北京市通州区" 7 } 8 } 9 }10}
精确查询-多内容查询
精确查询,查询地址为 北京市丰台区
、北京市昌平区
或 北京市大兴区
的人员信息:
1GET mydlq-user/_search 2{ 3 "query": { 4 "terms": { 5 "address.keyword": [ 6 "北京市丰台区", 7 "北京市昌平区", 8 "北京市大兴区" 9 ]10 }11 }12}
(2)、Java 代码示例
1import club.mydlq.elasticsearch.model.entity.UserInfo; 2import com.alibaba.fastjson.JSON; 3import lombok.extern.slf4j.Slf4j; 4import org.elasticsearch.action.search.SearchRequest; 5import org.elasticsearch.action.search.SearchResponse; 6import org.elasticsearch.client.RequestOptions; 7import org.elasticsearch.client.RestHighLevelClient; 8import org.elasticsearch.index.query.QueryBuilders; 9import org.elasticsearch.rest.RestStatus;10import org.elasticsearch.search.SearchHit;11import org.elasticsearch.search.SearchHits;12import org.elasticsearch.search.builder.SearchSourceBuilder;13import org.springframework.beans.factory.annotation.Autowired;14import org.springframework.stereotype.Service;15import java.io.IOException;1617@Slf4j18@Service19public class TermQueryService {2021 @Autowired22 private RestHighLevelClient restHighLevelClient;2324 /**25 * 精确查询(查询条件不会进行分词,但是查询内容可能会分词,导致查询不到)26 */27 public void termQuery() {28 try {29 // 构建查询条件(注意:termQuery 支持多种格式查询,如 boolean、int、double、string 等,这里使用的是 string 的查询)30 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();31 searchSourceBuilder.query(QueryBuilders.termQuery("address.keyword", "北京市通州区"));32 // 创建查询请求对象,将查询对象配置到其中33 SearchRequest searchRequest = new SearchRequest("mydlq-user");34 searchRequest.source(searchSourceBuilder);35 // 执行查询,然后处理响应结果36 SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);37 // 根据状态和数据条数验证是否返回了数据38 if (RestStatus.OK.equals(searchResponse.status()) && searchResponse.getHits().totalHits > 0) {39 SearchHits hits = searchResponse.getHits();40 for (SearchHit hit : hits) {41 // 将 JSON 转换成对象42 UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class);43 // 输出查询信息44 log.info(userInfo.toString());45 }46 }47 } catch (IOException e) {48 log.error("", e);49 }50 }5152 /**53 * 多个内容在一个字段中进行查询54 */55 public void termsQuery() {56 try {57 // 构建查询条件(注意:termsQuery 支持多种格式查询,如 boolean、int、double、string 等,这里使用的是 string 的查询)58 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();59 searchSourceBuilder.query(QueryBuilders.termsQuery("address.keyword", "北京市丰台区", "北京市昌平区", "北京市大兴区"));60 // 创建查询请求对象,将查询对象配置到其中61 SearchRequest searchRequest = new SearchRequest("mydlq-user");62 searchRequest.source(searchSourceBuilder);63 // 执行查询,然后处理响应结果64 SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);65 // 根据状态和数据条数验证是否返回了数据66 if (RestStatus.OK.equals(searchResponse.status()) && searchResponse.getHits().totalHits > 0) {67 SearchHits hits = searchResponse.getHits();68 for (SearchHit hit : hits) {69 // 将 JSON 转换成对象70 UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class);71 // 输出查询信息72 log.info(userInfo.toString());73 }74 }75 } catch (IOException e) {76 log.error("", e);77 }78 }7980}
2、匹配查询(match)
(1)、Restful 操作示例
匹配查询全部数据与分页
匹配查询符合条件的所有数据,并且设置以 salary
字段升序排序,并设置分页:
1GET mydlq-user/_search 2{ 3 "query": { 4 "match_all": {} 5 }, 6 "from": 0, 7 "size": 10, 8 "sort": [ 9 {10 "salary": {11 "order": "asc"12 }13 }14 ]15}
匹配查询数据
匹配查询地址为 通州区
的数据:
1GET mydlq-user/_search2{3 "query": {4 "match": {5 "address": "通州区"6 }7 }8}
词语匹配查询
词语匹配进行查询,匹配 address
中为 北京市通州区
的员工信息:
1GET mydlq-user/_search2{3 "query": {4 "match_phrase": {5 "address": "北京市通州区"6 }7 }8}
内容多字段查询
查询在字段 address
、remark
中存在 北京
内容的员工信息:
1GET mydlq-user/_search2{3 "query": {4 "multi_match": {5 "query": "北京",6 "fields": ["address","remark"]7 }8 }9}
(2)、Java 代码示例
1import club.mydlq.elasticsearch.model.entity.UserInfo; 2import com.alibaba.fastjson.JSON; 3import lombok.extern.slf4j.Slf4j; 4import org.elasticsearch.action.search.SearchRequest; 5import org.elasticsearch.action.search.SearchResponse; 6import org.elasticsearch.client.RequestOptions; 7import org.elasticsearch.client.RestHighLevelClient; 8import org.elasticsearch.index.query.MatchAllQueryBuilder; 9import org.elasticsearch.index.query.QueryBuilders; 10import org.elasticsearch.rest.RestStatus; 11import org.elasticsearch.search.SearchHit; 12import org.elasticsearch.search.SearchHits; 13import org.elasticsearch.search.builder.SearchSourceBuilder; 14import org.elasticsearch.search.sort.SortOrder; 15import org.springframework.beans.factory.annotation.Autowired; 16import org.springframework.stereotype.Service; 17import java.io.IOException; 18 19@Slf4j 20@Service 21public class MatchQueryService { 22 23 @Autowired 24 private RestHighLevelClient restHighLevelClient; 25 26 /** 27 * 匹配查询符合条件的所有数据,并设置分页 28 */ 29 public Object matchAllQuery() { 30 try { 31 // 构建查询条件 32 MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery(); 33 // 创建查询源构造器 34 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); 35 searchSourceBuilder.query(matchAllQueryBuilder); 36 // 设置分页 37 searchSourceBuilder.from(0); 38 searchSourceBuilder.size(3); 39 // 设置排序 40 searchSourceBuilder.sort("salary", SortOrder.ASC); 41 // 创建查询请求对象,将查询对象配置到其中 42 SearchRequest searchRequest = new SearchRequest("mydlq-user"); 43 searchRequest.source(searchSourceBuilder); 44 // 执行查询,然后处理响应结果 45 SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); 46 // 根据状态和数据条数验证是否返回了数据 47 if (RestStatus.OK.equals(searchResponse.status()) && searchResponse.getHits().totalHits > 0) { 48 SearchHits hits = searchResponse.getHits(); 49 for (SearchHit hit : hits) { 50 // 将 JSON 转换成对象 51 UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class); 52 // 输出查询信息 53 log.info(userInfo.toString()); 54 } 55 } 56 } catch (IOException e) { 57 log.error("", e); 58 } 59 } 60 61 /** 62 * 匹配查询数据 63 */ 64 public Object matchQuery() { 65 try { 66 // 构建查询条件 67 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); 68 searchSourceBuilder.query(QueryBuilders.matchQuery("address", "*通州区")); 69 // 创建查询请求对象,将查询对象配置到其中 70 SearchRequest searchRequest = new SearchRequest("mydlq-user"); 71 searchRequest.source(searchSourceBuilder); 72 // 执行查询,然后处理响应结果 73 SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); 74 // 根据状态和数据条数验证是否返回了数据 75 if (RestStatus.OK.equals(searchResponse.status()) && searchResponse.getHits().totalHits > 0) { 76 SearchHits hits = searchResponse.getHits(); 77 for (SearchHit hit : hits) { 78 // 将 JSON 转换成对象 79 UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class); 80 // 输出查询信息 81 log.info(userInfo.toString()); 82 } 83 } 84 } catch (IOException e) { 85 log.error("", e); 86 } 87 } 88 89 /** 90 * 词语匹配查询 91 */ 92 public Object matchPhraseQuery() { 93 try { 94 // 构建查询条件 95 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); 96 searchSourceBuilder.query(QueryBuilders.matchPhraseQuery("address", "北京市通州区")); 97 // 创建查询请求对象,将查询对象配置到其中 98 SearchRequest searchRequest = new SearchRequest("mydlq-user"); 99 searchRequest.source(searchSourceBuilder);100 // 执行查询,然后处理响应结果101 SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);102 // 根据状态和数据条数验证是否返回了数据103 if (RestStatus.OK.equals(searchResponse.status()) && searchResponse.getHits().totalHits > 0) {104 SearchHits hits = searchResponse.getHits();105 for (SearchHit hit : hits) {106 // 将 JSON 转换成对象107 UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class);108 // 输出查询信息109 log.info(userInfo.toString());110 }111 }112 } catch (IOException e) {113 log.error("", e);114 }115 }116117 /**118 * 内容在多字段中进行查询119 */120 public Object matchMultiQuery() {121 try {122 // 构建查询条件123 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();124 searchSourceBuilder.query(QueryBuilders.multiMatchQuery("北京市", "address", "remark"));125 // 创建查询请求对象,将查询对象配置到其中126 SearchRequest searchRequest = new SearchRequest("mydlq-user");127 searchRequest.source(searchSourceBuilder);128 // 执行查询,然后处理响应结果129 SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);130 // 根据状态和数据条数验证是否返回了数据131 if (RestStatus.OK.equals(searchResponse.status()) && searchResponse.getHits().totalHits > 0) {132 SearchHits hits = searchResponse.getHits();133 for (SearchHit hit : hits) {134 // 将 JSON 转换成对象135 UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class);136 // 输出查询信息137 log.info(userInfo.toString());138 }139 }140 } catch (IOException e) {141 log.error("", e);142 }143 }144145}
3、模糊查询(fuzzy)
(1)、Restful 操作示例
模糊查询所有以 三
结尾的姓名
1GET mydlq-user/_search2{3 "query": {4 "fuzzy": {5 "name": "三"6 }7 }8}
(2)、Java 代码示例
1import club.mydlq.elasticsearch.model.entity.UserInfo; 2import com.alibaba.fastjson.JSON; 3import lombok.extern.slf4j.Slf4j; 4import org.elasticsearch.action.search.SearchRequest; 5import org.elasticsearch.action.search.SearchResponse; 6import org.elasticsearch.client.RequestOptions; 7import org.elasticsearch.client.RestHighLevelClient; 8import org.elasticsearch.common.unit.Fuzziness; 9import org.elasticsearch.index.query.QueryBuilders;10import org.elasticsearch.rest.RestStatus;11import org.elasticsearch.search.SearchHit;12import org.elasticsearch.search.SearchHits;13import org.elasticsearch.search.builder.SearchSourceBuilder;14import org.springframework.beans.factory.annotation.Autowired;15import org.springframework.stereotype.Service;16import java.io.IOException;1718@Slf4j19@Service20public class FuzzyQueryService {2122 @Autowired23 private RestHighLevelClient restHighLevelClient;2425 /**26 * 模糊查询所有以 “三” 结尾的姓名27 */28 public Object fuzzyQuery() {29 try {30 // 构建查询条件31 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();32 searchSourceBuilder.query(QueryBuilders.fuzzyQuery("name", "三").fuzziness(Fuzziness.AUTO));33 // 创建查询请求对象,将查询对象配置到其中34 SearchRequest searchRequest = new SearchRequest("mydlq-user");35 searchRequest.source(searchSourceBuilder);36 // 执行查询,然后处理响应结果37 SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);38 // 根据状态和数据条数验证是否返回了数据39 if (RestStatus.OK.equals(searchResponse.status()) && searchResponse.getHits().totalHits > 0) {40 SearchHits hits = searchResponse.getHits();41 for (SearchHit hit : hits) {42 // 将 JSON 转换成对象43 UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class);44 // 输出查询信息45 log.info(userInfo.toString());46 }47 }48 } catch (IOException e) {49 log.error("", e);50 }51 }5253}
4、范围查询(range)
(1)、Restful 操作示例
查询岁数 ≥ 30 岁的员工数据:
1GET /mydlq-user/_search 2{ 3 "query": { 4 "range": { 5 "age": { 6 "gte": 30 7 } 8 } 9 }10}
查询生日距离现在 30 年间的员工数据:
1GET mydlq-user/_search 2{ 3 "query": { 4 "range": { 5 "birthDate": { 6 "gte": "now-30y" 7 } 8 } 9 }10}
(2)、Java 代码示例
1import club.mydlq.elasticsearch.model.entity.UserInfo; 2import com.alibaba.fastjson.JSON; 3import lombok.extern.slf4j.Slf4j; 4import org.elasticsearch.action.search.SearchRequest; 5import org.elasticsearch.action.search.SearchResponse; 6import org.elasticsearch.client.RequestOptions; 7import org.elasticsearch.client.RestHighLevelClient; 8import org.elasticsearch.index.query.QueryBuilders; 9import org.elasticsearch.rest.RestStatus;10import org.elasticsearch.search.SearchHit;11import org.elasticsearch.search.SearchHits;12import org.elasticsearch.search.builder.SearchSourceBuilder;13import org.springframework.beans.factory.annotation.Autowired;14import org.springframework.stereotype.Service;15import java.io.IOException;1617@Slf4j18@Service19public class RangeQueryService {2021 @Autowired22 private RestHighLevelClient restHighLevelClient;2324 /**25 * 查询岁数 ≥ 30 岁的员工数据26 */27 public void rangeQuery() {28 try {29 // 构建查询条件30 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();31 searchSourceBuilder.query(QueryBuilders.rangeQuery("age").gte(30));32 // 创建查询请求对象,将查询对象配置到其中33 SearchRequest searchRequest = new SearchRequest("mydlq-user");34 searchRequest.source(searchSourceBuilder);35 // 执行查询,然后处理响应结果36 SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);37 // 根据状态和数据条数验证是否返回了数据38 if (RestStatus.OK.equals(searchResponse.status()) && searchResponse.getHits().totalHits > 0) {39 SearchHits hits = searchResponse.getHits();40 for (SearchHit hit : hits) {41 // 将 JSON 转换成对象42 UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class);43 // 输出查询信息44 log.info(userInfo.toString());45 }46 }47 } catch (IOException e) {48 log.error("", e);49 }50 }5152 /**53 * 查询距离现在 30 年间的员工数据54 * [年(y)、月(M)、星期(w)、天(d)、小时(h)、分钟(m)、秒(s)]55 * 例如:56 * now-1h 查询一小时内范围57 * now-1d 查询一天内时间范围58 * now-1y 查询最近一年内的时间范围59 */60 public void dateRangeQuery() {61 try {62 // 构建查询条件63 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();64 // includeLower(是否包含下边界)、includeUpper(是否包含上边界)65 searchSourceBuilder.query(QueryBuilders.rangeQuery("birthDate")66 .gte("now-30y").includeLower(true).includeUpper(true));67 // 创建查询请求对象,将查询对象配置到其中68 SearchRequest searchRequest = new SearchRequest("mydlq-user");69 searchRequest.source(searchSourceBuilder);70 // 执行查询,然后处理响应结果71 SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);72 // 根据状态和数据条数验证是否返回了数据73 if (RestStatus.OK.equals(searchResponse.status()) && searchResponse.getHits().totalHits > 0) {74 SearchHits hits = searchResponse.getHits();75 for (SearchHit hit : hits) {76 // 将 JSON 转换成对象77 UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class);78 // 输出查询信息79 log.info(userInfo.toString());80 }81 }82 } catch (IOException e) {83 log.error("", e);84 }85 }8687}
5、通配符查询(wildcard)
(1)、Restful 操作示例
查询所有以 “三” 结尾的姓名:
1GET mydlq-user/_search 2{ 3 "query": { 4 "wildcard": { 5 "name.keyword": { 6 "value": "*三" 7 } 8 } 9 }10}
(2)、Java 代码示例
1import club.mydlq.elasticsearch.model.entity.UserInfo; 2import com.alibaba.fastjson.JSON; 3import lombok.extern.slf4j.Slf4j; 4import org.elasticsearch.action.search.SearchRequest; 5import org.elasticsearch.action.search.SearchResponse; 6import org.elasticsearch.client.RequestOptions; 7import org.elasticsearch.client.RestHighLevelClient; 8import org.elasticsearch.index.query.QueryBuilders; 9import org.elasticsearch.rest.RestStatus;10import org.elasticsearch.search.SearchHit;11import org.elasticsearch.search.SearchHits;12import org.elasticsearch.search.builder.SearchSourceBuilder;13import org.springframework.beans.factory.annotation.Autowired;14import org.springframework.stereotype.Service;15import java.io.IOException;1617@Slf4j18@Service19public class WildcardQueryService {2021 @Autowired22 private RestHighLevelClient restHighLevelClient;2324 /**25 * 查询所有以 “三” 结尾的姓名26 *27 * *:表示多个字符(0个或多个字符)28 * ?:表示单个字符29 */30 public Object wildcardQuery() {31 try {32 // 构建查询条件33 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();34 searchSourceBuilder.query(QueryBuilders.wildcardQuery("name.keyword", "*三"));35 // 创建查询请求对象,将查询对象配置到其中36 SearchRequest searchRequest = new SearchRequest("mydlq-user");37 searchRequest.source(searchSourceBuilder);38 // 执行查询,然后处理响应结果39 SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);40 // 根据状态和数据条数验证是否返回了数据41 if (RestStatus.OK.equals(searchResponse.status()) && searchResponse.getHits().totalHits > 0) {42 SearchHits hits = searchResponse.getHits();43 for (SearchHit hit : hits) {44 // 将 JSON 转换成对象45 UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class);46 // 输出查询信息47 log.info(userInfo.toString());48 }49 }50 } catch (IOException e) {51 log.error("", e);52 }53 }5455}
6、布尔查询(bool)
(1)、Restful 操作示例
查询出生在 1990-1995 年期间,且地址在 北京市昌平区
、北京市大兴区
、北京市房山区
的员工信息:
1GET /mydlq-user/_search 2{ 3 "query": { 4 "bool": { 5 "filter": { 6 "range": { 7 "birthDate": { 8 "format": "yyyy", 9 "gte": 1990,10 "lte": 199511 }12 }13 },14 "must": [15 {16 "terms": {17 "address.keyword": [18 "北京市昌平区",19 "北京市大兴区",20 "北京市房山区"21 ]22 }23 }24 ]25 }26 }27}
(2)、Java 代码示例
1import club.mydlq.elasticsearch.model.entity.UserInfo; 2import com.alibaba.fastjson.JSON; 3import lombok.extern.slf4j.Slf4j; 4import org.elasticsearch.action.search.SearchRequest; 5import org.elasticsearch.action.search.SearchResponse; 6import org.elasticsearch.client.RequestOptions; 7import org.elasticsearch.client.RestHighLevelClient; 8import org.elasticsearch.index.query.BoolQueryBuilder; 9import org.elasticsearch.index.query.QueryBuilders;10import org.elasticsearch.rest.RestStatus;11import org.elasticsearch.search.SearchHit;12import org.elasticsearch.search.SearchHits;13import org.elasticsearch.search.builder.SearchSourceBuilder;14import org.springframework.beans.factory.annotation.Autowired;15import org.springframework.stereotype.Service;16import java.io.IOException;1718@Slf4j19@Service20public class BoolQueryService {2122 @Autowired23 private RestHighLevelClient restHighLevelClient;2425 public Object boolQuery() {26 try {27 // 创建 Bool 查询构建器28 BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();29 // 构建查询条件30 boolQueryBuilder.must(QueryBuilders.termsQuery("address.keyword", "北京市昌平区", "北京市大兴区", "北京市房山区"))31 .filter().add(QueryBuilders.rangeQuery("birthDate").format("yyyy").gte("1990").lte("1995"));32 // 构建查询源构建器33 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();34 searchSourceBuilder.query(boolQueryBuilder);35 // 创建查询请求对象,将查询对象配置到其中36 SearchRequest searchRequest = new SearchRequest("mydlq-user");37 searchRequest.source(searchSourceBuilder);38 // 执行查询,然后处理响应结果39 SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);40 // 根据状态和数据条数验证是否返回了数据41 if (RestStatus.OK.equals(searchResponse.status()) && searchResponse.getHits().totalHits > 0) {42 SearchHits hits = searchResponse.getHits();43 for (SearchHit hit : hits) {44 // 将 JSON 转换成对象45 UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class);46 // 输出查询信息47 log.info(userInfo.toString());48 }49 }50 }catch (IOException e){51 log.error("",e);52 }53 }5455}
八、聚合查询操作示例
1、Metric 聚合分析
(1)、Restful 操作示例
统计员工总数、工资最高值、工资最低值、工资平均工资、工资总和:
1GET /mydlq-user/_search 2{ 3 "size": 0, 4 "aggs": { 5 "salary_stats": { 6 "stats": { 7 "field": "salary" 8 } 9 }10 }11}
统计员工工资最低值:
1GET /mydlq-user/_search 2{ 3 "size": 0, 4 "aggs": { 5 "salary_min": { 6 "min": { 7 "field": "salary" 8 } 9 }10 }11}
统计员工工资最高值:
1GET /mydlq-user/_search 2{ 3 "size": 0, 4 "aggs": { 5 "salary_max": { 6 "max": { 7 "field": "salary" 8 } 9 }10 }11}
统计员工工资平均值:
1GET /mydlq-user/_search 2{ 3 "size": 0, 4 "aggs": { 5 "salary_avg": { 6 "avg": { 7 "field": "salary" 8 } 9 }10 }11}
统计员工工资总值:
1GET /mydlq-user/_search 2{ 3 "size": 0, 4 "aggs": { 5 "salary_sum": { 6 "sum": { 7 "field": "salary" 8 } 9 }10 }11}
统计员工总数:
1GET /mydlq-user/_search 2{ 3 "size": 0, 4 "aggs": { 5 "employee_count": { 6 "value_count": { 7 "field": "salary" 8 } 9 }10 }11}
统计员工工资百分位:
1GET /mydlq-user/_search 2{ 3 "size": 0, 4 "aggs": { 5 "salary_percentiles": { 6 "percentiles": { 7 "field": "salary" 8 } 9 }10 }11}
(2)、Java 代码示例
1import lombok.extern.slf4j.Slf4j; 2import org.elasticsearch.action.search.SearchRequest; 3import org.elasticsearch.action.search.SearchResponse; 4import org.elasticsearch.client.RequestOptions; 5import org.elasticsearch.client.RestHighLevelClient; 6import org.elasticsearch.rest.RestStatus; 7import org.elasticsearch.search.aggregations.AggregationBuilder; 8import org.elasticsearch.search.aggregations.AggregationBuilders; 9import org.elasticsearch.search.aggregations.Aggregations; 10import org.elasticsearch.search.aggregations.metrics.avg.ParsedAvg; 11import org.elasticsearch.search.aggregations.metrics.max.ParsedMax; 12import org.elasticsearch.search.aggregations.metrics.min.ParsedMin; 13import org.elasticsearch.search.aggregations.metrics.percentiles.ParsedPercentiles; 14import org.elasticsearch.search.aggregations.metrics.percentiles.Percentile; 15import org.elasticsearch.search.aggregations.metrics.stats.ParsedStats; 16import org.elasticsearch.search.aggregations.metrics.sum.ParsedSum; 17import org.elasticsearch.search.aggregations.metrics.sum.SumAggregationBuilder; 18import org.elasticsearch.search.aggregations.metrics.valuecount.ParsedValueCount; 19import org.elasticsearch.search.builder.SearchSourceBuilder; 20import org.springframework.beans.factory.annotation.Autowired; 21import org.springframework.stereotype.Service; 22import java.io.IOException; 23 24@Slf4j 25@Service 26public class AggrMetricService { 27 28 @Autowired 29 private RestHighLevelClient restHighLevelClient; 30 31 /** 32 * stats 统计员工总数、员工工资最高值、员工工资最低值、员工平均工资、员工工资总和 33 */ 34 public Object aggregationStats() { 35 String responseResult = ""; 36 try { 37 // 设置聚合条件 38 AggregationBuilder aggr = AggregationBuilders.stats("salary_stats").field("salary"); 39 // 查询源构建器 40 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); 41 searchSourceBuilder.aggregation(aggr); 42 // 设置查询结果不返回,只返回聚合结果 43 searchSourceBuilder.size(0); 44 // 创建查询请求对象,将查询条件配置到其中 45 SearchRequest request = new SearchRequest("mydlq-user"); 46 request.source(searchSourceBuilder); 47 // 执行请求 48 SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT); 49 // 获取响应中的聚合信息 50 Aggregations aggregations = response.getAggregations(); 51 // 输出内容 52 if (RestStatus.OK.equals(response.status()) || aggregations != null) { 53 // 转换为 Stats 对象 54 ParsedStats aggregation = aggregations.get("salary_stats"); 55 log.info("-------------------------------------------"); 56 log.info("聚合信息:"); 57 log.info("count:{}", aggregation.getCount()); 58 log.info("avg:{}", aggregation.getAvg()); 59 log.info("max:{}", aggregation.getMax()); 60 log.info("min:{}", aggregation.getMin()); 61 log.info("sum:{}", aggregation.getSum()); 62 log.info("-------------------------------------------"); 63 } 64 // 根据具体业务逻辑返回不同结果,这里为了方便直接将返回响应对象Json串 65 responseResult = response.toString(); 66 } catch (IOException e) { 67 log.error("", e); 68 } 69 return responseResult; 70 } 71 72 /** 73 * min 统计员工工资最低值 74 */ 75 public Object aggregationMin() { 76 String responseResult = ""; 77 try { 78 // 设置聚合条件 79 AggregationBuilder aggr = AggregationBuilders.min("salary_min").field("salary"); 80 // 查询源构建器 81 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); 82 searchSourceBuilder.aggregation(aggr); 83 searchSourceBuilder.size(0); 84 // 创建查询请求对象,将查询条件配置到其中 85 SearchRequest request = new SearchRequest("mydlq-user"); 86 request.source(searchSourceBuilder); 87 // 执行请求 88 SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT); 89 // 获取响应中的聚合信息 90 Aggregations aggregations = response.getAggregations(); 91 // 输出内容 92 if (RestStatus.OK.equals(response.status()) || aggregations != null) { 93 // 转换为 Min 对象 94 ParsedMin aggregation = aggregations.get("salary_min"); 95 log.info("-------------------------------------------"); 96 log.info("聚合信息:"); 97 log.info("min:{}", aggregation.getValue()); 98 log.info("-------------------------------------------"); 99 }100 // 根据具体业务逻辑返回不同结果,这里为了方便直接将返回响应对象Json串101 responseResult = response.toString();102 } catch (IOException e) {103 log.error("", e);104 }105 return responseResult;106 }107108 /**109 * max 统计员工工资最高值110 */111 public Object aggregationMax() {112 String responseResult = "";113 try {114 // 设置聚合条件115 AggregationBuilder aggr = AggregationBuilders.max("salary_max").field("salary");116 // 查询源构建器117 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();118 searchSourceBuilder.aggregation(aggr);119 searchSourceBuilder.size(0);120 // 创建查询请求对象,将查询条件配置到其中121 SearchRequest request = new SearchRequest("mydlq-user");122 request.source(searchSourceBuilder);123 // 执行请求124 SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);125 // 获取响应中的聚合信息126 Aggregations aggregations = response.getAggregations();127 // 输出内容128 if (RestStatus.OK.equals(response.status()) || aggregations != null) {129 // 转换为 Max 对象130 ParsedMax aggregation = aggregations.get("salary_max");131 log.info("-------------------------------------------");132 log.info("聚合信息:");133 log.info("max:{}", aggregation.getValue());134 log.info("-------------------------------------------");135 }136 // 根据具体业务逻辑返回不同结果,这里为了方便直接将返回响应对象Json串137 responseResult = response.toString();138 } catch (IOException e) {139 log.error("", e);140 }141 return responseResult;142 }143144 /**145 * avg 统计员工工资平均值146 */147 public Object aggregationAvg() {148 String responseResult = "";149 try {150 // 设置聚合条件151 AggregationBuilder aggr = AggregationBuilders.avg("salary_avg").field("salary");152 // 查询源构建器153 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();154 searchSourceBuilder.aggregation(aggr);155 searchSourceBuilder.size(0);156 // 创建查询请求对象,将查询条件配置到其中157 SearchRequest request = new SearchRequest("mydlq-user");158 request.source(searchSourceBuilder);159 // 执行请求160 SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);161 // 获取响应中的聚合信息162 Aggregations aggregations = response.getAggregations();163 // 输出内容164 if (RestStatus.OK.equals(response.status()) || aggregations != null) {165 // 转换为 Avg 对象166 ParsedAvg aggregation = aggregations.get("salary_avg");167 log.info("-------------------------------------------");168 log.info("聚合信息:");169 log.info("avg:{}", aggregation.getValue());170 log.info("-------------------------------------------");171 }172 // 根据具体业务逻辑返回不同结果,这里为了方便直接将返回响应对象Json串173 responseResult = response.toString();174 } catch (IOException e) {175 log.error("", e);176 }177 return responseResult;178 }179180 /**181 * sum 统计员工工资总值182 */183 public Object aggregationSum() {184 String responseResult = "";185 try {186 // 设置聚合条件187 SumAggregationBuilder aggr = AggregationBuilders.sum("salary_sum").field("salary");188 // 查询源构建器189 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();190 searchSourceBuilder.aggregation(aggr);191 searchSourceBuilder.size(0);192 // 创建查询请求对象,将查询条件配置到其中193 SearchRequest request = new SearchRequest("mydlq-user");194 request.source(searchSourceBuilder);195 // 执行请求196 SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);197 // 获取响应中的聚合信息198 Aggregations aggregations = response.getAggregations();199 // 输出内容200 if (RestStatus.OK.equals(response.status()) || aggregations != null) {201 // 转换为 Sum 对象202 ParsedSum aggregation = aggregations.get("salary_sum");203 log.info("-------------------------------------------");204 log.info("聚合信息:");205 log.info("sum:{}", String.valueOf((aggregation.getValue())));206 log.info("-------------------------------------------");207 }208 // 根据具体业务逻辑返回不同结果,这里为了方便直接将返回响应对象Json串209 responseResult = response.toString();210 } catch (IOException e) {211 log.error("", e);212 }213 return responseResult;214 }215216 /**217 * count 统计员工总数218 */219 public Object aggregationCount() {220 String responseResult = "";221 try {222 // 设置聚合条件223 AggregationBuilder aggr = AggregationBuilders.count("employee_count").field("salary");224 // 查询源构建器225 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();226 searchSourceBuilder.aggregation(aggr);227 searchSourceBuilder.size(0);228 // 创建查询请求对象,将查询条件配置到其中229 SearchRequest request = new SearchRequest("mydlq-user");230 request.source(searchSourceBuilder);231 // 执行请求232 SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);233 // 获取响应中的聚合信息234 Aggregations aggregations = response.getAggregations();235 // 输出内容236 if (RestStatus.OK.equals(response.status()) || aggregations != null) {237 // 转换为 ValueCount 对象238 ParsedValueCount aggregation = aggregations.get("employee_count");239 log.info("-------------------------------------------");240 log.info("聚合信息:");241 log.info("count:{}", aggregation.getValue());242 log.info("-------------------------------------------");243 }244 // 根据具体业务逻辑返回不同结果,这里为了方便直接将返回响应对象Json串245 responseResult = response.toString();246 } catch (IOException e) {247 log.error("", e);248 }249 return responseResult;250 }251252 /**253 * percentiles 统计员工工资百分位254 */255 public Object aggregationPercentiles() {256 String responseResult = "";257 try {258 // 设置聚合条件259 AggregationBuilder aggr = AggregationBuilders.percentiles("salary_percentiles").field("salary");260 // 查询源构建器261 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();262 searchSourceBuilder.aggregation(aggr);263 searchSourceBuilder.size(0);264 // 创建查询请求对象,将查询条件配置到其中265 SearchRequest request = new SearchRequest("mydlq-user");266 request.source(searchSourceBuilder);267 // 执行请求268 SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);269 // 获取响应中的聚合信息270 Aggregations aggregations = response.getAggregations();271 // 输出内容272 if (RestStatus.OK.equals(response.status()) || aggregations != null) {273 // 转换为 Percentiles 对象274 ParsedPercentiles aggregation = aggregations.get("salary_percentiles");275 log.info("-------------------------------------------");276 log.info("聚合信息:");277 for (Percentile percentile : aggregation) {278 log.info("百分位:{}:{}", percentile.getPercent(), percentile.getValue());279 }280 log.info("-------------------------------------------");281 }282 // 根据具体业务逻辑返回不同结果,这里为了方便直接将返回响应对象Json串283 responseResult = response.toString();284 } catch (IOException e) {285 log.error("", e);286 }287 return responseResult;288 }289290}
2、Bucket 聚合分析
(1)、Restful 操作示例
按岁数进行聚合分桶,统计各个岁数员工的人数:
1GET mydlq-user/_search 2{ 3 "size": 0, 4 "aggs": { 5 "age_bucket": { 6 "terms": { 7 "field": "age", 8 "size": "10" 9 }10 }11 }12}
按工资范围进行聚合分桶,统计工资在 3000-5000、5000-9000 和 9000 以上的员工信息:
1GET mydlq-user/_search 2{ 3 "aggs": { 4 "salary_range_bucket": { 5 "range": { 6 "field": "salary", 7 "ranges": [ 8 { 9 "key": "低级员工", 10 "to": 300011 },{12 "key": "中级员工",13 "from": 5000,14 "to": 900015 },{16 "key": "高级员工",17 "from": 900018 }19 ]20 }21 }22 }23}
按照时间范围进行分桶,统计 1985-1990 年和 1990-1995 年出生的员工信息:
1GET mydlq-user/_search 2{ 3 "size": 10, 4 "aggs": { 5 "date_range_bucket": { 6 "date_range": { 7 "field": "birthDate", 8 "format": "yyyy", 9 "ranges": [10 {11 "key": "出生日期1985-1990的员工", 12 "from": "1985",13 "to": "1990"14 },{15 "key": "出生日期1990-1995的员工", 16 "from": "1990",17 "to": "1995"18 }19 ]20 }21 }22 }23}
按工资多少进行聚合分桶,设置统计的最小值为 0,最大值为 12000,区段间隔为 3000:
1GET mydlq-user/_search 2{ 3 "size": 0, 4 "aggs": { 5 "salary_histogram": { 6 "histogram": { 7 "field": "salary", 8 "extended_bounds": { 9 "min": 0,10 "max": 1200011 }, 12 "interval": 300013 }14 }15 }16}
按出生日期进行分桶:
1GET mydlq-user/_search 2{ 3 "size": 0, 4 "aggs": { 5 "birthday_histogram": { 6 "date_histogram": { 7 "format": "yyyy", 8 "field": "birthDate", 9 "interval": "year"10 }11 }12 }13}
(2)、Java 代码示例
1import lombok.extern.slf4j.Slf4j; 2import org.elasticsearch.action.search.SearchRequest; 3import org.elasticsearch.action.search.SearchResponse; 4import org.elasticsearch.client.RequestOptions; 5import org.elasticsearch.client.RestHighLevelClient; 6import org.elasticsearch.rest.RestStatus; 7import org.elasticsearch.search.aggregations.AggregationBuilder; 8import org.elasticsearch.search.aggregations.AggregationBuilders; 9import org.elasticsearch.search.aggregations.Aggregations; 10import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval; 11import org.elasticsearch.search.aggregations.bucket.histogram.Histogram; 12import org.elasticsearch.search.aggregations.bucket.range.Range; 13import org.elasticsearch.search.aggregations.bucket.terms.Terms; 14import org.elasticsearch.search.builder.SearchSourceBuilder; 15import org.springframework.beans.factory.annotation.Autowired; 16import org.springframework.stereotype.Service; 17import java.io.IOException; 18import java.util.List; 19 20@Slf4j 21@Service 22public class AggrBucketService { 23 24 @Autowired 25 private RestHighLevelClient restHighLevelClient; 26 27 /** 28 * 按岁数进行聚合分桶 29 */ 30 public Object aggrBucketTerms() { 31 try { 32 AggregationBuilder aggr = AggregationBuilders.terms("age_bucket").field("age"); 33 // 查询源构建器 34 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); 35 searchSourceBuilder.size(10); 36 searchSourceBuilder.aggregation(aggr); 37 // 创建查询请求对象,将查询条件配置到其中 38 SearchRequest request = new SearchRequest("mydlq-user"); 39 request.source(searchSourceBuilder); 40 // 执行请求 41 SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT); 42 // 获取响应中的聚合信息 43 Aggregations aggregations = response.getAggregations(); 44 // 输出内容 45 if (RestStatus.OK.equals(response.status())) { 46 // 分桶 47 Terms byCompanyAggregation = aggregations.get("age_bucket"); 48 List extends Terms.Bucket> buckets = byCompanyAggregation.getBuckets(); 49 // 输出各个桶的内容 50 log.info("-------------------------------------------"); 51 log.info("聚合信息:"); 52 for (Terms.Bucket bucket : buckets) { 53 log.info("桶名:{} | 总数:{}", bucket.getKeyAsString(), bucket.getDocCount()); 54 } 55 log.info("-------------------------------------------"); 56 } 57 } catch (IOException e) { 58 log.error("", e); 59 } 60 } 61 62 /** 63 * 按工资范围进行聚合分桶 64 */ 65 public Object aggrBucketRange() { 66 try { 67 AggregationBuilder aggr = AggregationBuilders.range("salary_range_bucket") 68 .field("salary") 69 .addUnboundedTo("低级员工", 3000) 70 .addRange("中级员工", 5000, 9000) 71 .addUnboundedFrom("高级员工", 9000); 72 // 查询源构建器 73 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); 74 searchSourceBuilder.size(0); 75 searchSourceBuilder.aggregation(aggr); 76 // 创建查询请求对象,将查询条件配置到其中 77 SearchRequest request = new SearchRequest("mydlq-user"); 78 request.source(searchSourceBuilder); 79 // 执行请求 80 SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT); 81 // 获取响应中的聚合信息 82 Aggregations aggregations = response.getAggregations(); 83 // 输出内容 84 if (RestStatus.OK.equals(response.status())) { 85 // 分桶 86 Range byCompanyAggregation = aggregations.get("salary_range_bucket"); 87 List extends Range.Bucket> buckets = byCompanyAggregation.getBuckets(); 88 // 输出各个桶的内容 89 log.info("-------------------------------------------"); 90 log.info("聚合信息:"); 91 for (Range.Bucket bucket : buckets) { 92 log.info("桶名:{} | 总数:{}", bucket.getKeyAsString(), bucket.getDocCount()); 93 } 94 log.info("-------------------------------------------"); 95 } 96 } catch (IOException e) { 97 log.error("", e); 98 } 99 }100101 /**102 * 按照时间范围进行分桶103 */104 public Object aggrBucketDateRange() {105 try {106 AggregationBuilder aggr = AggregationBuilders.dateRange("date_range_bucket")107 .field("birthDate")108 .format("yyyy")109 .addRange("1985-1990", "1985", "1990")110 .addRange("1990-1995", "1990", "1995");111 // 查询源构建器112 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();113 searchSourceBuilder.size(0);114 searchSourceBuilder.aggregation(aggr);115 // 创建查询请求对象,将查询条件配置到其中116 SearchRequest request = new SearchRequest("mydlq-user");117 request.source(searchSourceBuilder);118 // 执行请求119 SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);120 // 获取响应中的聚合信息121 Aggregations aggregations = response.getAggregations();122 // 输出内容123 if (RestStatus.OK.equals(response.status())) {124 // 分桶125 Range byCompanyAggregation = aggregations.get("date_range_bucket");126 List extends Range.Bucket> buckets = byCompanyAggregation.getBuckets();127 // 输出各个桶的内容128 log.info("-------------------------------------------");129 log.info("聚合信息:");130 for (Range.Bucket bucket : buckets) {131 log.info("桶名:{} | 总数:{}", bucket.getKeyAsString(), bucket.getDocCount());132 }133 log.info("-------------------------------------------");134 }135 } catch (IOException e) {136 log.error("", e);137 }138 }139140 /**141 * 按工资多少进行聚合分桶142 */143 public Object aggrBucketHistogram() {144 try {145 AggregationBuilder aggr = AggregationBuilders.histogram("salary_histogram")146 .field("salary")147 .extendedBounds(0, 12000)148 .interval(3000);149 // 查询源构建器150 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();151 searchSourceBuilder.size(0);152 searchSourceBuilder.aggregation(aggr);153 // 创建查询请求对象,将查询条件配置到其中154 SearchRequest request = new SearchRequest("mydlq-user");155 request.source(searchSourceBuilder);156 // 执行请求157 SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);158 // 获取响应中的聚合信息159 Aggregations aggregations = response.getAggregations();160 // 输出内容161 if (RestStatus.OK.equals(response.status())) {162 // 分桶163 Histogram byCompanyAggregation = aggregations.get("salary_histogram");164 List extends Histogram.Bucket> buckets = byCompanyAggregation.getBuckets();165 // 输出各个桶的内容166 log.info("-------------------------------------------");167 log.info("聚合信息:");168 for (Histogram.Bucket bucket : buckets) {169 log.info("桶名:{} | 总数:{}", bucket.getKeyAsString(), bucket.getDocCount());170 }171 log.info("-------------------------------------------");172 }173 } catch (IOException e) {174 log.error("", e);175 }176 }177178 /**179 * 按出生日期进行分桶180 */181 public Object aggrBucketDateHistogram() {182 try {183 AggregationBuilder aggr = AggregationBuilders.dateHistogram("birthday_histogram")184 .field("birthDate")185 .interval(1)186 .dateHistogramInterval(DateHistogramInterval.YEAR)187 .format("yyyy");188 // 查询源构建器189 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();190 searchSourceBuilder.size(0);191 searchSourceBuilder.aggregation(aggr);192 // 创建查询请求对象,将查询条件配置到其中193 SearchRequest request = new SearchRequest("mydlq-user");194 request.source(searchSourceBuilder);195 // 执行请求196 SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);197 // 获取响应中的聚合信息198 Aggregations aggregations = response.getAggregations();199 // 输出内容200 if (RestStatus.OK.equals(response.status())) {201 // 分桶202 Histogram byCompanyAggregation = aggregations.get("birthday_histogram");203204 List extends Histogram.Bucket> buckets = byCompanyAggregation.getBuckets();205 // 输出各个桶的内容206 log.info("-------------------------------------------");207 log.info("聚合信息:");208 for (Histogram.Bucket bucket : buckets) {209 log.info("桶名:{} | 总数:{}", bucket.getKeyAsString(), bucket.getDocCount());210 }211 log.info("-------------------------------------------");212 }213 } catch (IOException e) {214 log.error("", e);215 }216 }217218}
3、Metric 与 Bucket 聚合分析
(1)、Restful 操作示例
按照员工岁数分桶、然后统计每个岁数员工工资最高值:
1GET mydlq-user/_search 2{ 3 "size": 0, 4 "aggs": { 5 "salary_bucket": { 6 "terms": { 7 "field": "age", 8 "size": "10" 9 },10 "aggs": {11 "salary_max_user": {12 "top_hits": {13 "size": 1,14 "sort": [15 {16 "salary": {17 "order": "desc"18 }19 }20 ]21 }22 }23 }24 }25 }26}
(2)、Java 代码示例
1import lombok.extern.slf4j.Slf4j; 2import org.elasticsearch.action.search.SearchRequest; 3import org.elasticsearch.action.search.SearchResponse; 4import org.elasticsearch.client.RequestOptions; 5import org.elasticsearch.client.RestHighLevelClient; 6import org.elasticsearch.rest.RestStatus; 7import org.elasticsearch.search.SearchHit; 8import org.elasticsearch.search.aggregations.AggregationBuilder; 9import org.elasticsearch.search.aggregations.AggregationBuilders;10import org.elasticsearch.search.aggregations.Aggregations;11import org.elasticsearch.search.aggregations.bucket.terms.Terms;12import org.elasticsearch.search.aggregations.metrics.tophits.ParsedTopHits;13import org.elasticsearch.search.builder.SearchSourceBuilder;14import org.elasticsearch.search.sort.SortOrder;15import org.springframework.beans.factory.annotation.Autowired;16import org.springframework.stereotype.Service;17import java.io.IOException;18import java.util.List;1920@Slf4j21@Service22public class AggrBucketMetricService {2324 @Autowired25 private RestHighLevelClient restHighLevelClient;2627 /**28 * topHits 按岁数分桶、然后统计每个员工工资最高值29 */30 public Object aggregationTopHits() {31 try {32 AggregationBuilder testTop = AggregationBuilders.topHits("salary_max_user")33 .size(1)34 .sort("salary", SortOrder.DESC);35 AggregationBuilder salaryBucket = AggregationBuilders.terms("salary_bucket")36 .field("age")37 .size(10);38 salaryBucket.subAggregation(testTop);39 // 查询源构建器40 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();41 searchSourceBuilder.size(0);42 searchSourceBuilder.aggregation(salaryBucket);43 // 创建查询请求对象,将查询条件配置到其中44 SearchRequest request = new SearchRequest("mydlq-user");45 request.source(searchSourceBuilder);46 // 执行请求47 SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);48 // 获取响应中的聚合信息49 Aggregations aggregations = response.getAggregations();50 // 输出内容51 if (RestStatus.OK.equals(response.status())) {52 // 分桶53 Terms byCompanyAggregation = aggregations.get("salary_bucket");54 List extends Terms.Bucket> buckets = byCompanyAggregation.getBuckets();55 // 输出各个桶的内容56 log.info("-------------------------------------------");57 log.info("聚合信息:");58 for (Terms.Bucket bucket : buckets) {59 log.info("桶名:{}", bucket.getKeyAsString());60 ParsedTopHits topHits = bucket.getAggregations().get("salary_max_user");61 for (SearchHit hit:topHits.getHits()){62 log.info(hit.getSourceAsString());63 }64 }65 log.info("-------------------------------------------");66 }67 } catch (IOException e) {68 log.error("", e);69 }70 }7172}
● SpringBoot 使用 Caffeine 本地缓存
● Github推出了GitHub CLI
● (很全面)SpringBoot 集成 Apollo 配置中心
● 你知道如何成为一名靠谱的架构师不?
● Tomcat 在 SpringBoot 中是如何启动的?
● SpringBoot 深度调优,让你的项目飞起来!
● 8种经常被忽视的SQL错误用法,你有没有踩过坑?
● Java面试应该知道之深入理解Java的接口和抽象类
● Spring系列之beanFactory与ApplicationContext
● 多线程同步的五种方法
● redis应用场景
● 手把手带你剖析 Springboot 启动原理!
● Java多线程:synchronized关键字和Lock
● Java多线程:多线程基础知识
● Kafka基本架构及原理
springboot实体映射到数据库_SpringBoot 操作 ElasticSearch 详解相关推荐
- ElasticSearch-.net平台下c#操作ElasticSearch详解
ElasticSearch系列学习 ElasticSearch第一步-环境配置 ElasticSearch第二步-CRUD之Sense ElasticSearch第三步-中文分词 ElasticSea ...
- golang操作elasticsearch详解
golang操作elasticsearch详解 直接上代码 package mainimport ("bytes""context""fmt" ...
- SpringBoot 操作 ElasticSearch 详解(万字长文)
点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 作者:超级小豆丁 http://www.mydlq.club/ar ...
- 5万字长文!SpringBoot 操作 ElasticSearch 详解
点击上方 "程序员小乐"关注, 星标或置顶一起成长 每天凌晨00点00分, 第一时间与你相约 每日英文 No one can go to bear for you, no one ...
- springboot自动配置的原理_SpringBoot实战:详解SpringBoot自动配置原理
SpringBoot 自动配置主要通过 @EnableAutoConfiguration, @Conditional, @EnableConfigurationProperties 或者 @Confi ...
- [Python从零到壹] 八.数据库之MySQL和Sqlite基础知识及操作万字详解
欢迎大家来到"Python从零到壹",在这里我将分享约200篇Python系列文章,带大家一起去学习和玩耍,看看Python这个有趣的世界.所有文章都将结合案例.代码和作者的经验讲 ...
- Java操作MongoDB详解
Java操作MongoDB详解 1. MongoDB概述 1.1 MongoDB简介 1.2 MongoDB概念 2. MongoDB安装 2.1 MongoDB下载 2.2 MongoDB安装 2. ...
- vsftp建立虚拟用户不同目录分配不同权限操作步骤详解
这篇文章主要介绍了vsftp建立虚拟用户不同目录分配不同权限操作步骤详解,大家参考设置自己的FTP服务器吧vsftpd服务器同时支持匿名用户.本地用户和虚拟用户三类用户账号,使用虚拟用户账号可以提供集 ...
- oracle数据库中索值,Oracle数据库中的索引详解
Oracle数据库中的索引详解以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 一 ROWID的概念 存储了row在数据文 ...
最新文章
- 系统架构的过程 浮现式设计
- linux sa 命令,Linux 常用命令全拼
- 代理模式、动态代理和面向方面
- 启动两个Tomcat的方法
- vue 对象里面放数组刷新问题_Vue 数组和对象更新,但是页面没有刷新的解决方式...
- [故障引起的故事]URL中带加号(+)的处理
- 探索 .NET Core 依赖注入的 IServiceCollection
- wamp替换mysql_将wamp集成的mysql替换成安装版的
- Shell 编程:Bash空格的那点事
- 微服务间保持事务一致性
- hget如何获取多个value_《深入微服务》之 如何给老婆解释什么是微服务的基础框架SpringBoot?...
- QTP连接数据库,并将数据保存至Excel中
- excel多列数据生成图分类有间隔
- ida 反编译 php,飘云阁安全论坛在IDA pro中的这样一段反编译代码能够改写成易语言吗 - Powered by Discuz!...
- matlab神经网络结果怎么看,matlab神经网络实验报告
- 神仙道玄奇套装材料大全
- 电脑连接另一台电脑发出wifi时,显示ip4无访问权限,ip6无访问权限
- 云朵怎么画好看?超简单的天空上色教程
- Python量化选股入门:资本资产定价模型(CAPM)
- 没有群晖却要共享文件?试试HFS搭建精简版NAS吧
热门文章
- 一个模型搞定多个CTR业务!阿里STAR网络介绍(附代码实现)
- addeventlistener不支持ajax_好程序员web前端学习路线分享了解AJAX是什么
- http抓包实战 pdf_抓包实战 | 浏览器里的HTTP请求到底是如何完成的?
- Google浏览器一开启就提示“请停用以开发者模式运行的扩展程序“解决方案
- Python3爬虫入门之beautifulsoup库的使用
- JavaScript逻辑运算符
- 尼克老湿の面试回顾(7)
- Java自动化测试框架-06 - 来给你的测试报告化个妆整个形 - (下)(详细教程)
- log4j 日志级别_log4j-Mybatis(5)
- python安卓版开发环境搭建_python+appium环境搭建