赞
踩
SpringBoot是2.5.6
,elasticsearch是7.12.1
使用依赖elasticsearch-rest-high-level-client
使用RestHighLevelClient
操作
<?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>
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; @Bean RestHighLevelClient 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() { @Override public RequestConfig.Builder customizeRequestConfig(RequestConfig.Builder requestConfigBuilder) { requestConfigBuilder.setConnectTimeout(connectTimeOut); requestConfigBuilder.setSocketTimeout(socketTimeOut); requestConfigBuilder.setConnectionRequestTimeout(connectionRequestTimeOut); return requestConfigBuilder; } }); // 异步httpclient连接数配置 builder.setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() { @Override public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) { httpClientBuilder.setMaxConnTotal(maxConnectNum); httpClientBuilder.setMaxConnPerRoute(maxConnectPerRoute); return httpClientBuilder; } }); RestHighLevelClient client = new RestHighLevelClient(builder); return client; } }
# 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
这里简单说一下,索引就相当于是表结构,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; } }
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 { @Resource private 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) { // 获取当前类的对象-- Action Class<?> 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(); } } } // 对应property builder.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); // 解析response String 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; } }
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; }
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 { @Autowired private ElasticsearchUtil elasticsearchUtil; @Override public 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; } }
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);
}
}
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 { @Autowired private ElasticsearchUtil elasticsearchUtil; @Autowired private QueryService queryService; @Test void contextLoads() { try { elasticsearchUtil.createIndex(Search.class); } catch (Exception e) { e.printStackTrace(); } } @Test void 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
的索引(实体注解上配置),并且可以设置一些查询条件进行查询。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。