1.前置条件已经安装和搭建好了elasticsearch中间件
一:项目中引入elasticsearch相关依赖
我安装的elasticsearch版本是7.10.2 对应依赖的版本保持一致
此处省略springboot 搭建及必要的依赖项
xml
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.10.2</version>
</dependency>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>7.10.2</version>
</dependency>
二:项目配置文件里配置上elasticsearch相关的信息
application.yml
yml
es:
data:
host: ip # es安装所在的服务器ip
port: 9200 #es对外暴露的端口
clusterName: hc-es-cluster #es的集群
三:工程里编写elasticsearch相关的配置代码
java
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ESConfig {
@Value("${es.data.host}")
private String host;
@Value("${es.data.clusterName}")
private String clusterName;
@Value("${es.data.port}")
private Integer port;
@Bean
public RestHighLevelClient restHighLevelClient() {
RestHighLevelClient client = new RestHighLevelClient(
RestClient.builder(new HttpHost(host, port, "http"))
);
return client;
}
}
四:项目中的引入和测试
java
import cn.hutool.json.JSONUtil;
import com.jinyi.up.user.JinyiUserProviderApplication;
import com.jinyi.up.user.esPojo.AggDimensionEnum;
import com.jinyi.up.user.esPojo.EsUser;
import com.jinyi.up.user.esPojo.EsUserSearchQueryDto;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.DocWriteRequest;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
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.support.master.AcknowledgedResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.*;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author huangchong
* @date 2023/9/2 14:36
* @desc
*/
@SpringBootTest(classes = {JinyiUserProviderApplication.class})
public class TestES {
@Resource
private RestHighLevelClient esClient;
/**
* 创建索引
*
* @throws IOException
*/
@Test
public void createIndex() throws IOException {
//1.创建索引请求
CreateIndexRequest request = new CreateIndexRequest("hc_index");
//2.执行创建请求
CreateIndexResponse indexResponse = esClient.indices().create(request, RequestOptions.DEFAULT);
System.out.println(indexResponse);
}
/**
* 获取索引 判断是否存在
*
* @throws IOException
*/
@Test
public void getIndex() throws IOException {
//1.创建索引请求
GetIndexRequest request = new GetIndexRequest("hc_index");
//2.执行存在请求
Boolean exists = esClient.indices().exists(request, RequestOptions.DEFAULT);
System.out.println(exists);
}
/**
* 删除索引
*
* @throws IOException
*/
@Test
public void deleteIndex() throws IOException {
//1.创建索引请求
DeleteIndexRequest request = new DeleteIndexRequest("hc_index");
//2.执行删除请求
AcknowledgedResponse response = esClient.indices().delete(request, RequestOptions.DEFAULT);
System.out.println(response.isAcknowledged());
}
/**
* 添加文档
*
* @throws IOException
*/
@Test
public void addEsDocument() throws IOException {
EsUser esUser = new EsUser(1L, "hc", 32, 12, new Date());
//1.指定索引库
IndexRequest request = new IndexRequest("hc_index");
// PUT /hc_index/_doc/1
request.id("1")
.timeout(TimeValue.timeValueSeconds(2));
//2.将数据放入请求
request.source(JSONUtil.toJsonStr(esUser), XContentType.JSON);
//发送请求
IndexResponse response = esClient.index(request, RequestOptions.DEFAULT);
System.out.println(response.toString());
}
/**
* 判断文档是否存在文档
*
* @throws IOException
*/
@Test
public void existsEsDocument() throws IOException {
//1.指定索引库 和 查询id
GetRequest request = new GetRequest("hc_index", "1");
//不获取返回的_source 的上下文
request.fetchSourceContext(new FetchSourceContext(false));
request.storedFields("_none_");
boolean exists = esClient.exists(request, RequestOptions.DEFAULT);
System.out.println(exists);
}
/**
* 获取文档
*
* @throws IOException
*/
@Test
public void getEsDocument() throws IOException {
//1.指定索引库 和 查询id
GetRequest request = new GetRequest("hc_index", "1");
//不获取返回的_source 的上下文
// request.fetchSourceContext(new FetchSourceContext(false));
// request.storedFields("_none_");
GetResponse getResponse = esClient.get(request, RequestOptions.DEFAULT);
System.out.println(getResponse.toString());
String sourceAsString = getResponse.getSourceAsString();
System.out.println(sourceAsString); //返回全部内容 ,和命令一样
}
/**
* 更新文档
*
* @throws IOException
*/
@Test
public void updateEsDocument() throws IOException {
//1.指定索引库 和 查询id
GetRequest request = new GetRequest("hc_index", "1");
GetResponse getResponse = esClient.get(request, RequestOptions.DEFAULT);
System.out.println(getResponse.toString());
String sourceAsString = getResponse.getSourceAsString();
EsUser esUser = JSONUtil.toBean(sourceAsString, EsUser.class);
//1.指定索引库 和 查询id
UpdateRequest updateRequest = new UpdateRequest("hc_index", String.valueOf(esUser.getId()));
//不获取返回的_source 的上下文
updateRequest.timeout(TimeValue.timeValueSeconds(2));
esUser.setUserName("huangchong 2");
updateRequest.doc(JSONUtil.toJsonStr(esUser), XContentType.JSON);
UpdateResponse updateResponse = esClient.update(updateRequest, RequestOptions.DEFAULT);
System.out.println(updateResponse.toString());
}
/**
* 删除文档
*
* @throws IOException
*/
@Test
public void deleteEsDocument() throws IOException {
//1.指定索引库 和 查询id
DeleteRequest deleteRequest = new DeleteRequest("hc_index", "1");
deleteRequest.timeout("1s");
DeleteResponse delete = esClient.delete(deleteRequest, RequestOptions.DEFAULT);
System.out.println(delete.toString());
}
/**
* 批量操作
*
* @throws IOException
*/
@Test
public void bulkAddEsDocument() throws IOException {
BulkRequest bulkRequest = new BulkRequest();
bulkRequest.timeout("10s");
List<EsUser> esUsers = new ArrayList<EsUser>();
esUsers.add(new EsUser(11L, "hc1", 31, 1, new Date()));
esUsers.add(new EsUser(17L, "hc2", 31, 1, new Date()));
esUsers.add(new EsUser(18L, "hc3", 28, 2, new Date()));
esUsers.add(new EsUser(19L, "hc4", 25, 2, new Date()));
esUsers.add(new EsUser(20L, "hc5", 19, 3, new Date()));
//批量插入
for (int i = 0; i < esUsers.size(); i++) {
EsUser esUser = esUsers.get(i);
bulkRequest.add(new IndexRequest("hc_index").id(String.valueOf(esUser.getId()))
.source(JSONUtil.toJsonStr(esUser), XContentType.JSON).opType(DocWriteRequest.OpType.CREATE));
}
esClient.bulk(bulkRequest, RequestOptions.DEFAULT);
}
/**
* private AggregatorFactories.Builder aggregations;
* 1.SearchRequest 请求
* 2.SearchSourceBuilder 条件构建
* searchSourceBuilder.highlighter() 高亮
*
* @throws IOException
*/
@Test
public void queryEsDocument() throws IOException {
// 1.指定索引库
SearchRequest searchRequest = new SearchRequest("hc_index");
//2.构建查询请求条件
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//QueryBuilders工具类 termQuery 精确查询
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("userName", "hc4");
searchSourceBuilder.query(termQueryBuilder);
searchSourceBuilder.timeout(TimeValue.timeValueSeconds(60L));
searchRequest.source(searchSourceBuilder);
SearchResponse response = esClient.search(searchRequest, RequestOptions.DEFAULT);
SearchHits searchHits = response.getHits();
SearchHit[] hits = searchHits.getHits();
for (int i = 0; i < hits.length; i++) {
SearchHit hit = hits[i];
String sourceAsString = hit.getSourceAsString();
System.out.println(JSONUtil.toBean(sourceAsString, EsUser.class).toString());
}
}
/**
* private AggregatorFactories.Builder aggregations;
* 1.SearchRequest 请求
* 2.SearchSourceBuilder 条件构建
* searchSourceBuilder.highlighter() 高亮
*
* @throws IOException
*/
@Test
public void aggsEsDocument() throws IOException {
//对hc_index库的查询请求
SearchRequest searchRequest = new SearchRequest("hc_index");
//paramDto 转BoolQueryBuilder :对查询条件统一封装
EsUserSearchQueryDto queryDto = new EsUserSearchQueryDto();
queryDto.setLikeWords("hc");
queryDto.setUserStatus("1,2,3");
queryDto.setAggDimensions("age");
BoolQueryBuilder boolQueryBuilder = buildQuery(queryDto);
//查询条件构建
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(boolQueryBuilder);
//聚合分析无需得到分页结果,只要聚合结果就行
buildQueryFromSize(searchSourceBuilder, 1, 0);
//构建聚合
aggregationsBuild(searchSourceBuilder, queryDto);
searchRequest.source(searchSourceBuilder);
//获取结果
SearchResponse searchResponse = esClient.search(searchRequest, RequestOptions.DEFAULT);
Map<String, Aggregation> aggregationMap = searchResponse.getAggregations().asMap();
ParsedValueCount idNumAggs = (ParsedValueCount) aggregationMap.get("idNum");
ParsedSum ageSumAggs = (ParsedSum) aggregationMap.get("ageSum");
ParsedAvg ageAveAggs = (ParsedAvg) aggregationMap.get("ageAve");
ParsedCardinality userNumAggs = (ParsedCardinality) aggregationMap.get("userStatusCount");
}
/**
* 构建聚合方式
*/
private void aggregationsBuild(SearchSourceBuilder sourceBuilder, EsUserSearchQueryDto queryDto) {
ValueCountAggregationBuilder idNumAggs = AggregationBuilders.count("idNum").field("id");
SumAggregationBuilder ageSumAggs = AggregationBuilders.sum("ageSum").field("age");
//平均值
AvgAggregationBuilder ageAvgAggs = AggregationBuilders.avg("ageAve").field("age");
//统计去重后的数量
CardinalityAggregationBuilder userStatusAggs = AggregationBuilders.cardinality("userStatusCount").field("userStatus");
sourceBuilder.aggregation(idNumAggs);
sourceBuilder.aggregation(ageSumAggs);
sourceBuilder.aggregation(userStatusAggs);
sourceBuilder.aggregation(ageAvgAggs);
if (StringUtils.isNotEmpty(queryDto.getAggDimensions())) {
List<String> list = Arrays.asList(queryDto.getAggDimensions().split(",")).stream().map(s -> s.trim()).collect(Collectors.toList());
for (String dimension : list) {
AggDimensionEnum dimensionEnum = AggDimensionEnum.getByDimension(dimension);
if (dimension == null) {
continue;
}
TermsAggregationBuilder aggs = AggregationBuilders.terms(dimensionEnum.getDimension()).field(dimensionEnum.getField())
.size(10000);
sourceBuilder.aggregation(aggs);
aggs.subAggregation(idNumAggs);
aggs.subAggregation(ageSumAggs);
aggs.subAggregation(ageAvgAggs);
aggs.subAggregation(userStatusAggs);
}
}
}
protected void buildQueryFromSize(SearchSourceBuilder sourceBuilder, Integer start, Integer size) {
sourceBuilder.from(start);
sourceBuilder.size(size);
}
/**
* 构建查询条件
*
* @param queryDto
* @return
*/
private BoolQueryBuilder buildQuery(EsUserSearchQueryDto queryDto) {
BoolQueryBuilder query = QueryBuilders.boolQuery();
//搜索 分词
if (StringUtils.isNotEmpty(queryDto.getUserName())) {
query.must(QueryBuilders.matchQuery("userName", queryDto.getUserName()));
}
//匹配 包含 模糊查询
if (StringUtils.isNotEmpty(queryDto.getLikeWords())) {
query.must(QueryBuilders.wildcardQuery("userName", "*" + queryDto.getLikeWords() + "*"));
}
//订单状态 多状态 or查询
if (StringUtils.isNotEmpty(queryDto.getUserStatus())) {
String[] orderStatuss = StringUtils.split(queryDto.getUserStatus(), ",");
BoolQueryBuilder orQuery = QueryBuilders.boolQuery()
// 多个状态查询
.should(QueryBuilders.termsQuery("userStatus", orderStatuss));
query.must(orQuery);
}
//订单创建时间
if (queryDto.getBeginCreateTime() != null) {
query.must(QueryBuilders.rangeQuery("createTime").gte(queryDto.getBeginCreateTime().getTime()));
}
if (queryDto.getEndCreateTime() != null) {
query.must(QueryBuilders.rangeQuery("createTime").lte(queryDto.getEndCreateTime().getTime()));
}
return query;
}
}
java
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Component;
import java.util.Date;
/**
* @author huangchong
* @date 2023/9/2 14:51
* @desc
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Component
public class EsUser {
private Long id;
private String userName;
private Integer age;
private Integer userStatus;
private Date createTime;
}
java
import lombok.Data;
import java.util.Date;
/**
* @author huangchong
* @date 2023/9/3 16:12
* @desc
*/
@Data
public class EsUserSearchQueryDto {
private Long id;
private String userName;
private String likeWords;
private Integer age;
private String userStatus;
private Date beginCreateTime;
private Date endCreateTime;
private String aggDimensions;
}
java
package com.jinyi.up.user.esPojo;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 聚合分析维度
* @author huangchong
* @date 2023/9/3 17:00
* @desc
*/
public enum AggDimensionEnum {
userStatus("userStatus", "userStatus", "用户状态"),
age("age", "age", "年纪类型"),
name("userName", "userName", "名字")
;
private final String dimension;
private final String field;
private final String desc;
AggDimensionEnum(String dimension, String field, String desc) {
this.dimension = dimension;
this.field = field;
this.desc = desc;
}
public String getDesc() {
return desc;
}
public String getDimension() {
return dimension;
}
public String getField() {
return field;
}
private static final Map<String, String> aggDimensionEnumMap = Arrays.stream(values()).collect(Collectors.toMap(AggDimensionEnum::getDimension, AggDimensionEnum::getDesc));
public static Map<String, String> getAggDimensionEnumMap() {
return aggDimensionEnumMap;
}
public static AggDimensionEnum getByDimension(String dimension) {
for (AggDimensionEnum dimensionEnum : values()) {
if (dimensionEnum.dimension.equals(dimension)) {
return dimensionEnum;
}
}
return null;
}
}