Springboot2.5.6整合Elasticsearch7.12.1完整示例
Springboot2.5.6整合Elasticsearch7.12.1完整示例
SpringBoot是2.5.6
,elasticsearch是7.12.1
使用依赖elasticsearch-rest-high-level-client
使用RestHighLevelClient
操作
1、引入Pom文件的依赖
<?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.6</version><relativePath/></parent><groupId>com.example</groupId><artifactId>spring-boot-elasticsearch4</artifactId><version>0.0.1-SNAPSHOT</version><name>spring-boot-elasticsearch4</name><description>spring-boot-elasticsearch4</description><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId><version>7.12.1</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.58</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId></dependency><dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>5.2.0</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
2、添加配置文件ElasticsearchConfig
package com.example.springbootelasticsearch4.config;import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
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;/*** @author zhangshixing* @date 2021年11月11日 13:55* elasticsearch 配置类*/
@Configuration
public class ElasticsearchConfig {@Value("${elasticsearch.address}")private String address;/*** 连接超时时间*/@Value("${elasticsearch.connect-timeout}")private int connectTimeOut = 1000;/*** 连接超时时间*/@Value("${elasticsearch.socket-timeout}")private int socketTimeOut = 30000;/*** 获取连接的超时时间*/@Value("${elasticsearch.connection-request-timeout}")private int connectionRequestTimeOut = 500;/*** 最大连接数*/@Value("${elasticsearch.max-connect-num}")private int maxConnectNum = 100;/*** 最大路由连接数*/@Value("${elasticsearch.max-connect-per-route}")private int maxConnectPerRoute = 100;@BeanRestHighLevelClient restHighLevelClient() {System.out.println("elasticsearch init......");ArrayList<HttpHost> hostList = new ArrayList<>();String[] addrss = address.split(",");for (String addr : addrss) {String[] arr = addr.split(":");hostList.add(new HttpHost(arr[0], Integer.parseInt(arr[1]), "http"));}RestClientBuilder builder = RestClient.builder(hostList.toArray(new HttpHost[0]));// 异步httpclient连接延时配置builder.setRequestConfigCallback(new RestClientBuilder.RequestConfigCallback() {@Overridepublic RequestConfig.Builder customizeRequestConfig(RequestConfig.Builder requestConfigBuilder) {requestConfigBuilder.setConnectTimeout(connectTimeOut);requestConfigBuilder.setSocketTimeout(socketTimeOut);requestConfigBuilder.setConnectionRequestTimeout(connectionRequestTimeOut);return requestConfigBuilder;}});// 异步httpclient连接数配置builder.setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {@Overridepublic HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) {httpClientBuilder.setMaxConnTotal(maxConnectNum);httpClientBuilder.setMaxConnPerRoute(maxConnectPerRoute);return httpClientBuilder;}});RestHighLevelClient client = new RestHighLevelClient(builder);return client;}
}
3、配置yml文件
# elasticsearch配置
# 如果是集群,用逗号隔开
elasticsearch.address = 127.0.0.1:9200
# 连接超时时间
elasticsearch.connect-timeout = 1000
# 连接超时时间
elasticsearch.socket-timeout = 30000
elasticsearch.connection-request-timeout = 500
elasticsearch.max-connect-num = 100
elasticsearch.max-connect-per-route = 100
4、自定义注解创建索引
这里简单说一下,索引就相当于是表结构,es本身也是存储数据的,既然是存储,就需要定一个结构,比如有哪
些字段,每个字段是什么类型。但是痛点是如果我们定义的这个结构如果比较复杂,那么用原生的方法代码会很
多,很麻烦,所以我们可以自己定义一套注解,加入到实体类上,这样就可以根据实体类,让es自己去创建索
引,很方便。就类似于以前hibernate,可以根据我们写的实体类自动生表。
关于注解,这里也给出以下,在之前文章基础上做了些改动,主要就是加入了EsId注解,可以将制定字段作为es的
id,如果不加这个,es默认id是自动生成的,有了这个,那么我们可以让mysql的id直接作为es的id,方便更新。
关于这块的内容参见:https://blog.csdn.net/lsqingfeng/article/details/106526493
package com.example.springbootelasticsearch4.annotation;import java.lang.annotation.*;/*** @author zhangshixing* @date 2021年11月11日 16:01* Es 文档注解,用于做索引实体映射*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Inherited
public @interface Document {/*** index : 索引名称** @return*/String index();/*** 类型名称** @return*/String type();}
package com.example.springbootelasticsearch4.annotation;import java.lang.annotation.*;/*** @author zhangshixing* @date 2021年11月11日 16:02* 用于标识使用,该字段作为ES数据中的id*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Documented
@Inherited
public @interface EsId {
}
package com.example.springbootelasticsearch4.annotation;import java.lang.annotation.*;/*** @author zhangshixing* @date 2021年11月11日 16:03* 作用在字段上,用于定义类型,映射关系*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Documented
@Inherited
public @interface Field {FieldType type() default FieldType.TEXT;/*** 指定分词器** @return*/AnalyzerType analyzer() default AnalyzerType.STANDARD;
}
两个枚举:
package com.example.springbootelasticsearch4.annotation;/*** @author zhangshixing* @date 2021年11月11日 19:05*/import lombok.Getter;/*** es 类型参看* https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html*/
@Getter
public enum FieldType {/*** text*/TEXT("text"),KEYWORD("keyword"),INTEGER("integer"),DOUBLE("double"),DATE("date"),/*** 单条数据*/OBJECT("object"),/*** 嵌套数组*/NESTED("nested"),;FieldType(String type) {this.type = type;}private String type;}
package com.example.springbootelasticsearch4.annotation;import lombok.Getter;/*** @author zhangshixing* @date 2021年11月11日 16:04*/
@Getter
public enum AnalyzerType {NO("不使用分词"),/*** 标准分词,默认分词器*/STANDARD("standard"),/*** ik_smart:会做最粗粒度的拆分;已被分出的词语将不会再次被其它词语占有*/IK_SMART("ik_smart"),/*** ik_max_word :会将文本做最细粒度的拆分;尽可能多的拆分出词语*/IK_MAX_WORD("ik_max_word");private String type;AnalyzerType(String type) {this.type = type;}
}
5、封装Elasticsearch工具类
package com.example.springbootelasticsearch4.utils;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.example.springbootelasticsearch4.annotation.Document;
import com.example.springbootelasticsearch4.annotation.EsId;
import com.example.springbootelasticsearch4.annotation.FieldType;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkItemResponse;
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.support.IndicesOptions;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.support.replication.ReplicationResponse;
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.client.indices.PutMappingRequest;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.stereotype.Component;import javax.annotation.Resource;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;/*** @author zhangshixing* @date 2021年11月11日 19:10* es 操作工具类,这里均采用同步调用的方式*/
@Component
@Slf4j
public class ElasticsearchUtil {@Resourceprivate RestHighLevelClient restHighLevelClient;/*** 生成索引对应的字段信息** @param clazz* @return* @throws IOException*/private XContentBuilder generateBuilder(Class clazz) throws IOException {// 获取索引名称及类型Document doc = (Document) clazz.getAnnotation(Document.class);System.out.println(doc.index());System.out.println(doc.type());XContentBuilder builder = XContentFactory.jsonBuilder();builder.startObject();builder.startObject("properties");Field[] declaredFields = clazz.getDeclaredFields();for (Field f : declaredFields) {if (f.isAnnotationPresent(com.example.springbootelasticsearch4.annotation.Field.class)) {// 获取注解com.example.springbootelasticsearch4.annotation.Field declaredAnnotation = f.getDeclaredAnnotation(com.example.springbootelasticsearch4.annotation.Field.class);// 如果嵌套对象if (declaredAnnotation.type() == FieldType.OBJECT) {// 获取当前类的对象-- ActionClass<?> type = f.getType();Field[] df2 = type.getDeclaredFields();builder.startObject(f.getName());builder.startObject("properties");// 遍历该对象中的所有属性for (Field f2 : df2) {if (f2.isAnnotationPresent(com.example.springbootelasticsearch4.annotation.Field.class)) {// 获取注解com.example.springbootelasticsearch4.annotation.Field declaredAnnotation2 = f2.getDeclaredAnnotation(com.example.springbootelasticsearch4.annotation.Field.class);builder.startObject(f2.getName());builder.field("type", declaredAnnotation2.type().getType());// keyword不需要分词if (declaredAnnotation2.type() == FieldType.TEXT) {builder.field("analyzer", declaredAnnotation2.analyzer().getType());}if (declaredAnnotation2.type() == FieldType.DATE) {builder.field("format", "yyyy-MM-dd HH:mm:ss");}builder.endObject();}}builder.endObject();builder.endObject();} else {builder.startObject(f.getName());builder.field("type", declaredAnnotation.type().getType());// keyword不需要分词if (declaredAnnotation.type() == FieldType.TEXT) {builder.field("analyzer", declaredAnnotation.analyzer().getType());}if (declaredAnnotation.type() == FieldType.DATE) {builder.field("format", "yyyy-MM-dd HH:mm:ss");}builder.endObject();}}}// 对应propertybuilder.endObject();builder.endObject();return builder;}/*** 1、创建索引* 默认分片数为5和副本数为1** @param clazz 根据实体自动映射es索引* @throws IOException*/public boolean createIndex(Class clazz) throws Exception {Document declaredAnnotation = (Document) clazz.getDeclaredAnnotation(Document.class);if (declaredAnnotation == null) {throw new Exception(String.format("class name: %s can not find Annotation [Document], please check", clazz.getName()));}String indexName = declaredAnnotation.index();boolean indexExists = isIndexExists(indexName);if (!indexExists) {CreateIndexRequest request = new CreateIndexRequest(indexName);request.settings(Settings.builder()// 设置分片数为3, 副本为2.put("index.number_of_shards", 3).put("index.number_of_replicas", 2));request.mapping(generateBuilder(clazz));CreateIndexResponse response = restHighLevelClient.indices().create(request, RequestOptions.DEFAULT);// 指示是否所有节点都已确认请求boolean acknowledged = response.isAcknowledged();// 指示是否在超时之前为索引中的每个分片启动了必需的分片副本数boolean shardsAcknowledged = response.isShardsAcknowledged();if (acknowledged || shardsAcknowledged) {log.info("创建索引成功!索引名称为{}", indexName);return true;}} else {log.info("索引已经存在!索引名称为{}", indexName);return false;}return false;}/*** 2、判断索引是否存在** @param indexName* @return*/public boolean isIndexExists(String indexName) {boolean exists = false;try {GetIndexRequest getIndexRequest = new GetIndexRequest(indexName);getIndexRequest.humanReadable(true);exists = restHighLevelClient.indices().exists(getIndexRequest, RequestOptions.DEFAULT);} catch (IOException e) {e.printStackTrace();}return exists;}/*** 3、更新索引* 默认分片数为5和副本数为1* 只能给索引上添加一些不存在的字段* 已经存在的映射不能改** @param clazz 根据实体自动映射es索引* @throws IOException*/public boolean updateIndex(Class clazz) throws Exception {Document declaredAnnotation = (Document) clazz.getDeclaredAnnotation(Document.class);if (declaredAnnotation == null) {throw new Exception(String.format("class name: %s can not find Annotation [Document], please check", clazz.getName()));}String indexName = declaredAnnotation.index();PutMappingRequest request = new PutMappingRequest(indexName);request.source(generateBuilder(clazz));AcknowledgedResponse response = restHighLevelClient.indices().putMapping(request, RequestOptions.DEFAULT);// 指示是否所有节点都已确认请求boolean acknowledged = response.isAcknowledged();if (acknowledged) {log.info("更新索引索引成功!索引名称为{}", indexName);return true;} else {log.info("更新索引索引失败!索引名称为{}", indexName);return false;}}/*** 4、删除索引** @param indexName* @return*/public boolean delIndex(String indexName) {boolean acknowledged = false;try {DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(indexName);deleteIndexRequest.indicesOptions(IndicesOptions.LENIENT_EXPAND_OPEN);AcknowledgedResponse delete = restHighLevelClient.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);acknowledged = delete.isAcknowledged();} catch (IOException e) {e.printStackTrace();}return acknowledged;}/*** 获取字段信息** @param o* @param annotationClass* @return*/private static Field getFieldByAnnotation(Object o, Class annotationClass) {Field[] declaredFields = o.getClass().getDeclaredFields();if (declaredFields != null && declaredFields.length > 0) {for (Field f : declaredFields) {if (f.isAnnotationPresent(annotationClass)) {return f;}}}return null;}/*** 5、添加单条数据* 提供多种方式:* 1. json* 2. map* Map<String, Object> jsonMap = new HashMap<>();* jsonMap.put("user", "kimchy");* jsonMap.put("postDate", new Date());* jsonMap.put("message", "trying out Elasticsearch");* IndexRequest indexRequest = new IndexRequest("posts").id("1").source(jsonMap);* 3. builder* XContentBuilder builder = XContentFactory.jsonBuilder();* builder.startObject();* {* builder.field("user", "kimchy");* builder.timeField("postDate", new Date());* builder.field("message", "trying out Elasticsearch");* }* builder.endObject();* IndexRequest indexRequest = new IndexRequest("posts").id("1").source(builder);* 4. source:* IndexRequest indexRequest = new IndexRequest("posts").id("1").source("user", "kimchy","postDate", new Date(),"message", "trying out Elasticsearch");** @return*/public IndexResponse addDocument(Object o) throws Exception {Document declaredAnnotation = (Document) o.getClass().getDeclaredAnnotation(Document.class);if (declaredAnnotation == null) {throw new Exception(String.format("class name: %s can not find Annotation [Document], please check", o.getClass().getName()));}String indexName = declaredAnnotation.index();IndexRequest request = new IndexRequest(indexName);Field fieldByAnnotation = getFieldByAnnotation(o, EsId.class);if (fieldByAnnotation != null) {fieldByAnnotation.setAccessible(true);try {Object id = fieldByAnnotation.get(o);request = request.id(id.toString());} catch (IllegalAccessException e) {log.error("获取id字段出错:{}", e);}}String userJson = JSON.toJSONString(o);request.source(userJson, XContentType.JSON);IndexResponse indexResponse = restHighLevelClient.index(request, RequestOptions.DEFAULT);return indexResponse;}/*** 6、根据id查询** @return*/public String queryDocumentById(String indexName, String id) throws IOException {GetRequest getRequest = new GetRequest(indexName, id);// getRequest.fetchSourceContext(FetchSourceContext.DO_NOT_FETCH_SOURCE);GetResponse getResponse = restHighLevelClient.get(getRequest, RequestOptions.DEFAULT);String jsonStr = getResponse.getSourceAsString();return jsonStr;}/*** 7、查询封装,返回json字符串** @param indexName* @param searchSourceBuilder* @return* @throws IOException*/public String search(String indexName, SearchSourceBuilder searchSourceBuilder) throws IOException {SearchRequest searchRequest = new SearchRequest(indexName);searchRequest.source(searchSourceBuilder);searchRequest.scroll(TimeValue.timeValueMinutes(1L));SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);String scrollId = searchResponse.getScrollId();SearchHits hits = searchResponse.getHits();JSONArray jsonArray = new JSONArray();for (SearchHit hit : hits) {String sourceAsString = hit.getSourceAsString();JSONObject jsonObject = JSON.parseObject(sourceAsString);jsonArray.add(jsonObject);}log.info("返回总数为:" + hits.getTotalHits());return jsonArray.toJSONString();}/*** 8、查询封装,返回带分页** @param searchSourceBuilder* @param pageNum* @param pageSize* @param s* @param <T>* @return* @throws IOException*/public <T> PageInfo<T> search(SearchSourceBuilder searchSourceBuilder, int pageNum, int pageSize, Class<T> s) throws Exception {Document declaredAnnotation = (Document) s.getDeclaredAnnotation(Document.class);if (declaredAnnotation == null) {throw new Exception(String.format("class name: %s can not find Annotation [Document], please check", s.getName()));}String indexName = declaredAnnotation.index();SearchRequest searchRequest = new SearchRequest(indexName);searchRequest.source(searchSourceBuilder);SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);SearchHits hits = searchResponse.getHits();JSONArray jsonArray = new JSONArray();for (SearchHit hit : hits) {String sourceAsString = hit.getSourceAsString();JSONObject jsonObject = JSON.parseObject(sourceAsString);jsonArray.add(jsonObject);}log.info("返回总数为:" + hits.getTotalHits());int total = (int) hits.getTotalHits().value;// 封装分页List<T> list = jsonArray.toJavaList(s);PageInfo<T> page = new PageInfo<>();page.setList(list);page.setPageNum(pageNum);page.setPageSize(pageSize);page.setTotal(total);page.setPages(total == 0 ? 0 : (total % pageSize == 0 ? total / pageSize : (total / pageSize) + 1));page.setHasNextPage(page.getPageNum() < page.getPages());return page;}/*** 9、查询封装,返回集合** @param searchSourceBuilder* @param s* @param <T>* @return* @throws IOException*/public <T> List<T> search(SearchSourceBuilder searchSourceBuilder, Class<T> s) throws Exception {Document declaredAnnotation = (Document) s.getDeclaredAnnotation(Document.class);if (declaredAnnotation == null) {throw new Exception(String.format("class name: %s can not find Annotation [Document], please check", s.getName()));}String indexName = declaredAnnotation.index();SearchRequest searchRequest = new SearchRequest(indexName);searchRequest.source(searchSourceBuilder);searchRequest.scroll(TimeValue.timeValueMinutes(1L));SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);String scrollId = searchResponse.getScrollId();SearchHits hits = searchResponse.getHits();JSONArray jsonArray = new JSONArray();for (SearchHit hit : hits) {String sourceAsString = hit.getSourceAsString();JSONObject jsonObject = JSON.parseObject(sourceAsString);jsonArray.add(jsonObject);}// 封装分页List<T> list = jsonArray.toJavaList(s);return list;}/*** 10、批量插入文档* 文档存在则更新* 文档不存在则插入** @param list* @return*/public <T> boolean batchSaveOrUpdate(List<T> list) throws Exception {Object o1 = list.get(0);Document declaredAnnotation = (Document) o1.getClass().getDeclaredAnnotation(Document.class);if (declaredAnnotation == null) {throw new Exception(String.format("class name: %s can not find Annotation [@Document], please check", o1.getClass().getName()));}String indexName = declaredAnnotation.index();BulkRequest request = new BulkRequest(indexName);for (Object o : list) {String jsonStr = JSON.toJSONString(o);IndexRequest indexReq = new IndexRequest().source(jsonStr, XContentType.JSON);Field fieldByAnnotation = getFieldByAnnotation(o, EsId.class);if (fieldByAnnotation != null) {fieldByAnnotation.setAccessible(true);try {Object id = fieldByAnnotation.get(o);indexReq = indexReq.id(id.toString());} catch (IllegalAccessException e) {log.error("获取id字段出错:{}", e);}}request.add(indexReq);}BulkResponse bulkResponse = restHighLevelClient.bulk(request, RequestOptions.DEFAULT);for (BulkItemResponse bulkItemResponse : bulkResponse) {DocWriteResponse itemResponse = bulkItemResponse.getResponse();IndexResponse indexResponse = (IndexResponse) itemResponse;log.info("单条返回结果:{}", indexResponse);if (bulkItemResponse.isFailed()) {log.error("es 返回错误{}", bulkItemResponse.getFailureMessage());return false;}}return true;}/*** 11、删除文档** @param indexName: 索引名称* @param docId: 文档id*/public boolean deleteDoc(String indexName, String docId) throws IOException {DeleteRequest request = new DeleteRequest(indexName, docId);DeleteResponse deleteResponse = restHighLevelClient.delete(request, RequestOptions.DEFAULT);// 解析responseString index = deleteResponse.getIndex();String id = deleteResponse.getId();long version = deleteResponse.getVersion();ReplicationResponse.ShardInfo shardInfo = deleteResponse.getShardInfo();if (shardInfo.getFailed() > 0) {for (ReplicationResponse.ShardInfo.Failure failure :shardInfo.getFailures()) {String reason = failure.reason();log.info("删除失败,原因为 {}", reason);}}return true;}/*** 12、根据json类型更新文档** @param indexName* @param docId* @param o* @return* @throws IOException*/public boolean updateDoc(String indexName, String docId, Object o) throws IOException {UpdateRequest request = new UpdateRequest(indexName, docId);request.doc(JSON.toJSONString(o), XContentType.JSON);UpdateResponse updateResponse = restHighLevelClient.update(request, RequestOptions.DEFAULT);String index = updateResponse.getIndex();String id = updateResponse.getId();long version = updateResponse.getVersion();if (updateResponse.getResult() == DocWriteResponse.Result.CREATED) {return true;} else if (updateResponse.getResult() == DocWriteResponse.Result.UPDATED) {return true;} else if (updateResponse.getResult() == DocWriteResponse.Result.DELETED) {return false;} else if (updateResponse.getResult() == DocWriteResponse.Result.NOOP) {return false;}return false;}/*** 13、根据Map类型更新文档** @param indexName* @param docId* @param map* @return* @throws IOException*/public boolean updateDoc(String indexName, String docId, Map<String, Object> map) throws IOException {UpdateRequest request = new UpdateRequest(indexName, docId);request.doc(map);UpdateResponse updateResponse = restHighLevelClient.update(request, RequestOptions.DEFAULT);String index = updateResponse.getIndex();String id = updateResponse.getId();long version = updateResponse.getVersion();if (updateResponse.getResult() == DocWriteResponse.Result.CREATED) {return true;} else if (updateResponse.getResult() == DocWriteResponse.Result.UPDATED) {return true;} else if (updateResponse.getResult() == DocWriteResponse.Result.DELETED) {return false;} else if (updateResponse.getResult() == DocWriteResponse.Result.NOOP) {return false;}return false;}}
6、实体
package com.example.springbootelasticsearch4.pojo;import com.example.springbootelasticsearch4.annotation.*;
import lombok.Data;/*** @author zhangshixing* @date 2022年01月16日 9:53* @Description ElasticSearch索引实体类*/@Data
@Document(index = "search_index", type = "")
public class Search {/*** 商品id*/@EsId@Field(type = FieldType.INTEGER)private Integer itemId;/*** 商品名字*/@Field(type = FieldType.TEXT, analyzer = AnalyzerType.IK_MAX_WORD)private String itemName;/*** 价格* 要进行范围筛选*/@Field(type = FieldType.DOUBLE)private Double price;/*** 规格名称* 多个规格组合*/@Field(type = FieldType.TEXT, analyzer = AnalyzerType.IK_MAX_WORD)private String itemSpecName;/*** 产地*/@Field(type = FieldType.KEYWORD)private String productPlace;/*** 保质期* 200天* 要进行范围筛选*/@Field(type = FieldType.INTEGER)private Integer footPeriod;/*** 品牌*/@Field(type = FieldType.TEXT, analyzer = AnalyzerType.IK_MAX_WORD)private String brand;/*** 包装方式*/@Field(type = FieldType.KEYWORD)private String packagingMethod;/*** 商品重量* 25g* 要进行范围筛选*/@Field(type = FieldType.DOUBLE)private Integer weight;/*** 食用方式*/@Field(type = FieldType.KEYWORD)private String eatMethod;/*** 销量* 要进行范围筛选*/@Field(type = FieldType.INTEGER)private Integer sellCounts;/*** 口味* 多种口味组合*/@Field(type = FieldType.TEXT, analyzer = AnalyzerType.IK_MAX_WORD)private String flavor;/*** 图片的展示图片*/@Field(type = FieldType.KEYWORD)private String showImg;}
这里会使用反射通过上面标注的注解来使用:比如我有一个实体,根据这个实体自动创建索引的方式如下; 首先
在实体上加入我们自定义的注解,来设置索引名称,字段的类型,分词器是什么。这里字符串类型在es中有两
种,一是KEY_WORD,不分词, 二是TEXT,会分词。
package com.example.springbootelasticsearch4.pojo;import lombok.*;/*** 将查询条件和分页条件都封装到一个VO中。*/
@Data
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class SearchVO {/*** 商品id*/private Integer itemId;/*** 商品名字*/private String itemName;/*** 价格* 要进行范围筛选*/private Double price;/*** 规格名称* 多个规格组合*/private String itemSpecName;/*** 产地*/private String productPlace;/*** 保质期* 200天* 要进行范围筛选*/private Integer footPeriod;/*** 品牌*/private String brand;/*** 包装方式*/private String packagingMethod;/*** 商品重量* 25g* 要进行范围筛选*/private Integer weight;/*** 食用方式*/private String eatMethod;/*** 销量* 要进行范围筛选*/private Integer sellCounts;/*** 口味* 多种口味组合*/private String flavor;/*** 图片的展示图片*/private String showImg;/*** 当前第几页*/private Integer pageNum;/*** 每页显示多少条数据*/private Integer pageSize;/*** 排序的字段名*/private String sortName;/*** 排的方式* 降序或者是升序*/private String orderSort;
}
7、Service
package com.example.springbootelasticsearch4.service;import com.example.springbootelasticsearch4.pojo.SearchVO;
import com.github.pagehelper.PageInfo;public interface QueryService {public PageInfo<SearchVO> pageSearchQuery(SearchVO searchVO) throws Exception;
}
package com.example.springbootelasticsearch4.service.impl;import com.example.springbootelasticsearch4.pojo.Search;
import com.example.springbootelasticsearch4.pojo.SearchVO;
import com.example.springbootelasticsearch4.service.QueryService;
import com.example.springbootelasticsearch4.utils.ElasticsearchUtil;
import com.github.pagehelper.PageInfo;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;/*** @author zhangshixing* @date 2021年11月11日 20:45*/
@Service
public class QueryServiceImpl implements QueryService {@Autowiredprivate ElasticsearchUtil elasticsearchUtil;@Overridepublic PageInfo<SearchVO> pageSearchQuery(SearchVO searchVO) throws Exception {SearchSourceBuilder searchSourceBuilder = getSearchSourceBuilder(searchVO);PageInfo page = elasticsearchUtil.search(searchSourceBuilder, searchVO.getPageNum(), searchVO.getPageSize(), Search.class);return page;}/*** 拼接综合查询 查询条件** @param searchVO* @return*/private SearchSourceBuilder getSearchSourceBuilder(SearchVO searchVO) {SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();// 设置第几页if (searchVO.getPageNum() == null) {searchVO.setPageNum(1);}// 设置每页显示的数量if (searchVO.getPageSize() == null) {searchVO.setPageSize(10000);}// 设置页数sourceBuilder.from((searchVO.getPageNum() - 1) * searchVO.getPageSize());sourceBuilder.size(searchVO.getPageSize());// 符合条件查询BoolQueryBuilder boolBuilder = QueryBuilders.boolQuery();if (StringUtils.isNotEmpty(searchVO.getItemName())) {boolBuilder.must(QueryBuilders.matchQuery("itemName", searchVO.getItemName()));}if (StringUtils.isNotEmpty(searchVO.getItemSpecName())) {boolBuilder.must(QueryBuilders.termQuery("itemSpecName", searchVO.getItemSpecName()));}if (searchVO.getPrice() != null) {boolBuilder.must(QueryBuilders.rangeQuery("price").gte(searchVO.getPrice()));}sourceBuilder.query(boolBuilder);// 排序if (StringUtils.isNotEmpty(searchVO.getSortName())) {FieldSortBuilder fieldSortBuilder = new FieldSortBuilder(searchVO.getSortName());// 按照升序还是降序排序fieldSortBuilder = fieldSortBuilder.order("orderDesc".equals(searchVO.getOrderSort()) ? SortOrder.DESC : SortOrder.ASC);sourceBuilder.sort(fieldSortBuilder);}return sourceBuilder;}
}
8、启动类
package com.example.springbootelasticsearch4;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class SpringBootElasticsearch4Application {public static void main(String[] args) {SpringApplication.run(SpringBootElasticsearch4Application.class, args);}}
9、测试
package com.example.springbootelasticsearch4;import com.example.springbootelasticsearch4.pojo.Search;
import com.example.springbootelasticsearch4.pojo.SearchVO;
import com.example.springbootelasticsearch4.service.QueryService;
import com.example.springbootelasticsearch4.utils.ElasticsearchUtil;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;@Slf4j
@SpringBootTest
class SpringBootElasticsearch4ApplicationTests {@Autowiredprivate ElasticsearchUtil elasticsearchUtil;@Autowiredprivate QueryService queryService;@Testvoid contextLoads() {try {elasticsearchUtil.createIndex(Search.class);} catch (Exception e) {e.printStackTrace();}}@Testvoid contextLoads1() {// 这里可以设置一些属性SearchVO searchVO = new SearchVO();PageInfo<SearchVO> returnPageInfo = null;try {returnPageInfo = queryService.pageSearchQuery(searchVO);} catch (Exception e) {log.error("es 综合查询异常,开始使用数据库做综合查询,错误为 :{}", e);// es异常,使用数据库查询// 进行数据库的一些查询操作// returnPageInfo = 数据库操作}System.out.println(returnPageInfo);}
}
这样就会根据创建一个叫做search_index
的索引(实体注解上配置),并且可以设置一些查询条件进行查询。
相关文章:
Springboot2.5.6整合Elasticsearch7.12.1完整示例
Springboot2.5.6整合Elasticsearch7.12.1完整示例 SpringBoot是2.5.6,elasticsearch是7.12.1 使用依赖elasticsearch-rest-high-level-client 使用RestHighLevelClient操作 1、引入Pom文件的依赖 <?xml version"1.0" encoding"UTF-8"?…...

全网超全,接口自动化测试-动态数据生成/替换数据(实战应用)
目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 接口自动化过程中…...
CRUD操作-select
CRUD操作-select 基本查询(一) -- CRUD操作 -- insert into -- insert -- replace intouse dbok; show tables; drop table if exists t5,t6,t_stu,t_student,t_teacher;-- 建立学生表 create table t_student(sid int unsigned auto_increment,sname v…...
SD-WAN网络加速及应用场景分析
SD-WAN技术实现网络加速的主要方式有以下几个: 智能路由:SD-WAN技术可以自动智能地选择最佳路径,将数据流量传输到最优路线上,从而避免了传统VPN网络较为笨重的配置和管理方式,大大节省了时间和精力,提高了…...

python机器学习(六)决策树(上) 构造树、信息熵的分类和度量、信息增益、CART算法、剪枝
决策树算法 模拟相亲的过程,通过相亲决策图,男的去相亲,会先选择性别为女的,然后依次根据年龄、长相、收入、职业等信息对相亲的另一方有所了解。 通过决策图可以发现,生活中面临各种各样的选择,基于我们的…...

eNSP:ospf和mgre的配置
完成下图操作: 信息标注: 如下是各路由器上的命令: r1: <Huawei>sys Enter system view, return user view with CtrlZ. [Huawei]sys r1 [r1]int loop0 [r1-LoopBack0]ip add 192.168.1.1 24 [r1-LoopBack0]int g0/0/0 …...

培训报名小程序-订阅消息发送
目录 1 创建API2 获取模板参数3 编写自定义代码4 添加订单编号5 发送消息6 发布预览 我们上一篇讲解了小程序如何获取用户订阅消息授权,用户允许我们发送模板消息后,按照模板的参数要求,我们需要传入我们想要发送消息的内容给模板,…...

资深测试员才知道的五个行业秘密
作为一名资深测试员,总有一些平时难以诉说的行业秘密,我也不例外。也许这些秘密你认可,也许你嗤之以鼻,但不管如何,我都希望能给你带来一丝感悟,更深的认识测试,并走得更远。 1、手工测试不可替…...
Ozone命令行接口详解
命令行接口简介 Ozone Shell是命令行与Ozone交互的主要界面,底层用的是Java。 有些功能只能通过Ozone Shell进行操作: 创建带有限额限制的Volume管理内部ACLs(访问控制列表)创建带有加密密钥的存储桶 大部分操作除了Shell操作…...

机器学习笔记 - 基于C++的深度学习 二、实现卷积运算
一、卷积 卷积是信号处理领域的老朋友。最初的定义如下 在机器学习术语中: I(…)通常称为输入 K(…)作为内核,并且 F(…)作为给定K的I(x)的特征图。 虑多维离散域,我们可以将积分转换为以下求和 对于二维数字图像,我们可以将其重写为: <...
python pandas 获取Excel文件下所有的sheet名称,表格数据
方法1: 一定要加sheet_nameNone,才能读取出所有的sheet,否则默认读取第一个sheet,且获取到的keys是第一行的值 df pd.read_excel(自己的Excel文件路径.xlsx, sheet_nameNone) # 路径注意转义 for i in df.keys():print(i)方法…...

gateway做token校验
本文使用springcloud的gateway做token校验 登录的本质:拿用户名和密码 换 token。 token会返回给浏览器(存储),当访问的时候,携带token 发起请求。 token校验图 引入redis依赖 <dependency><groupId>or…...
C#学习记录-线程
线程 定义:Thread t new Thread(Test); //可以用匿名 lamda 调用:t.Start("ljc6666");方法可以无参或一个参数,如果要传入多个参数,可以传入一个结构体 namespace _17_线程Thread {internal class Program{stati…...

Spring Boot 启动注解分析
虽然我们在日常开发中,Spring Boot 使用非常多,算是目前 Java 开发领域一个标配了,但是小伙伴们仔细想想自己的面试经历,和 Spring Boot 相关的面试题都有哪些?个人感觉应该是比较少的,Spring Boot 本质上还…...
React Native数据存储
最近做RN开发中需要数据存储,查阅RN官方资料,发现推荐我们使用 AsyncStorage,对使用步骤做一下记录。 AsyncStorage是什么 简单的,异步的,持久化的key-value存储系统AsyncStorage在IOS下存储分为两种情况: 存储内容较…...

【网络编程】揭开套接字的神秘面纱
文章目录 1 :peach:简单理解TCP/UDP协议 :peach:2 :peach:网络字节序 :peach:3 :peach:socket编程接口 :peach:3.1 :apple:socket 常见API :apple:3.2 :apple:sockaddr结构:apple: 4 :peach:简单的UDP网络程序 :peach:4.1 :apple:基本分析:apple:4.2 :apple:udpServer.hpp(重点…...
MySQL 8.0 事务定义和基本操作
MySQL 事务(Transaction)的四大特性:A、C、I、D A、原子性:(Atomicity) 一个事务是不可分割的最小工作单位。 执行的事务,要么全部成功,要么回滚到执行事务之前的状态。 C、一致…...
项目经理必备:常用的项目管理系统推荐!
当我们成为项目负责人时,找到合适的工具来管理跟进项目,就成为了迫切需要解决的问题。一款优秀的工具,在项目的管理跟进中,起着极为重要的作用,一般可以付费购买专门的项目管理软件。 1.可快速切换查看不同角度的项目信…...
【香瓜说职场】信任危机(2022.08.19)
自从17年4月份开始辞职创业,已经5年零4个月了。今天跟大家聊一点不太正能量的事。 首先关于“要不要说些不好的”这件事,我爸妈常建议我不要把不好的事情写出来,因为觉得丢人、不体面、怕影响合伙人关系、影响同事关系。而我觉得如果只写好的…...

【Rust】Rust学习 第六章枚举和模式匹配
本章介绍 枚举(enumerations),也被称作 enums。枚举允许你通过列举可能的 成员(variants) 来定义一个类型。首先,我们会定义并使用一个枚举来展示它是如何连同数据一起编码信息的。接下来,我们会…...
变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析
一、变量声明设计:let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性,这种设计体现了语言的核心哲学。以下是深度解析: 1.1 设计理念剖析 安全优先原则:默认不可变强制开发者明确声明意图 let x 5; …...

AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...
Neo4j 集群管理:原理、技术与最佳实践深度解析
Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...

k8s业务程序联调工具-KtConnect
概述 原理 工具作用是建立了一个从本地到集群的单向VPN,根据VPN原理,打通两个内网必然需要借助一个公共中继节点,ktconnect工具巧妙的利用k8s原生的portforward能力,简化了建立连接的过程,apiserver间接起到了中继节…...
docker 部署发现spring.profiles.active 问题
报错: org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...

用机器学习破解新能源领域的“弃风”难题
音乐发烧友深有体会,玩音乐的本质就是玩电网。火电声音偏暖,水电偏冷,风电偏空旷。至于太阳能发的电,则略显朦胧和单薄。 不知你是否有感觉,近两年家里的音响声音越来越冷,听起来越来越单薄? —…...

深度学习水论文:mamba+图像增强
🧀当前视觉领域对高效长序列建模需求激增,对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模,以及动态计算优势,在图像质量提升和细节恢复方面有难以替代的作用。 🧀因此短时间内,就有不…...

【C++特殊工具与技术】优化内存分配(一):C++中的内存分配
目录 一、C 内存的基本概念 1.1 内存的物理与逻辑结构 1.2 C 程序的内存区域划分 二、栈内存分配 2.1 栈内存的特点 2.2 栈内存分配示例 三、堆内存分配 3.1 new和delete操作符 4.2 内存泄漏与悬空指针问题 4.3 new和delete的重载 四、智能指针…...

LabVIEW双光子成像系统技术
双光子成像技术的核心特性 双光子成像通过双低能量光子协同激发机制,展现出显著的技术优势: 深层组织穿透能力:适用于活体组织深度成像 高分辨率观测性能:满足微观结构的精细研究需求 低光毒性特点:减少对样本的损伤…...