赞
踩
注:文章皆为个人纪录,可用性请以最终结果为准,若有错还请大佬们指出,谢谢!
此文章重在spring boot中对6.3.2版本Es的各种操作,简单易学,暂不做基础概念梳理。
每个操作都已测试,请放心食用~~
注:此处引入 elasticsearch-rest-high-level-client 的Java客户端,并且与Es相关所有工具的版本需保持一致!
- <?xml version="1.0" encoding="UTF-8"?>
- <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-parent</artifactId>
- <version>2.5.4</version>
- <relativePath/> <!-- lookup parent from repository -->
- </parent>
- <groupId>com.es</groupId>
- <artifactId>example</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- <name>example</name>
- <description>Demo project for Elastic Search</description>
- <properties>
- <java.version>1.8</java.version>
- <elasticsearch.version>6.3.2</elasticsearch.version>
- <elasticsearch.clent.version>6.3.2</elasticsearch.clent.version>
- <fastjson.version>1.2.61</fastjson.version>
- <hutool.version>5.1.0</hutool.version>
- </properties>
-
-
- <dependencies>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
-
- <dependency>
- <groupId>org.projectlombok</groupId>
- <artifactId>lombok</artifactId>
- <optional>true</optional>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-test</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>fastjson</artifactId>
- <version>${fastjson.version}</version>
- </dependency>
-
- <dependency>
- <groupId>cn.hutool</groupId>
- <artifactId>hutool-all</artifactId>
- <version>${hutool.version}</version>
- </dependency>
-
- <!-- elasticsearch 依赖 -->
- <dependency>
- <groupId>org.elasticsearch</groupId>
- <artifactId>elasticsearch</artifactId>
- <version>${elasticsearch.version}</version>
- </dependency>
-
- <!-- elasticsearch Java操作客户端依赖 -->
- <dependency>
- <groupId>org.elasticsearch.client</groupId>
- <artifactId>elasticsearch-rest-high-level-client</artifactId>
- <version>${elasticsearch.clent.version}</version>
- </dependency>
- </dependencies>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-maven-plugin</artifactId>
- <configuration>
- <excludes>
- <exclude>
- <groupId>org.projectlombok</groupId>
- <artifactId>lombok</artifactId>
- </exclude>
- </excludes>
- </configuration>
- </plugin>
- </plugins>
- </build>
-
- </project>
配好Es相关信息
- server:
- port: 7777
-
- spring:
- application:
- name: EsStudyTest
-
- elasticsearch:
- schema: http # 协议
- address: 127.0.0.1:9200 # 连接地址(Es的 ip : port)
- connectTimeout: 5000 # 连接超时时间
- socketTimeout: 5000 # socket 连接超时时间
- connectionRequestTimeout: 5000 # 获取连接的超时时间
- maxConnectNum: 100 # 最大连接数
- maxConnectPerRoute: 100 # 最大路由连接数
-
获取 RestHighLevelClient 的入口
- package com.es.example.config;
-
- import org.apache.http.HttpHost;
- import org.elasticsearch.client.RestClient;
- import org.elasticsearch.client.RestClientBuilder;
- import org.elasticsearch.client.RestHighLevelClient;
- import org.springframework.beans.factory.annotation.Value;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
-
- import java.util.ArrayList;
- import java.util.List;
-
- /**
- * ElasticSearch 连接配置
- */
- @Configuration
- public class EsConfig {
- /** 协议 */
- @Value("${elasticsearch.schema}")
- private String schema;
-
- /** 集群地址,如果有多个则用英文都好相隔 */
- @Value("${elasticsearch.address}")
- private String address;
-
- /** 连接超时时间 */
- @Value("${elasticsearch.connectTimeout}")
- private int connectTimeout;
-
- /** socket 连接超时时间 */
- @Value("${elasticsearch.socketTimeout}")
- private int socketTimeout;
-
- /** 获取连接的超时时间 */
- @Value("${elasticsearch.connectionRequestTimeout}")
- private int connectionRequestTimeout;
-
- /** 最大连接数 */
- @Value("${elasticsearch.maxConnectNum}")
- private int maxConnectNum;
-
- /** 最大路由连接数 */
- @Value("${elasticsearch.maxConnectPerRoute}")
- private int maxConnectPerRoute;
-
- @Bean
- public RestHighLevelClient restHighLevelClient() {
- // 组装集群地址
- List<HttpHost> hostList = new ArrayList<>();
- String[] hostArray = address.split(",");
- for (String addr : hostArray) {
- String host = addr.split(":")[0];
- String port = addr.split(":")[1];
- hostList.add(new HttpHost(host, Integer.parseInt(port), schema));
- }
- HttpHost[] httpHost = hostList.toArray(new HttpHost[]{});
-
- // 构建连接对象
- RestClientBuilder builder = RestClient.builder(httpHost);
-
- // 异步连接延时配置
- builder.setRequestConfigCallback(requestConfigBuilder -> {
- requestConfigBuilder.setConnectTimeout(connectTimeout);
- requestConfigBuilder.setSocketTimeout(socketTimeout);
- requestConfigBuilder.setConnectionRequestTimeout(connectionRequestTimeout);
- return requestConfigBuilder;
- });
-
- // 异步连接数配置
- builder.setHttpClientConfigCallback(httpClientBuilder -> {
- httpClientBuilder.setMaxConnTotal(maxConnectNum);
- httpClientBuilder.setMaxConnPerRoute(maxConnectPerRoute);
- return httpClientBuilder;
- });
-
- return new RestHighLevelClient(builder);
- }
- }
用于在实体上说明Es的索引与type
- package com.es.example.annotations;
-
- import java.lang.annotation.ElementType;
- import java.lang.annotation.Retention;
- import java.lang.annotation.RetentionPolicy;
- import java.lang.annotation.Target;
-
- /**
- * 自定义注解 声明Es的索引与type
- */
- @Target({ElementType.TYPE}) // 声明注解使用类型
- @Retention(RetentionPolicy.RUNTIME) // 声明注解生命周期为运行时
- public @interface EsDocument {
- /**
- * 索引
- */
- String index();
-
- /**
- * type
- */
- String type();
- }
- package com.es.example.entity;
-
- import com.es.example.annotations.EsDocument;
- import lombok.AllArgsConstructor;
- import lombok.Builder;
- import lombok.Data;
- import lombok.NoArgsConstructor;
- import org.springframework.format.annotation.DateTimeFormat;
-
- import java.util.Date;
-
- @Data
- @Builder
- @EsDocument(index = "test20210910", type = "doc") // 自定义注解,声明Es的索引与type
- @NoArgsConstructor
- @AllArgsConstructor
- public class UserInfo {
- /**
- * 姓名
- */
- private String name;
-
- /**
- * 年龄
- */
- private Integer age = 0;
-
- /**
- * 生日
- */
- @DateTimeFormat(pattern = "yyyy-MM-dd")
- private String birthday;
-
- /**
- * 工资
- */
- private Integer salary = 0;
-
- /**
- * 地址
- */
- private String address;
-
- /**
- * 备注
- */
- private String remark;
-
- /**
- * 测试数据
- */
- private String sayWords;
-
- /**
- * 创建时间
- */
- private Date createTime;
- }
此步骤中的方法相对全面,且每一步都有注释,以及逻辑之间我都会做明显分隔,便于理解,
前部分做索引与文档的增删改操作,后半部分做查询操作,有明显分割提示,所有操作都在一个类中,成员变量共享,
但是我没有做每个方法的具体响应示例,重在"授人以渔"。
后面的一系列查询操作思路核心就五步:
第一步:创建查询条件;
第二步:创建查询源构建器,并将查询条件配置其中;
第三步:创建请求;
第四步:调用 RestHighLevelClient 客户端去获取请求响应体;
第五步:解析响应体
- package com.es.example.service.impl;
-
- import cn.hutool.core.bean.BeanUtil;
- import cn.hutool.core.collection.CollectionUtil;
- import com.alibaba.fastjson.JSON;
- import com.es.example.annotations.EsDocument;
- import com.es.example.entity.UserInfo;
- import com.es.example.service.EsIndexOperationService;
- import lombok.extern.slf4j.Slf4j;
- import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
- import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
- import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
- import org.elasticsearch.action.admin.indices.delete.DeleteIndexResponse;
- import org.elasticsearch.action.bulk.BulkRequest;
- import org.elasticsearch.action.bulk.BulkResponse;
- import org.elasticsearch.action.delete.DeleteRequest;
- import org.elasticsearch.action.delete.DeleteResponse;
- import org.elasticsearch.action.get.GetRequest;
- import org.elasticsearch.action.get.GetResponse;
- import org.elasticsearch.action.index.IndexRequest;
- import org.elasticsearch.action.index.IndexResponse;
- import org.elasticsearch.action.search.SearchRequest;
- import org.elasticsearch.action.search.SearchResponse;
- import org.elasticsearch.action.update.UpdateRequest;
- import org.elasticsearch.action.update.UpdateResponse;
- import org.elasticsearch.client.RestHighLevelClient;
- import org.elasticsearch.common.settings.Settings;
- import org.elasticsearch.common.unit.Fuzziness;
- import org.elasticsearch.common.xcontent.XContentBuilder;
- import org.elasticsearch.common.xcontent.XContentFactory;
- import org.elasticsearch.common.xcontent.XContentType;
- import org.elasticsearch.index.query.BoolQueryBuilder;
- import org.elasticsearch.index.query.MatchAllQueryBuilder;
- import org.elasticsearch.index.query.QueryBuilders;
- import org.elasticsearch.rest.RestStatus;
- import org.elasticsearch.search.SearchHit;
- import org.elasticsearch.search.SearchHits;
- import org.elasticsearch.search.aggregations.AggregationBuilder;
- import org.elasticsearch.search.aggregations.AggregationBuilders;
- import org.elasticsearch.search.aggregations.Aggregations;
- import org.elasticsearch.search.aggregations.bucket.terms.Terms;
- import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
- import org.elasticsearch.search.aggregations.metrics.stats.ParsedStats;
- import org.elasticsearch.search.aggregations.metrics.tophits.ParsedTopHits;
- import org.elasticsearch.search.builder.SearchSourceBuilder;
- import org.elasticsearch.search.sort.SortOrder;
- import org.springframework.stereotype.Service;
-
- import javax.annotation.Resource;
- import java.io.IOException;
- import java.util.ArrayList;
- import java.util.Date;
- import java.util.List;
-
- /**
- * Es索引相关操作
- */
- @Service
- @Slf4j
- public class EsIndexOperationServiceImpl implements EsIndexOperationService {
- /**
- * 测试所用 ES文档id
- */
- private static final String TEST_ES_DOCUMENT_ID = "R0Xp3HsByDspl6UWckXA";
-
- /**
- * 查询条件的字段
- */
- private static final String TEST_ES_DOCUMENT_QUERY_KEY = "address";
-
-
-
- @Resource
- private RestHighLevelClient restHighLevelClient;
-
- /**
- * 创建索引
- *
- * @return 创建成功与否
- */
- @Override
- public String createIndex() {
- try {
- // 创建mapping
- XContentBuilder mapping = getCreateIndexMapping();
-
- // 创建索引配置信息
- Settings settings = Settings.builder()
- .put("index.number_of_shards", 1)
- .put("index.number_of_replicas", 0)
- .build();
-
- // 创建索引请求对象,然后设置索引类型(ES 7.0 将不在存在索引类型)和 mapping 与 index 配置
- CreateIndexRequest request = new CreateIndexRequest("test20210910", settings);
- request.mapping("doc", mapping);
-
- // 客户端执行创建索引的请求
- CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(request);
-
- // 判断是否创建成功
- boolean isCreated = createIndexResponse.isAcknowledged();
- log.info("是否创建成功:[{}]", isCreated);
-
- return isCreated ? "创建成功" : "创建失败";
- } catch (IOException e) {
- e.printStackTrace();
- }
- return null;
- }
-
- /**
- * 获取创建索引的mapping
- *
- * @return mapping
- * @throws IOException IO异常
- */
- private XContentBuilder getCreateIndexMapping() throws IOException {
- // 对比ES原生创建索引Dsl语句,每一个startObject()与endObject()就相当于Dsl语句中的一组大括号 {}
- return XContentFactory.jsonBuilder()
- .startObject()
- .field("dynamic", true)
- .startObject("properties")
- .startObject("name")
- .field("type", "text")
- .startObject("fields")
- .startObject("keyword")
- .field("type", "keyword")
- .endObject()
- .endObject()
- .endObject()
-
- .startObject("address")
- .field("type", "text")
- .startObject("fields")
- .startObject("keyword")
- .field("type", "keyword")
- .endObject()
- .endObject()
- .endObject()
-
- .startObject("remark")
- .field("type", "text")
- .startObject("fields")
- .startObject("keyword")
- .field("type", "keyword")
- .endObject()
- .endObject()
- .endObject()
-
- .startObject("sayWords")
- .field("type", "text")
- .endObject()
-
- .startObject("age")
- .field("type", "integer")
- .endObject()
-
- .startObject("salary")
- .field("type", "integer")
- .endObject()
-
- .startObject("birthDate")
- .field("type", "date")
- .field("format", "yyyy-MM-dd")
- .endObject()
-
- .startObject("createTime")
- .field("type", "date")
- .endObject()
- .endObject()
- .endObject();
- }
- /**
- * 删除索引
- *
- * @return 是否删除成功
- */
- @Override
- public String deleteIndex() {
- try {
- // 创建请求
- DeleteIndexRequest request = new DeleteIndexRequest("test20210910");
-
- // 处理请求
- DeleteIndexResponse response = restHighLevelClient.indices().delete(request);
-
- // 拿到结果
- boolean isDelete = response.isAcknowledged();
- log.info("是否删除成功:[{}]", isDelete);
-
- return isDelete ? "删除成功" : "删除失败";
- } catch (IOException e) {
- e.printStackTrace();
- }
- return null;
- }
- /**
- * 新增一条文档
- *
- * @return 是否新增成功
- */
- @Override
- public String addADocument() {
- // 创建请求
- EsDocument annotation = UserInfo.class.getAnnotation(EsDocument.class); // 获取注解
- IndexRequest request = new IndexRequest(annotation.index(), annotation.type());
-
- // 创建员工信息
- UserInfo userInfo = UserInfo.builder()
- .name("王五")
- .age(9)
- .salary(1100)
- .address("天津市")
- .remark("来自北京市的王先生")
- .sayWords("啊阿萨飒飒")
- .createTime(new Date())
- .birthday("1991-01-01").build();
-
- /*
- 将对象转为JSON数组
- 不转为JSON格式并且不声明的话会报错java.lang.IllegalArgumentException: The number of object passed must be even but was [1])
- 意为 request.source(userInfo) 方法不知道userInfo是什么类型的数据
- */
- byte[] json = JSON.toJSONBytes(userInfo);
-
- // 设置文档内容
- request.source(json, XContentType.JSON); // 声明类型
- try {
- // 执行请求
- IndexResponse response = restHighLevelClient.index(request);
- log.info("新增一条文档的结果状态:[{}]", response.status());
- } catch (IOException e) {
- e.printStackTrace();
- }
- return "新增一条文档成功";
- }
- /**
- * 批量新增文档
- *
- * @return 是否新增成功
- */
- @Override
- public String addBulkDocument() {
- // 创建数据集
- List<UserInfo> userInfoList = new ArrayList<>();
- for (int i = 0; i <= 10; i++) {
- UserInfo userInfo = UserInfo.builder()
- .name("用户" + i)
- .age(i)
- .salary(i * 100 + 100)
- .address("用户" + i + "住在" + i + "号街区")
- .remark("这是第" + i + "条文档信息的批量插入")
- .sayWords("大大慢慢那得看" + i)
- .createTime(new Date())
- .birthday("199" + i + "-01-01").build();
- userInfoList.add(userInfo);
- }
-
- // 获取注解
- EsDocument annotation = UserInfo.class.getAnnotation(EsDocument.class);
-
- // 创建批量插入的请求
- BulkRequest bulkRequest = new BulkRequest();
- for (UserInfo userInfo : userInfoList) {
- IndexRequest request = new IndexRequest(annotation.index(), annotation.type());
- /*
- * 将对象转为JSON数组
- 不转为JSON格式并且不声明的话会报错java.lang.IllegalArgumentException: The number of object passed must be even but was [1])
- 意为 request.source(userInfo) 方法不知道userInfo是什么类型的数据
- * */
- byte[] json = JSON.toJSONBytes(userInfo);
- request.source(json, XContentType.JSON); // 声明类型
- bulkRequest.add(request);
- }
-
- // 执行批量请求
- BulkResponse response = null;
- try {
- response = restHighLevelClient.bulk(bulkRequest);
- log.info("新增一条文档的结果状态:[{}]", response.status().getStatus());
- } catch (IOException e) {
- e.printStackTrace();
- }
- return response != null && response.status().getStatus() == 200 ? "批量新增文档成功" : "批量新增文档失败";
- }
- /**
- * 更新文档
- *
- * @return 是否更新成功
- */
- @Override
- public String updateDocument() {
- // 设置更新数据
- UserInfo update = UserInfo.builder().address("湖南省常德市").build();
- byte[] json = JSON.toJSONBytes(update);
-
- // 创建请求
- EsDocument annotation = UserInfo.class.getAnnotation(EsDocument.class);
- UpdateRequest request = new UpdateRequest(annotation.index(), annotation.type(), TEST_ES_DOCUMENT_ID);
- request.doc(json, XContentType.JSON);
-
- // 处理请求
- UpdateResponse response = null;
- try {
- response = restHighLevelClient.update(request);
- log.info("更新一条文档的结果状态:[{}]", response.status().getStatus());
- } catch (IOException e) {
- e.printStackTrace();
- }
- return response != null && response.status().getStatus() == 200 ? "更新成功" : "更新失败";
- }
- /**
- * 删除文档
- *
- * @return 是否删除成功
- */
- @Override
- public String deleteDocument() {
- EsDocument annotation = UserInfo.class.getAnnotation(EsDocument.class);
- DeleteRequest request = new DeleteRequest(annotation.index(), annotation.type(), TEST_ES_DOCUMENT_ID);
-
- DeleteResponse response = null;
- try {
- response = restHighLevelClient.delete(request);
- log.info("删除一条文档的结果状态:[{}]", response.status().getStatus());
- } catch (IOException e) {
- e.printStackTrace();
- }
- return response != null && response.status().getStatus() == 200 ? "删除成功" : "删除失败";
- }
以下为各种查询操作
- /**
- * 根据id获取文档
- *
- * @return 文档结果
- */
- @Override
- public UserInfo getDocument() {
- EsDocument annotation = UserInfo.class.getAnnotation(EsDocument.class);
- GetRequest request = new GetRequest(annotation.index(), annotation.type(), TEST_ES_DOCUMENT_ID);
- GetResponse response = null;
- try {
- response = restHighLevelClient.get(request);
- log.info("根据id查询的响应体:" + response);
- } catch (IOException e) {
- e.printStackTrace();
- }
- if (response != null) {
- UserInfo userInfo = JSON.parseObject(response.getSourceAsBytes(), UserInfo.class);
- log.info("获取查询结果:" + userInfo);
- return BeanUtil.isEmpty(userInfo) ? null : userInfo;
- }
- return null;
- }
查询条件不会进行分词,但是查询内容可能会分词,导致查询不到
- /**
- * 精确查询(查询条件不会进行分词,但是查询内容可能会分词,导致查询不到)
- *
- * @return 查询结果
- */
- @Override
- public List<UserInfo> termQuery() {
- // 构建查询条件(注意:termQuery 支持多种格式查询,如 boolean、int、double、string 等,这里使用的是 string 的查询)
- SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
- searchSourceBuilder.query(QueryBuilders.termQuery(TEST_ES_DOCUMENT_QUERY_KEY + ".keyword", "用户2住在2号街区")); // 加".keyword"就是整句匹配
- /*
- * QueryBuilders 有很多查询方式,详情请查看源码
- * termsQuery 相当于 Mysql 的 in
- * searchSourceBuilder.query(QueryBuilders.termsQuery("address.keyword", "用户1住在1号街区", , "用户2住在2号街区"));
- *
- * 也可以不加 .keyword 进行模糊匹配
- * searchSourceBuilder.query(QueryBuilders.termsQuery("sayWords", "街", "常"));
- * */
-
- // 拿到索引信息
- EsDocument annotation = UserInfo.class.getAnnotation(EsDocument.class);
-
- // 创建查询请求,将查询对象配置到其中
- SearchRequest searchRequest = new SearchRequest(annotation.index());
- searchRequest.source(searchSourceBuilder);
-
- // 处理查询请求
- SearchResponse response = null;
- try {
- response = restHighLevelClient.search(searchRequest);
- log.info("精确查询的响应体:" + response);
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- // 处理响应
- if (response != null) {
- if (RestStatus.OK.equals(response.status()) && response.getHits().totalHits > 0) {
- List<UserInfo> result = new ArrayList<>();
- SearchHits hits = response.getHits();
- for (SearchHit hit : hits) {
- // 将JSON转换为对象
- UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class);
- result.add(userInfo);
- }
- log.info("获取查询结果:" + result);
- return CollectionUtil.isEmpty(result) ? null : result;
- }
- }
- return null;
- }
- /**
- * 匹配查询符合条件的所有数据,并设置分页
- *
- * @return 查询结果
- */
- @Override
- public List<UserInfo> matchAllQuery() {
- // 创建匹配全部的查询条件
- MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
- /*
- * 创建匹配筛选的查询条件
- * MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery(TEST_ES_DOCUMENT_QUERY_KEY, "*街区");
- *
- * 创建匹配短句的查询条件
- * MatchPhraseQueryBuilder matchPhraseQueryBuilder = QueryBuilders.matchPhraseQuery(TEST_ES_DOCUMENT_QUERY_KEY, "用户");
- *
- * 创建根据内容匹配多个字段的查询条件
- * MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("北京", TEST_ES_DOCUMENT_QUERY_KEY, "remark");
- * */
-
- // 创建查询源构造器
- SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
- searchSourceBuilder.query(matchAllQueryBuilder);
-
- // 设置分页
- searchSourceBuilder.from(0);
- searchSourceBuilder.size(10);
-
- // 设置排序
- searchSourceBuilder.sort("salary", SortOrder.DESC);
-
- // 创建请求,并将查询条件配置到其中
- EsDocument annotation = UserInfo.class.getAnnotation(EsDocument.class);
- SearchRequest request = new SearchRequest(annotation.index());
- request.source(searchSourceBuilder);
-
- // 处理查询请求
- SearchResponse response = null;
- try {
- response = restHighLevelClient.search(request);
- log.info("匹配所有条件查询的响应体:" + response);
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- // 处理响应
- if (response != null) {
- if (RestStatus.OK.equals(response.status()) && response.getHits().totalHits > 0) {
- List<UserInfo> result = new ArrayList<>();
- for (SearchHit hit : response.getHits()) {
- // 将JSON转化为对象
- UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class);
- result.add(userInfo);
- }
- log.info("获取查询结果:" + result);
- return CollectionUtil.isEmpty(result) ? null : result;
- }
- }
- return null;
- }
- /**
- * 模糊查询
- *
- * 慎用!!
- *
- * @return 查询结果
- */
- @Override
- public List<UserInfo> fuzzyQuery() {
- // 设置筛选条件,并设置模糊性(越大匹配度越低,注意:模糊度没设置合适可能会出现不想要的结果甚至无结果) 慎用!!
- SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
- searchSourceBuilder.query(QueryBuilders.fuzzyQuery(TEST_ES_DOCUMENT_QUERY_KEY, "街区").fuzziness(Fuzziness.ONE));
-
- // 创建请求
- EsDocument annotation = UserInfo.class.getAnnotation(EsDocument.class);
- SearchRequest searchRequest = new SearchRequest(annotation.index());
- searchRequest.source(searchSourceBuilder);
-
- // 处理请求
- SearchResponse response = null;
- try {
- response = restHighLevelClient.search(searchRequest);
- log.info("模糊查询查询的响应体:" + response);
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- // 处理响应
- if (response != null) {
- if (RestStatus.OK.equals(response.status()) && response.getHits().totalHits > 0) {
- List<UserInfo> result = new ArrayList<>();
- for (SearchHit hit : response.getHits()) {
- UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class);
- result.add(userInfo);
- }
- log.info("获取查询结果:" + result);
- return result;
- }
- }
- return null;
- }
- /**
- * 范围查询
- *
- * @return 查询结果
- */
- @Override
- public List<UserInfo> rangeQuery() {
- // 设置查询条件,includeLower(是否包含下边界)、includeUpper(是否包含上边界)
- SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
- searchSourceBuilder.query(QueryBuilders.rangeQuery("salary").gte(500).lte(1000).includeLower(true).includeUpper(true));
- /*
- 如果查询的字段是日期类型
- searchSourceBuilder.query(QueryBuilders.rangeQuery("birthday").from("1991-01-01").to("1999-01-01").includeLower(true).includeUpper(true));
- */
-
- // 创建请求
- EsDocument annotation = UserInfo.class.getAnnotation(EsDocument.class);
- SearchRequest request = new SearchRequest(annotation.index());
- request.source(searchSourceBuilder);
-
- // 处理请求
- SearchResponse response = null;
- try {
- response = restHighLevelClient.search(request);
- log.info("范围查询的响应体:" + response);
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- // 处理响应
- if (response != null) {
- if (RestStatus.OK.equals(response.status()) && response.getHits().totalHits > 0) {
- List<UserInfo> result = new ArrayList<>();
- for (SearchHit hit : response.getHits()) {
- UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class);
- result.add(userInfo);
- }
- log.info("获取查询结果:" + result);
- return result;
- }
- }
- return null;
- }
*:表示多个字符(0个或多个字符) ?:表示单个字符
- /**
- * 通配符查询( *:表示多个字符(0个或多个字符) ?:表示单个字符)
- *
- * @return 查询结果
- */
- @Override
- public List<UserInfo> wildcardQuery() {
- // 创建查询条件
- SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
- searchSourceBuilder.query(QueryBuilders.wildcardQuery(TEST_ES_DOCUMENT_QUERY_KEY + ".keyword", "*街区"));
-
- // 创建请求
- EsDocument annotation = UserInfo.class.getAnnotation(EsDocument.class);
- SearchRequest request = new SearchRequest(annotation.index());
- request.source(searchSourceBuilder);
-
- // 处理请求
- SearchResponse response = null;
- try {
- response = restHighLevelClient.search(request);
- log.info("通配符查询的响应体:" + response);
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- // 处理响应
- if (response != null) {
- if (RestStatus.OK.equals(response.status()) && response.getHits().totalHits > 0) {
- List<UserInfo> result = new ArrayList<>();
- for (SearchHit hit : response.getHits()) {
- UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class);
- result.add(userInfo);
- }
- log.info("获取查询结果:" + result);
- return result;
- }
- }
- return null;
- }
- /**
- * 布尔查询(重点!)
- *
- * @return 查询结果
- */
- @Override
- public List<UserInfo> boolQuery() {
- // 创建bool查询构建器
- BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
-
- // 创建查询条件(若有多个条件,就让后面接着加)
- boolQueryBuilder.must(QueryBuilders.termsQuery(TEST_ES_DOCUMENT_QUERY_KEY + ".keyword", "用户2住在2号街区", "用户3住在3号街区", "用户8住在8号街区"))
- .filter().add(QueryBuilders.rangeQuery("birthday").format("yyyy").gte("1990").lte("1995").includeLower(true).includeUpper(true));
-
- // 创建查询源并将构建器配置其中
- SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
- searchSourceBuilder.query(boolQueryBuilder);
-
- // 创建请求
- EsDocument annotation = UserInfo.class.getAnnotation(EsDocument.class);
- SearchRequest request = new SearchRequest(annotation.index());
- request.source(searchSourceBuilder);
-
- // 处理请求
- SearchResponse response = null;
- try {
- response = restHighLevelClient.search(request);
- log.info("布尔查询的响应体:" + response);
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- // 处理响应
- if (response != null) {
- if (RestStatus.OK.equals(response.status()) && response.getHits().totalHits > 0) {
- List<UserInfo> result = new ArrayList<>();
- for (SearchHit hit : response.getHits()) {
- UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class);
- result.add(userInfo);
- }
- log.info("获取查询结果:" + result);
- return result;
- }
- }
- return null;
- }
- /**
- * 聚合统计查询(重点!)
- *
- * @return 查询结果如下:
- * {
- * "salary_stats": {
- * "name": "salary_stats",
- * "count": 26,
- * "min": 100.0,
- * "max": 1100.0,
- * "sum": 12100.0,
- * "avg": 465.38461538461536,
- * "type": "stats",
- * "sumAsString": "12100.0",
- * "maxAsString": "1100.0",
- * "avgAsString": "465.38461538461536",
- * "minAsString": "100.0",
- * "metaData": null,
- * "fragment": true
- * }
- * }
- */
- @Override
- public Object aggregationStats() {
- /*
- 声明聚合的类型与字段
- 统计数据(可拿到总数、平均数、最大值、最小值等数据) -- stats("字段_stats").field("字段")
- 总数 -- count("字段_count").field("字段")
- 平均数 -- avg("字段_avg").field("字段")
- 以此类推...
- */
- AggregationBuilder aggr = AggregationBuilders.stats("salary_stats").field("salary");
-
- // 设置查询条件
- SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
- searchSourceBuilder.aggregation(aggr);
-
- // 设置查询结果不返回,只返回聚合的结果
- searchSourceBuilder.size(0);
-
- // 创建请求
- EsDocument annotation = UserInfo.class.getAnnotation(EsDocument.class);
- SearchRequest request = new SearchRequest(annotation.index());
- request.source(searchSourceBuilder);
-
- // 处理请求
- SearchResponse response = null;
- try {
- response = restHighLevelClient.search(request);
- log.info("聚合统计查询的响应体:" + response);
- } catch (IOException e) {
- e.printStackTrace();
- }
-
-
- // 处理响应
- if (response != null) {
- // 获取响应中的聚合信息
- Aggregations aggregations = response.getAggregations();
-
- if (RestStatus.OK.equals(response.status()) && aggregations != null) {
- /*
- 解析数据类型
- ParsedStats -- 聚合信息
- ParsedValueCount -- 总数
- ParsedAvg -- 平均数
- 以此类推
- */
- ParsedStats stats = aggregations.get("salary_stats");
- log.info("-------------------------------------------");
- log.info("聚合信息:");
- log.info("count:{}", stats.getCount());
- log.info("avg:{}", stats.getAvg());
- log.info("max:{}", stats.getMax());
- log.info("min:{}", stats.getMin());
- log.info("sum:{}", stats.getSum());
- log.info("-------------------------------------------");
-
- return aggregations.getAsMap();
- }
- }
- return null;
- }
- /**
- * 聚合分桶查询(重点!)
- *
- * @return 查询结果: 桶名 与 对应的总数
- */
- @Override
- public Object aggregationBucket() {
- /*
- < 声明聚合的类型与字段 >
- 按岁数进行聚合分桶
- TermsAggregationBuilder aggr = AggregationBuilders.terms("age_bucket").field("age");
- 按工资范围进行聚合分桶
- AggregationBuilder aggr = AggregationBuilders.range("salary_range_bucket")
- .field("salary")
- .addUnboundedTo("低级员工", 3000)
- .addRange("中级员工", 5000, 9000)
- .addUnboundedFrom("高级员工", 9000);
- 按照时间范围进行分桶
- AggregationBuilder aggr = AggregationBuilders.dateRange("date_range_bucket")
- .field("birthday")
- .format("yyyy")
- .addRange("1985-1990", "1985", "1990")
- .addRange("1990-1995", "1990", "1995");
- 按工资多少进行聚合分桶
- AggregationBuilder aggr = AggregationBuilders.histogram("salary_histogram")
- .field("salary")
- .extendedBounds(0, 12000)
- .interval(3000);
- 按出生日期进行分桶
- AggregationBuilder aggr = AggregationBuilders.dateHistogram("birthday_histogram")
- .field("birthday")
- .interval(1)
- .dateHistogramInterval(DateHistogramInterval.YEAR)
- .format("yyyy");
- */
- TermsAggregationBuilder aggr = AggregationBuilders.terms("age_bucket").field("age");
-
- // 创建查询条件
- SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
- searchSourceBuilder.aggregation(aggr);
- searchSourceBuilder.size(10);
-
- // 创建请求
- EsDocument annotation = UserInfo.class.getAnnotation(EsDocument.class);
- SearchRequest request = new SearchRequest(annotation.index());
- request.source(searchSourceBuilder);
-
- // 处理请求
- SearchResponse response = null;
- try {
- response = restHighLevelClient.search(request);
- log.info("聚合分桶查询的响应体:" + response);
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- // 处理响应
- if (response != null) {
- if (RestStatus.OK.equals(response.status())) {
- // 获取响应中的聚合信息
- Aggregations aggregations = response.getAggregations();
-
- // 分桶
- Terms byCompanyAggregation = aggregations.get("age_bucket"); // 不同的聚合类型修改 声明聚合的类型与字段 中AggregationBuilders的不同名称即可
- List<? extends Terms.Bucket> buckets = byCompanyAggregation.getBuckets();
-
- // 输出各个桶的内容
- log.info("-------------------------------------------");
- log.info("聚合信息:");
- for (Terms.Bucket bucket : buckets) {
- log.info("桶名:{} | 总数:{}", bucket.getKeyAsString(), bucket.getDocCount());
- }
- log.info("-------------------------------------------");
-
- return aggregations.getAsMap();
- }
- }
- return null;
- }
按岁数分桶、然后统计各个岁数收入最高的用户信息
- /**
- * 聚合查询场景分析
- * (按岁数分桶、然后统计各个岁数收入最高的用户信息)
- *
- * @return 查询结果:
- * 桶名:1
- * 值:{"address":"湖南省常德市","age":1,"birthday":"1991-01-01","createTime":1631498892472,"name":"用户1","remark":"这是第1条文档信息的批量插入","salary":200}
- *
- * 以此类推...
- */
- @Override
- public Object aggregationAnalysis() {
- // 构建聚合参数
- AggregationBuilder testTop = AggregationBuilders.topHits("salary_max_user")
- .size(1)
- .sort("salary", SortOrder.DESC);
- AggregationBuilder salaryBucket = AggregationBuilders.terms("salary_bucket")
- .field("age")
- .size(10);
- salaryBucket.subAggregation(testTop);
-
- // 创建查询条件
- SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
- searchSourceBuilder.size(0);
- searchSourceBuilder.aggregation(salaryBucket);
-
- // 创建请求
- EsDocument annotation = UserInfo.class.getAnnotation(EsDocument.class);
- SearchRequest request = new SearchRequest(annotation.index());
- request.source(searchSourceBuilder);
-
- // 处理请求
- SearchResponse response = null;
- try {
- response = restHighLevelClient.search(request);
- log.info("聚合查询场景分析的响应体:" + response);
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- // 处理响应
- if (response != null) {
- // 获取响应中的聚合信息
- Aggregations aggregations = response.getAggregations();
-
- if (RestStatus.OK.equals(response.status())) {
- // 分桶
- Terms byCompanyAggregation = aggregations.get("salary_bucket");
- List<? extends Terms.Bucket> buckets = byCompanyAggregation.getBuckets();
- // 输出各个桶的内容
- log.info("-------------------------------------------");
- log.info("聚合信息:");
- for (Terms.Bucket bucket : buckets) {
- log.info("桶名:{}", bucket.getKeyAsString());
- ParsedTopHits topHits = bucket.getAggregations().get("salary_max_user");
- for (SearchHit hit:topHits.getHits()){
- log.info(hit.getSourceAsString());
- }
- }
- log.info("-------------------------------------------");
-
- return aggregations.getAsMap();
- }
- }
- return response;
- }
-
-
- }
- package com.es.example.service.impl;
-
- import cn.hutool.core.bean.BeanUtil;
- import cn.hutool.core.collection.CollectionUtil;
- import com.alibaba.fastjson.JSON;
- import com.es.example.annotations.EsDocument;
- import com.es.example.entity.UserInfo;
- import com.es.example.service.EsIndexOperationService;
- import lombok.extern.slf4j.Slf4j;
- import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
- import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
- import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
- import org.elasticsearch.action.admin.indices.delete.DeleteIndexResponse;
- import org.elasticsearch.action.bulk.BulkRequest;
- import org.elasticsearch.action.bulk.BulkResponse;
- import org.elasticsearch.action.delete.DeleteRequest;
- import org.elasticsearch.action.delete.DeleteResponse;
- import org.elasticsearch.action.get.GetRequest;
- import org.elasticsearch.action.get.GetResponse;
- import org.elasticsearch.action.index.IndexRequest;
- import org.elasticsearch.action.index.IndexResponse;
- import org.elasticsearch.action.search.SearchRequest;
- import org.elasticsearch.action.search.SearchResponse;
- import org.elasticsearch.action.update.UpdateRequest;
- import org.elasticsearch.action.update.UpdateResponse;
- import org.elasticsearch.client.RestHighLevelClient;
- import org.elasticsearch.common.settings.Settings;
- import org.elasticsearch.common.unit.Fuzziness;
- import org.elasticsearch.common.xcontent.XContentBuilder;
- import org.elasticsearch.common.xcontent.XContentFactory;
- import org.elasticsearch.common.xcontent.XContentType;
- import org.elasticsearch.index.query.BoolQueryBuilder;
- import org.elasticsearch.index.query.MatchAllQueryBuilder;
- import org.elasticsearch.index.query.QueryBuilders;
- import org.elasticsearch.rest.RestStatus;
- import org.elasticsearch.search.SearchHit;
- import org.elasticsearch.search.SearchHits;
- import org.elasticsearch.search.aggregations.AggregationBuilder;
- import org.elasticsearch.search.aggregations.AggregationBuilders;
- import org.elasticsearch.search.aggregations.Aggregations;
- import org.elasticsearch.search.aggregations.bucket.terms.Terms;
- import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
- import org.elasticsearch.search.aggregations.metrics.stats.ParsedStats;
- import org.elasticsearch.search.aggregations.metrics.tophits.ParsedTopHits;
- import org.elasticsearch.search.builder.SearchSourceBuilder;
- import org.elasticsearch.search.sort.SortOrder;
- import org.springframework.stereotype.Service;
-
- import javax.annotation.Resource;
- import java.io.IOException;
- import java.util.ArrayList;
- import java.util.Date;
- import java.util.List;
-
- /**
- * Es索引相关操作
- */
- @Service
- @Slf4j
- public class EsIndexOperationServiceImpl implements EsIndexOperationService {
- /**
- * 测试所用 ES文档id
- */
- private static final String TEST_ES_DOCUMENT_ID = "R0Xp3HsByDspl6UWckXA";
-
- /**
- * 查询条件的字段
- */
- private static final String TEST_ES_DOCUMENT_QUERY_KEY = "address";
-
-
-
- @Resource
- private RestHighLevelClient restHighLevelClient;
-
- /**
- * 创建索引
- *
- * @return 创建成功与否
- */
- @Override
- public String createIndex() {
- try {
- // 创建mapping
- XContentBuilder mapping = getCreateIndexMapping();
-
- // 创建索引配置信息
- Settings settings = Settings.builder()
- .put("index.number_of_shards", 1)
- .put("index.number_of_replicas", 0)
- .build();
-
- // 创建索引请求对象,然后设置索引类型(ES 7.0 将不在存在索引类型)和 mapping 与 index 配置
- CreateIndexRequest request = new CreateIndexRequest("test20210910", settings);
- request.mapping("doc", mapping);
-
- // 客户端执行创建索引的请求
- CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(request);
-
- // 判断是否创建成功
- boolean isCreated = createIndexResponse.isAcknowledged();
- log.info("是否创建成功:[{}]", isCreated);
-
- return isCreated ? "创建成功" : "创建失败";
- } catch (IOException e) {
- e.printStackTrace();
- }
- return null;
- }
-
- /**
- * 获取创建索引的mapping
- *
- * @return mapping
- * @throws IOException IO异常
- */
- private XContentBuilder getCreateIndexMapping() throws IOException {
- // 对比ES原生创建索引Dsl语句,每一个startObject()与endObject()就相当于Dsl语句中的一组大括号 {}
- return XContentFactory.jsonBuilder()
- .startObject()
- .field("dynamic", true)
- .startObject("properties")
- .startObject("name")
- .field("type", "text")
- .startObject("fields")
- .startObject("keyword")
- .field("type", "keyword")
- .endObject()
- .endObject()
- .endObject()
-
- .startObject("address")
- .field("type", "text")
- .startObject("fields")
- .startObject("keyword")
- .field("type", "keyword")
- .endObject()
- .endObject()
- .endObject()
-
- .startObject("remark")
- .field("type", "text")
- .startObject("fields")
- .startObject("keyword")
- .field("type", "keyword")
- .endObject()
- .endObject()
- .endObject()
-
- .startObject("sayWords")
- .field("type", "text")
- .endObject()
-
- .startObject("age")
- .field("type", "integer")
- .endObject()
-
- .startObject("salary")
- .field("type", "integer")
- .endObject()
-
- .startObject("birthDate")
- .field("type", "date")
- .field("format", "yyyy-MM-dd")
- .endObject()
-
- .startObject("createTime")
- .field("type", "date")
- .endObject()
- .endObject()
- .endObject();
- }
-
- /**
- * 删除索引
- *
- * @return 是否删除成功
- */
- @Override
- public String deleteIndex() {
- try {
- // 创建请求
- DeleteIndexRequest request = new DeleteIndexRequest("test20210910");
-
- // 处理请求
- DeleteIndexResponse response = restHighLevelClient.indices().delete(request);
-
- // 拿到结果
- boolean isDelete = response.isAcknowledged();
- log.info("是否删除成功:[{}]", isDelete);
-
- return isDelete ? "删除成功" : "删除失败";
- } catch (IOException e) {
- e.printStackTrace();
- }
- return null;
- }
-
- /**
- * 新增一条文档
- *
- * @return 是否新增成功
- */
- @Override
- public String addADocument() {
- // 创建请求
- EsDocument annotation = UserInfo.class.getAnnotation(EsDocument.class); // 获取注解
- IndexRequest request = new IndexRequest(annotation.index(), annotation.type());
-
- // 创建员工信息
- UserInfo userInfo = UserInfo.builder()
- .name("王五")
- .age(9)
- .salary(1100)
- .address("天津市")
- .remark("来自北京市的王先生")
- .sayWords("啊阿萨飒飒")
- .createTime(new Date())
- .birthday("1991-01-01").build();
-
- /*
- 将对象转为JSON数组
- 不转为JSON格式并且不声明的话会报错java.lang.IllegalArgumentException: The number of object passed must be even but was [1])
- 意为 request.source(userInfo) 方法不知道userInfo是什么类型的数据
- */
- byte[] json = JSON.toJSONBytes(userInfo);
-
- // 设置文档内容
- request.source(json, XContentType.JSON); // 声明类型
- try {
- // 执行请求
- IndexResponse response = restHighLevelClient.index(request);
- log.info("新增一条文档的结果状态:[{}]", response.status());
- } catch (IOException e) {
- e.printStackTrace();
- }
- return "新增一条文档成功";
- }
-
- /**
- * 批量新增文档
- *
- * @return 是否新增成功
- */
- @Override
- public String addBulkDocument() {
- // 创建数据集
- List<UserInfo> userInfoList = new ArrayList<>();
- for (int i = 0; i <= 10; i++) {
- UserInfo userInfo = UserInfo.builder()
- .name("用户" + i)
- .age(i)
- .salary(i * 100 + 100)
- .address("用户" + i + "住在" + i + "号街区")
- .remark("这是第" + i + "条文档信息的批量插入")
- .sayWords("大大慢慢那得看" + i)
- .createTime(new Date())
- .birthday("199" + i + "-01-01").build();
- userInfoList.add(userInfo);
- }
-
- // 获取注解
- EsDocument annotation = UserInfo.class.getAnnotation(EsDocument.class);
-
- // 创建批量插入的请求
- BulkRequest bulkRequest = new BulkRequest();
- for (UserInfo userInfo : userInfoList) {
- IndexRequest request = new IndexRequest(annotation.index(), annotation.type());
- /*
- * 将对象转为JSON数组
- 不转为JSON格式并且不声明的话会报错java.lang.IllegalArgumentException: The number of object passed must be even but was [1])
- 意为 request.source(userInfo) 方法不知道userInfo是什么类型的数据
- * */
- byte[] json = JSON.toJSONBytes(userInfo);
- request.source(json, XContentType.JSON); // 声明类型
- bulkRequest.add(request);
- }
-
- // 执行批量请求
- BulkResponse response = null;
- try {
- response = restHighLevelClient.bulk(bulkRequest);
- log.info("新增一条文档的结果状态:[{}]", response.status().getStatus());
- } catch (IOException e) {
- e.printStackTrace();
- }
- return response != null && response.status().getStatus() == 200 ? "批量新增文档成功" : "批量新增文档失败";
- }
-
- /**
- * 更新文档
- *
- * @return 是否更新成功
- */
- @Override
- public String updateDocument() {
- // 设置更新数据
- UserInfo update = UserInfo.builder().address("湖南省常德市").build();
- byte[] json = JSON.toJSONBytes(update);
-
- // 创建请求
- EsDocument annotation = UserInfo.class.getAnnotation(EsDocument.class);
- UpdateRequest request = new UpdateRequest(annotation.index(), annotation.type(), TEST_ES_DOCUMENT_ID);
- request.doc(json, XContentType.JSON);
-
- // 处理请求
- UpdateResponse response = null;
- try {
- response = restHighLevelClient.update(request);
- log.info("更新一条文档的结果状态:[{}]", response.status().getStatus());
- } catch (IOException e) {
- e.printStackTrace();
- }
- return response != null && response.status().getStatus() == 200 ? "更新成功" : "更新失败";
- }
-
- /**
- * 删除文档
- *
- * @return 是否删除成功
- */
- @Override
- public String deleteDocument() {
- EsDocument annotation = UserInfo.class.getAnnotation(EsDocument.class);
- DeleteRequest request = new DeleteRequest(annotation.index(), annotation.type(), TEST_ES_DOCUMENT_ID);
-
- DeleteResponse response = null;
- try {
- response = restHighLevelClient.delete(request);
- log.info("删除一条文档的结果状态:[{}]", response.status().getStatus());
- } catch (IOException e) {
- e.printStackTrace();
- }
- return response != null && response.status().getStatus() == 200 ? "删除成功" : "删除失败";
- }
-
-
- /* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 以下为查询操作示例 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
-
- /**
- * 根据id获取文档
- *
- * @return 文档结果
- */
- @Override
- public UserInfo getDocument() {
- EsDocument annotation = UserInfo.class.getAnnotation(EsDocument.class);
- GetRequest request = new GetRequest(annotation.index(), annotation.type(), TEST_ES_DOCUMENT_ID);
- GetResponse response = null;
- try {
- response = restHighLevelClient.get(request);
- log.info("根据id查询的响应体:" + response);
- } catch (IOException e) {
- e.printStackTrace();
- }
- if (response != null) {
- UserInfo userInfo = JSON.parseObject(response.getSourceAsBytes(), UserInfo.class);
- log.info("获取查询结果:" + userInfo);
- return BeanUtil.isEmpty(userInfo) ? null : userInfo;
- }
- return null;
- }
-
- /**
- * 精确查询(查询条件不会进行分词,但是查询内容可能会分词,导致查询不到)
- *
- * @return 查询结果
- */
- @Override
- public List<UserInfo> termQuery() {
- // 构建查询条件(注意:termQuery 支持多种格式查询,如 boolean、int、double、string 等,这里使用的是 string 的查询)
- SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
- searchSourceBuilder.query(QueryBuilders.termQuery(TEST_ES_DOCUMENT_QUERY_KEY + ".keyword", "用户2住在2号街区")); // 加".keyword"就是整句匹配
- /*
- * QueryBuilders 有很多查询方式,详情请查看源码
- * termsQuery 相当于 Mysql 的 in
- * searchSourceBuilder.query(QueryBuilders.termsQuery("address.keyword", "用户1住在1号街区", , "用户2住在2号街区"));
- *
- * 也可以不加 .keyword 进行模糊匹配
- * searchSourceBuilder.query(QueryBuilders.termsQuery("sayWords", "街", "常"));
- * */
-
- // 拿到索引信息
- EsDocument annotation = UserInfo.class.getAnnotation(EsDocument.class);
-
- // 创建查询请求,将查询对象配置到其中
- SearchRequest searchRequest = new SearchRequest(annotation.index());
- searchRequest.source(searchSourceBuilder);
-
- // 处理查询请求
- SearchResponse response = null;
- try {
- response = restHighLevelClient.search(searchRequest);
- log.info("精确查询的响应体:" + response);
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- // 处理响应
- if (response != null) {
- if (RestStatus.OK.equals(response.status()) && response.getHits().totalHits > 0) {
- List<UserInfo> result = new ArrayList<>();
- SearchHits hits = response.getHits();
- for (SearchHit hit : hits) {
- // 将JSON转换为对象
- UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class);
- result.add(userInfo);
- }
- log.info("获取查询结果:" + result);
- return CollectionUtil.isEmpty(result) ? null : result;
- }
- }
- return null;
- }
-
- /**
- * 匹配查询符合条件的所有数据,并设置分页
- *
- * @return 查询结果
- */
- @Override
- public List<UserInfo> matchAllQuery() {
- // 创建匹配全部的查询条件
- MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
- /*
- * 创建匹配筛选的查询条件
- * MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery(TEST_ES_DOCUMENT_QUERY_KEY, "*街区");
- *
- * 创建匹配短句的查询条件
- * MatchPhraseQueryBuilder matchPhraseQueryBuilder = QueryBuilders.matchPhraseQuery(TEST_ES_DOCUMENT_QUERY_KEY, "用户");
- *
- * 创建根据内容匹配多个字段的查询条件
- * MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("北京", TEST_ES_DOCUMENT_QUERY_KEY, "remark");
- * */
-
- // 创建查询源构造器
- SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
- searchSourceBuilder.query(matchAllQueryBuilder);
-
- // 设置分页
- searchSourceBuilder.from(0);
- searchSourceBuilder.size(10);
-
- // 设置排序
- searchSourceBuilder.sort("salary", SortOrder.DESC);
-
- // 创建请求,并将查询条件配置到其中
- EsDocument annotation = UserInfo.class.getAnnotation(EsDocument.class);
- SearchRequest request = new SearchRequest(annotation.index());
- request.source(searchSourceBuilder);
-
- // 处理查询请求
- SearchResponse response = null;
- try {
- response = restHighLevelClient.search(request);
- log.info("匹配所有条件查询的响应体:" + response);
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- // 处理响应
- if (response != null) {
- if (RestStatus.OK.equals(response.status()) && response.getHits().totalHits > 0) {
- List<UserInfo> result = new ArrayList<>();
- for (SearchHit hit : response.getHits()) {
- // 将JSON转化为对象
- UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class);
- result.add(userInfo);
- }
- log.info("获取查询结果:" + result);
- return CollectionUtil.isEmpty(result) ? null : result;
- }
- }
- return null;
- }
-
- /**
- * 模糊查询
- *
- * 慎用!!
- *
- * @return 查询结果
- */
- @Override
- public List<UserInfo> fuzzyQuery() {
- // 设置筛选条件,并设置模糊性(越大匹配度越低,注意:模糊度没设置合适可能会出现不想要的结果甚至无结果) 慎用!!
- SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
- searchSourceBuilder.query(QueryBuilders.fuzzyQuery(TEST_ES_DOCUMENT_QUERY_KEY, "街区").fuzziness(Fuzziness.ONE));
-
- // 创建请求
- EsDocument annotation = UserInfo.class.getAnnotation(EsDocument.class);
- SearchRequest searchRequest = new SearchRequest(annotation.index());
- searchRequest.source(searchSourceBuilder);
-
- // 处理请求
- SearchResponse response = null;
- try {
- response = restHighLevelClient.search(searchRequest);
- log.info("模糊查询查询的响应体:" + response);
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- // 处理响应
- if (response != null) {
- if (RestStatus.OK.equals(response.status()) && response.getHits().totalHits > 0) {
- List<UserInfo> result = new ArrayList<>();
- for (SearchHit hit : response.getHits()) {
- UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class);
- result.add(userInfo);
- }
- log.info("获取查询结果:" + result);
- return result;
- }
- }
- return null;
- }
-
- /**
- * 范围查询
- *
- * @return 查询结果
- */
- @Override
- public List<UserInfo> rangeQuery() {
- // 设置查询条件,includeLower(是否包含下边界)、includeUpper(是否包含上边界)
- SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
- searchSourceBuilder.query(QueryBuilders.rangeQuery("salary").gte(500).lte(1000).includeLower(true).includeUpper(true));
- /*
- 如果查询的字段是日期类型
- searchSourceBuilder.query(QueryBuilders.rangeQuery("birthday").from("1991-01-01").to("1999-01-01").includeLower(true).includeUpper(true));
- */
-
- // 创建请求
- EsDocument annotation = UserInfo.class.getAnnotation(EsDocument.class);
- SearchRequest request = new SearchRequest(annotation.index());
- request.source(searchSourceBuilder);
-
- // 处理请求
- SearchResponse response = null;
- try {
- response = restHighLevelClient.search(request);
- log.info("范围查询的响应体:" + response);
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- // 处理响应
- if (response != null) {
- if (RestStatus.OK.equals(response.status()) && response.getHits().totalHits > 0) {
- List<UserInfo> result = new ArrayList<>();
- for (SearchHit hit : response.getHits()) {
- UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class);
- result.add(userInfo);
- }
- log.info("获取查询结果:" + result);
- return result;
- }
- }
- return null;
- }
-
- /**
- * 通配符查询( *:表示多个字符(0个或多个字符) ?:表示单个字符)
- *
- * @return 查询结果
- */
- @Override
- public List<UserInfo> wildcardQuery() {
- // 创建查询条件
- SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
- searchSourceBuilder.query(QueryBuilders.wildcardQuery(TEST_ES_DOCUMENT_QUERY_KEY + ".keyword", "*街区"));
-
- // 创建请求
- EsDocument annotation = UserInfo.class.getAnnotation(EsDocument.class);
- SearchRequest request = new SearchRequest(annotation.index());
- request.source(searchSourceBuilder);
-
- // 处理请求
- SearchResponse response = null;
- try {
- response = restHighLevelClient.search(request);
- log.info("通配符查询的响应体:" + response);
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- // 处理响应
- if (response != null) {
- if (RestStatus.OK.equals(response.status()) && response.getHits().totalHits > 0) {
- List<UserInfo> result = new ArrayList<>();
- for (SearchHit hit : response.getHits()) {
- UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class);
- result.add(userInfo);
- }
- log.info("获取查询结果:" + result);
- return result;
- }
- }
- return null;
- }
-
- /**
- * 布尔查询(重点!)
- *
- * @return 查询结果
- */
- @Override
- public List<UserInfo> boolQuery() {
- // 创建bool查询构建器
- BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
-
- // 创建查询条件(若有多个条件,就让后面接着加)
- boolQueryBuilder.must(QueryBuilders.termsQuery(TEST_ES_DOCUMENT_QUERY_KEY + ".keyword", "用户2住在2号街区", "用户3住在3号街区", "用户8住在8号街区"))
- .filter().add(QueryBuilders.rangeQuery("birthday").format("yyyy").gte("1990").lte("1995").includeLower(true).includeUpper(true));
-
- // 创建查询源并将构建器配置其中
- SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
- searchSourceBuilder.query(boolQueryBuilder);
-
- // 创建请求
- EsDocument annotation = UserInfo.class.getAnnotation(EsDocument.class);
- SearchRequest request = new SearchRequest(annotation.index());
- request.source(searchSourceBuilder);
-
- // 处理请求
- SearchResponse response = null;
- try {
- response = restHighLevelClient.search(request);
- log.info("布尔查询的响应体:" + response);
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- // 处理响应
- if (response != null) {
- if (RestStatus.OK.equals(response.status()) && response.getHits().totalHits > 0) {
- List<UserInfo> result = new ArrayList<>();
- for (SearchHit hit : response.getHits()) {
- UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class);
- result.add(userInfo);
- }
- log.info("获取查询结果:" + result);
- return result;
- }
- }
- return null;
- }
-
- /**
- * 聚合统计查询(重点!)
- *
- * @return 查询结果如下:
- * {
- * "salary_stats": {
- * "name": "salary_stats",
- * "count": 26,
- * "min": 100.0,
- * "max": 1100.0,
- * "sum": 12100.0,
- * "avg": 465.38461538461536,
- * "type": "stats",
- * "sumAsString": "12100.0",
- * "maxAsString": "1100.0",
- * "avgAsString": "465.38461538461536",
- * "minAsString": "100.0",
- * "metaData": null,
- * "fragment": true
- * }
- * }
- */
- @Override
- public Object aggregationStats() {
- /*
- 声明聚合的类型与字段
- 统计数据(可拿到总数、平均数、最大值、最小值等数据) -- stats("字段_stats").field("字段")
- 总数 -- count("字段_count").field("字段")
- 平均数 -- avg("字段_avg").field("字段")
- 以此类推...
- */
- AggregationBuilder aggr = AggregationBuilders.stats("salary_stats").field("salary");
-
- // 设置查询条件
- SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
- searchSourceBuilder.aggregation(aggr);
-
- // 设置查询结果不返回,只返回聚合的结果
- searchSourceBuilder.size(0);
-
- // 创建请求
- EsDocument annotation = UserInfo.class.getAnnotation(EsDocument.class);
- SearchRequest request = new SearchRequest(annotation.index());
- request.source(searchSourceBuilder);
-
- // 处理请求
- SearchResponse response = null;
- try {
- response = restHighLevelClient.search(request);
- log.info("聚合统计查询的响应体:" + response);
- } catch (IOException e) {
- e.printStackTrace();
- }
-
-
- // 处理响应
- if (response != null) {
- // 获取响应中的聚合信息
- Aggregations aggregations = response.getAggregations();
-
- if (RestStatus.OK.equals(response.status()) && aggregations != null) {
- /*
- 解析数据类型
- ParsedStats -- 聚合信息
- ParsedValueCount -- 总数
- ParsedAvg -- 平均数
- 以此类推
- */
- ParsedStats stats = aggregations.get("salary_stats");
- log.info("-------------------------------------------");
- log.info("聚合信息:");
- log.info("count:{}", stats.getCount());
- log.info("avg:{}", stats.getAvg());
- log.info("max:{}", stats.getMax());
- log.info("min:{}", stats.getMin());
- log.info("sum:{}", stats.getSum());
- log.info("-------------------------------------------");
-
- return aggregations.getAsMap();
- }
- }
- return null;
- }
-
- /**
- * 聚合分桶查询(重点!)
- *
- * @return 查询结果: 桶名 与 对应的总数
- */
- @Override
- public Object aggregationBucket() {
- /*
- < 声明聚合的类型与字段 >
- 按岁数进行聚合分桶
- TermsAggregationBuilder aggr = AggregationBuilders.terms("age_bucket").field("age");
- 按工资范围进行聚合分桶
- AggregationBuilder aggr = AggregationBuilders.range("salary_range_bucket")
- .field("salary")
- .addUnboundedTo("低级员工", 3000)
- .addRange("中级员工", 5000, 9000)
- .addUnboundedFrom("高级员工", 9000);
- 按照时间范围进行分桶
- AggregationBuilder aggr = AggregationBuilders.dateRange("date_range_bucket")
- .field("birthday")
- .format("yyyy")
- .addRange("1985-1990", "1985", "1990")
- .addRange("1990-1995", "1990", "1995");
- 按工资多少进行聚合分桶
- AggregationBuilder aggr = AggregationBuilders.histogram("salary_histogram")
- .field("salary")
- .extendedBounds(0, 12000)
- .interval(3000);
- 按出生日期进行分桶
- AggregationBuilder aggr = AggregationBuilders.dateHistogram("birthday_histogram")
- .field("birthday")
- .interval(1)
- .dateHistogramInterval(DateHistogramInterval.YEAR)
- .format("yyyy");
- */
- TermsAggregationBuilder aggr = AggregationBuilders.terms("age_bucket").field("age");
-
- // 创建查询条件
- SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
- searchSourceBuilder.aggregation(aggr);
- searchSourceBuilder.size(10);
-
- // 创建请求
- EsDocument annotation = UserInfo.class.getAnnotation(EsDocument.class);
- SearchRequest request = new SearchRequest(annotation.index());
- request.source(searchSourceBuilder);
-
- // 处理请求
- SearchResponse response = null;
- try {
- response = restHighLevelClient.search(request);
- log.info("聚合分桶查询的响应体:" + response);
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- // 处理响应
- if (response != null) {
- if (RestStatus.OK.equals(response.status())) {
- // 获取响应中的聚合信息
- Aggregations aggregations = response.getAggregations();
-
- // 分桶
- Terms byCompanyAggregation = aggregations.get("age_bucket"); // 不同的聚合类型修改 声明聚合的类型与字段 中AggregationBuilders的不同名称即可
- List<? extends Terms.Bucket> buckets = byCompanyAggregation.getBuckets();
-
- // 输出各个桶的内容
- log.info("-------------------------------------------");
- log.info("聚合信息:");
- for (Terms.Bucket bucket : buckets) {
- log.info("桶名:{} | 总数:{}", bucket.getKeyAsString(), bucket.getDocCount());
- }
- log.info("-------------------------------------------");
-
- return aggregations.getAsMap();
- }
- }
- return null;
- }
-
- /**
- * 聚合查询场景分析
- * (按岁数分桶、然后统计各个岁数收入最高的用户信息)
- *
- * @return 查询结果:
- * 桶名:1
- * 值:{"address":"湖南省常德市","age":1,"birthday":"1991-01-01","createTime":1631498892472,"name":"用户1","remark":"这是第1条文档信息的批量插入","salary":200}
- *
- * 以此类推...
- */
- @Override
- public Object aggregationAnalysis() {
- // 构建聚合参数
- AggregationBuilder testTop = AggregationBuilders.topHits("salary_max_user")
- .size(1)
- .sort("salary", SortOrder.DESC);
- AggregationBuilder salaryBucket = AggregationBuilders.terms("salary_bucket")
- .field("age")
- .size(10);
- salaryBucket.subAggregation(testTop);
-
- // 创建查询条件
- SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
- searchSourceBuilder.size(0);
- searchSourceBuilder.aggregation(salaryBucket);
-
- // 创建请求
- EsDocument annotation = UserInfo.class.getAnnotation(EsDocument.class);
- SearchRequest request = new SearchRequest(annotation.index());
- request.source(searchSourceBuilder);
-
- // 处理请求
- SearchResponse response = null;
- try {
- response = restHighLevelClient.search(request);
- log.info("聚合查询场景分析的响应体:" + response);
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- // 处理响应
- if (response != null) {
- // 获取响应中的聚合信息
- Aggregations aggregations = response.getAggregations();
-
- if (RestStatus.OK.equals(response.status())) {
- // 分桶
- Terms byCompanyAggregation = aggregations.get("salary_bucket");
- List<? extends Terms.Bucket> buckets = byCompanyAggregation.getBuckets();
- // 输出各个桶的内容
- log.info("-------------------------------------------");
- log.info("聚合信息:");
- for (Terms.Bucket bucket : buckets) {
- log.info("桶名:{}", bucket.getKeyAsString());
- ParsedTopHits topHits = bucket.getAggregations().get("salary_max_user");
- for (SearchHit hit:topHits.getHits()){
- log.info(hit.getSourceAsString());
- }
- }
- log.info("-------------------------------------------");
-
- return aggregations.getAsMap();
- }
- }
- return response;
- }
-
-
- }
说明:
本文章是在学习了 <全栈开发者社区> 与 <狂神说> 的Es相关讲解后的实践与补充,想学习更加完整的知识可去膜拜大神!!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。