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.0</modelVersion>
5 <parent>
6 <groupId>org.springframework.boot</groupId>
7 <artifactId>spring-boot-starter-parent</artifactId>
8 <version>2.2.4.RELEASE</version>
9 <relativePath/> <!-- lookup parent from repository -->
10 </parent>
11 <groupId>club.mydlq</groupId>
12 <artifactId>springboot-elasticsearch-example</artifactId>
13 <version>0.0.1-SNAPSHOT</version>
14 <name>springboot-elasticsearch-example</name>
15 <description>Demo project for Spring Boot ElasticSearch</description>
16
17 <properties>
18 <java.version>1.8</java.version>
19 </properties>
20 <dependencies>
21 <!--web-->
22 <dependency>
23 <groupId>org.springframework.boot</groupId>
24 <artifactId>spring-boot-starter-web</artifactId>
25 </dependency>
26 <!--lombok-->
27 <dependency>
28 <groupId>org.projectlombok</groupId>
29 <artifactId>lombok</artifactId>
30 <optional>true</optional>
31 </dependency>
32 <!--fastjson-->
33 <dependency>
34 <groupId>com.alibaba</groupId>
35 <artifactId>fastjson</artifactId>
36 <version>1.2.61</version>
37 </dependency>
38 <!--elasticsearch-->
39 <dependency>
40 <groupId>org.elasticsearch.client</groupId>
41 <artifactId>elasticsearch-rest-high-level-client</artifactId>
42 <version>6.5.4</version>
43 </dependency>
44 <dependency>
45 <groupId>org.elasticsearch</groupId>
46 <artifactId>elasticsearch</artifactId>
47 <version>6.5.4</version>
48 </dependency>
49 </dependencies>
50
51 <build>
52 <plugins>
53 <plugin>
54 <groupId>org.springframework.boot</groupId>
55 <artifactId>spring-boot-maven-plugin</artifactId>
56 </plugin>
57 </plugins>
58 </build>
59
60</project>
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: http
11 address: 127.0.0.1:9200
12 connectTimeout: 5000
13 socketTimeout: 5000
14 connectionRequestTimeout: 5000
15 maxConnectNum: 100
16 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;
10
11/**
12 * ElasticSearch 配置
13 */
14@Configuration
15public class ElasticSearchConfig {
16
17 /** 协议 */
18 @Value("${elasticsearch.schema:http}")
19 private String schema;
20
21 /** 集群地址,如果有多个用“,”隔开 */
22 @Value("${elasticsearch.address}")
23 private String address;
24
25 /** 连接超时时间 */
26 @Value("${elasticsearch.connectTimeout:5000}")
27 private int connectTimeout;
28
29 /** Socket 连接超时时间 */
30 @Value("${elasticsearch.socketTimeout:10000}")
31 private int socketTimeout;
32
33 /** 获取连接的超时时间 */
34 @Value("${elasticsearch.connectionRequestTimeout:5000}")
35 private int connectionRequestTimeout;
36
37 /** 最大连接数 */
38 @Value("${elasticsearch.maxConnectNum:100}")
39 private int maxConnectNum;
40
41 /** 最大路由连接数 */
42 @Value("${elasticsearch.maxConnectPerRoute:100}")
43 private int maxConnectPerRoute;
44
45 @Bean
46 public RestHighLevelClient restHighLevelClient() {
47 // 拆分地址
48 List<HttpHost> 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 }
74
75}
四、索引操作示例
这里示例会指出通过 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 }
105
106}
五、文档操作示例
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": 100
10}
获取文档信息
获取 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": 100
10}
删除文档信息
删除之前创建的 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 }
111
112}
六、插入初始化数据
执行查询示例前,先往索引中插入一批数据:
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;
16
17@Slf4j
18@Service
19public class TermQueryService {
20
21 @Autowired
22 private RestHighLevelClient restHighLevelClient;
23
24 /**
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 }
51
52 /**
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 }
79
80}
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/_search
2{
3 "query": {
4 "match": {
5 "address": "通州区"
6 }
7 }
8}
词语匹配查询
词语匹配进行查询,匹配 address
中为 北京市通州区
的员工信息:
1GET mydlq-user/_search
2{
3 "query": {
4 "match_phrase": {
5 "address": "北京市通州区"
6 }
7 }
8}
内容多字段查询
查询在字段 address
、remark
中存在 北京
内容的员工信息:
1GET mydlq-user/_search
2{
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 }
116
117 /**
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 }
144
145}
3、模糊查询(fuzzy)
(1)、Restful 操作示例
模糊查询所有以 三
结尾的姓名
1GET mydlq-user/_search
2{
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;
17
18@Slf4j
19@Service
20public class FuzzyQueryService {
21
22 @Autowired
23 private RestHighLevelClient restHighLevelClient;
24
25 /**
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 }
52
53}
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;
16
17@Slf4j
18@Service
19public class RangeQueryService {
20
21 @Autowired
22 private RestHighLevelClient restHighLevelClient;
23
24 /**
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 }
51
52 /**
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 }
86
87}
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;
16
17@Slf4j
18@Service
19public class WildcardQueryService {
20
21 @Autowired
22 private RestHighLevelClient restHighLevelClient;
23
24 /**
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 }
54
55}
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": 1995
11 }
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;
17
18@Slf4j
19@Service
20public class BoolQueryService {
21
22 @Autowired
23 private RestHighLevelClient restHighLevelClient;
24
25 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 }
54
55}
八、聚合查询操作示例
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 }
107
108 /**
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 }
143
144 /**
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 }
179
180 /**
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 }
215
216 /**
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 }
251
252 /**
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 }
289
290}
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": 3000
11 },{
12 "key": "中级员工",
13 "from": 5000,
14 "to": 9000
15 },{
16 "key": "高级员工",
17 "from": 9000
18 }
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": 12000
11 },
12 "interval": 3000
13 }
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 }
100
101 /**
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 }
139
140 /**
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 }
177
178 /**
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");
203
204 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 }
217
218}
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;
19
20@Slf4j
21@Service
22public class AggrBucketMetricService {
23
24 @Autowired
25 private RestHighLevelClient restHighLevelClient;
26
27 /**
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 }
71
72}
● (很全面)SpringBoot 集成 Apollo 配置中心
● Tomcat 在 SpringBoot 中是如何启动的?
● Spring系列之beanFactory与ApplicationContext