查看原文
其他

SpringBoot 操作 ElasticSearch 详解

超级小豆丁 SpringForAll社区 2021-05-26
点击上方☝SpringForAll社区 轻松关注!
及时获取有趣有料的技术文章

本文来源: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}

内容多字段查询

查询在字段 addressremark 中存在 北京 内容的员工信息:

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("中级员工"50009000)
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(012000)
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 使用 Caffeine 本地缓存

● Github推出了GitHub CLI

● (很全面)SpringBoot 集成 Apollo 配置中心

● 你知道如何成为一名靠谱的架构师不?

● Tomcat 在 SpringBoot 中是如何启动的?

● SpringBoot 深度调优,让你的项目飞起来!

● 8种经常被忽视的SQL错误用法,你有没有踩过坑?

● Java面试应该知道之深入理解Java的接口和抽象类

● Spring系列之beanFactory与ApplicationContext

● 多线程同步的五种方法

● redis应用场景

● 手把手带你剖析 Springboot 启动原理!

● Java多线程:synchronized关键字和Lock

● Java多线程:多线程基础知识

● Kafka基本架构及原理



    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存