SpringBoot集成Elasticsearch8.x(7)|(新版本Java API Client使用完整示例)
文章目录
- SpringBoot集成Elasticsearch8.x(7)|(新版本Java API Client使用完整示例)
- @[TOC]
- 前言
- 一、项目依赖
- 二、springboot集成实现
- 1.ElasticSearchConfig配置实现
- 2.elasticsearch工具类
- 3.定义一个ES存储数据结构体
- 4.elasticsearch查询工具类
- 4.1.查询满足条件的数据
- 4.2.查询某些分组下满足条件的数据
- 4.3.查询某个文档的数据并高亮显示关键词
- 5.elasticsearch增删工具类
- 5.1.批量增加数据
- 5.2.批量删除数据
- 5.调用测试实现
- 总结
- @[TOC]
- 1.ElasticSearchConfig配置实现
- 2.elasticsearch工具类
- 3.定义一个ES存储数据结构体
- 4.elasticsearch查询工具类
- 4.1.查询满足条件的数据
- 4.2.查询某些分组下满足条件的数据
- 4.3.查询某个文档的数据并高亮显示关键词
- 5.elasticsearch增删工具类
- 5.1.批量增加数据
- 5.2.批量删除数据
- 5.调用测试实现
章节
第一章链接: SpringBoot集成Elasticsearch7.x(1)|(增删改查功能实现)
第二章链接: SpringBoot集成Elasticsearch7.x(2)|(复杂查询)
第三章链接: SpringBoot集成Elasticsearch7.x(3)|(aggregations之指标聚合查询)
第四章链接: SpringBoot集成Elasticsearch7.x(4)|(aggregations之分桶聚合查询)
第五章链接: SpringBoot集成Elasticsearch7.x(5)|(term、match、match_phrase区别)
第六章链接: SpringBoot集成Elasticsearch8.x(6)|(新版本Java API Client使用)
第七章链接: SpringBoot集成Elasticsearch8.x(7)|(新版本Java API Client使用完整示例)
第八章链接:SpringBoot集成Elasticsearch8.x(8)|(新版本Java API Client的Painless语言脚本script使用)
前言
在Es7.15版本之后,es官方将它的高级客户端RestHighLevelClient标记为弃用状态。同时推出了全新的java API客户端Elasticsearch Java API Client,该客户端也将在Elasticsearch8.0及以后版本中成为官方推荐使用的客户端。
一、项目依赖
这里没有应用springboot版本自带elasticsearch依赖,自带的版本应该是7.x的,所以单独引入了elasticsearch8.x依赖
<!-- springboot 依赖 --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.5.7</version> <relativePath/> </parent> <!-- elasticsearch依赖 --> <dependency> <groupId>co.elastic.clients</groupId> <artifactId>elasticsearch-java</artifactId> <version>8.1.0</version> </dependency> <dependency> <groupId>org.glassfish</groupId> <artifactId>jakarta.json</artifactId> <version>2.0.1</version> </dependency>
二、springboot集成实现
1.ElasticSearchConfig配置实现
注入elasticsearch客户端,此处兼容了es的集群模式配置格式http://ip1:9200、http://ip2:9200
@Configurationpublic class ElasticSearchConfig {@Value("${es.hosts}")private String hosts;@Value("${es.name:elastic}")private String name;@Value("${es.password:aimind}")private String password;@Beanpublic ElasticsearchClient docqaElasticsearchClient() {final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(name, password));List<HttpHost> httpHosts = Lists.newArrayList();String[] split = hosts.split(",");for (int i = 0; i < split.length; i++) {httpHosts.add(HttpHost.create(split[i]));}HttpHost[] httpHosts1 = httpHosts.toArray(new HttpHost[0]);RestClient client = RestClient.builder(httpHosts1).setHttpClientConfigCallback(httpAsyncClientBuilder ->httpAsyncClientBuilder.setDefaultCredentialsProvider(credentialsProvider).setKeepAliveStrategy((response, context) -> 180 * 1000)).build();ElasticsearchTransport transport = new RestClientTransport(client, new JacksonJsonpMapper());return new ElasticsearchClient(transport);}}
2.elasticsearch工具类
ElasticsearchHandle工具类主要是封装elasticsearch的索引,数据对应的一些增删改查方法
@Slf4j@Componentpublic class ElasticsearchHandle {@Autowiredprivate ElasticsearchClient client;/** * 判断索引是否存在 * * @param indexName * @return * @throws IOException */public boolean hasIndex(String indexName) throws IOException {BooleanResponse exists = client.indices().exists(d -> d.index(indexName));return exists.value();}/** * 删除索引 * * @param indexName * @throws IOException */public boolean deleteIndex(String indexName) throws IOException {DeleteIndexResponse response = client.indices().delete(d -> d.index(indexName));return true;}/** * 创建索引 * * @param indexName * @return * @throws IOException */public boolean createIndex(String indexName) {try {CreateIndexResponse indexResponse = client.indices().create(c -> c.index(indexName));} catch (IOException e) {log.error("索引创建失败:{}", e.getMessage());throw new ExploException(HttpCode.INDEX_CREATE_ERROR, "创建索引失败");}return true;}/** * 创建索引,不允许外部直接调用 * * @param indexName * @param mapping * @throws IOException */private boolean createIndex(String indexName, Map<String, Property> mapping) throws IOException {CreateIndexResponse createIndexResponse = client.indices().create(c -> {c.index(indexName).mappings(mappings -> mappings.properties(mapping));return c;});return createIndexResponse.acknowledged();}//public Map buildMapping( Map propertyKeys) {//Map documentMap = new HashMap();//for (Map.Entry propertyKey : propertyKeys.entrySet()) {//String type = getIndxPropType(propertyKey.getValue());//String key = propertyKey.getKey();//log.info("属性:{}类型:{}", key, type);//if (type.equals("text")) {//documentMap.put(key, Property.of(property ->//property.keyword(KeywordProperty.of(p ->//p.index(true)//)//)//)//);//} else if (type.equals("date")) {//documentMap.put(key, Property.of(property ->//property.date(DateProperty.of(p ->//p.index(true).format("yyyy-MM-dd HH:mm:ss.SSS")//)//)//)//);//} else if (type.equals("long")) {//documentMap.put(key, Property.of(property ->//property.long_(LongNumberProperty.of(p ->//p.index(true)//)//)//)//);//} else if (type.equals("integer")) {//documentMap.put(key, Property.of(property ->//property.integer(//IntegerNumberProperty.of(p ->//p.index(false)//)//)//)//);//} else {//documentMap.put(key, Property.of(property ->//property.object(//ObjectProperty.of(p ->//p.enabled(true)//)//)//)//);//}//}//return documentMap;//}/** * 重新创建索引,如果已存在先删除 * * @param indexName * @param mapping */public void reCreateIndex(String indexName, Map<String, Property> mapping) {try {if (this.hasIndex(indexName)) {this.deleteIndex(indexName);}} catch (IOException e) {e.printStackTrace();throw new ExploException(HttpCode.INDEX_DELETE_ERROR, "删除索引失败");}try {this.createIndex(indexName, mapping);} catch (IOException e) {e.printStackTrace();throw new ExploException(HttpCode.INDEX_CREATE_ERROR, "重新创建索引失败");}}/** * 新增数据 * * @param indexName * @throws IOException */public boolean insertDocument(String indexName, Object obj, String id) {try {IndexResponse indexResponse = client.index(i -> i.index(indexName).id(id).document(obj));return true;} catch (IOException e) {log.error("数据插入ES异常:{}", e.getMessage());throw new ExploException(HttpCode.ES_INSERT_ERROR, "ES新增数据失败");}}/** * 查询数据 * * @param indexName * @param id * @return */public GetResponse<DocumentPartESDto> searchDocument(String indexName, String id) {try {GetResponse<DocumentPartESDto> getResponse = client.get(g -> g.index(indexName).id(id), DocumentPartESDto.class);return getResponse;} catch (IOException e) {log.error("查询ES异常:{}", e.getMessage());throw new ExploException(HttpCode.ES_SEARCH_ERROR, "查询ES数据失败");}}/** * 删除数据 * * @param indexName * @param id * @return */public boolean deleteDocument(String indexName, String id) {try {DeleteResponse deleteResponse = client.delete(d -> d.index(indexName).id(id));} catch (IOException e) {log.error("删除Es数据异常:{}", e.getMessage());throw new ExploException(HttpCode.ES_DELETE_ERROR, "数据删除失败");}return true;}}
3.定义一个ES存储数据结构体
定义一个实体,用于向ES中存储数据
@Data@Builder@NoArgsConstructor@AllArgsConstructorpublic class DocumentPartESDto {private String id;private String docId;private String kgId;private String content;private String type;}
4.elasticsearch查询工具类
由于我们使用大多情况是查询的场景,这里我来完善查询的一些方法
4.1.查询满足条件的数据
参数介绍
ndexName:为索引名称
query:查询的内容
top :查询条数
public List<DocumentParagraph> search(String indexName, String query,int top) {List<DocumentParagraph> documentParagraphs = Lists.newArrayList();try {SearchResponse<DocumentParagraph> search = client.search(s -> s.index(indexName).query(q -> q.match(t -> t.field("content").query(query))).from(0).size(top)//.sort(f -> f.field(o -> o.field("docId").order(SortOrder.Desc))), DocumentParagraph.class);for (Hit<DocumentParagraph> hit : search.hits().hits()) {DocumentParagraph pd = hit.source();documentParagraphs.add(pd);}} catch (IOException e) {log.error("查询ES异常:{}", e.getMessage());throw new ExploException(HttpCode.ES_SEARCH_ERROR, "查询ES数据失败");}return documentParagraphs;}
4.2.查询某些分组下满足条件的数据
参数介绍
ndexName:为索引名称
query:查询的内容
categoryId: 查询那些类别下的数据
top :查询条数
public List<DocumentParagraph> search(String indexName, String query, List<String> categoryId,int top) {List<DocumentParagraph> documentParagraphs = Lists.newArrayList();List<FieldValue> values = new ArrayList<>();for (String id : categoryId) {values.add(FieldValue.of(id));}Query categoryQuery = TermsQuery.of(t -> t.field("categoryId.keyword").terms(new TermsQueryField.Builder().value(values).build()))._toQuery();try {SearchResponse<DocumentParagraph> search = client.search(s -> s.index(indexName).query(q -> q.bool(b -> b.must(categoryQuery).should(sh -> sh.match(t -> t.field("content").query(query))))).highlight(h -> h.fields("content", f -> f.preTags("").postTags(""))).from(0).size(top), DocumentParagraph.class);for (Hit<DocumentParagraph> hit : search.hits().hits()) {DocumentParagraph pd = hit.source();documentParagraphs.add(pd);}} catch (IOException e) {log.error("查询ES异常:{}", e.getMessage());throw new ExploException(HttpCode.ES_SEARCH_ERROR, "查询ES数据失败");}return documentParagraphs;}/*** 高亮数据提取*/private DocumentParagraph highLight(Hit<DocumentParagraph> hit) {DocumentParagraph paragraph = hit.source();try {Map<String, List<String>> highlight = hit.highlight();List<String> list = highlight.get("content");String join = StringUtils.join(list, "");if (StringUtils.isNotBlank(join)) {paragraph.setContent(join);paragraph.setScore(hit.score());}} catch (Exception e) {log.error("获取ES高亮数据异常:{}", e.getMessage());}return paragraph;}/***解析高亮数据*/ Map<String, List<String>> highlight = hit.highlight();List<String> list = highlight.get("content");String join = StringUtils.join(list, "");if (StringUtils.isNotBlank(join)) {paragraph.setContent(join);}
4.3.查询某个文档的数据并高亮显示关键词
参数介绍
ndexName:为索引名称
id:文档id
public List<DocumentParagraph> searchDocumentByDocId(String indexName, String id) {List<DocumentParagraph> documentParagraphs = Lists.newArrayList();try {SearchResponse<DocumentParagraph> search = client.search(s -> s.index(indexName).query(q -> q.term(t -> t.field("docId").value(id))), DocumentParagraph.class);for (Hit<DocumentParagraph> hit : search.hits().hits()) {DocumentParagraph pd = hit.source();documentParagraphs.add(pd);}} catch (IOException e) {log.error("查询ES异常:{}", e.getMessage());throw new ExploException(HttpCode.ES_SEARCH_ERROR, "查询ES数据失败");}return documentParagraphs;}
5.elasticsearch增删工具类
批量增删也是常见类型
5.1.批量增加数据
参数介绍
ndexName:为索引名称
objs:插入实体
public boolean batchInsertDocument(String indexName, List<DocumentParagraph> objs) {try {List<BulkOperation> bulkOperationArrayList = new ArrayList<>();for (DocumentParagraph obj : objs) {bulkOperationArrayList.add(BulkOperation.of(o -> o.index(i -> i.document(obj))));}BulkResponse bulkResponse = client.bulk(b -> b.index(indexName).operations(bulkOperationArrayList));return true;} catch (IOException e) {log.error("数据插入ES异常:{}", e.getMessage());throw new ExploException(HttpCode.ES_INSERT_ERROR, "ES新增数据失败");}}
5.2.批量删除数据
删除文章下的所有数据
参数介绍
ndexName:为索引名称
docId:文章id
public Boolean deleteDocument(String indexName, String docId) {try {client.deleteByQuery(d -> d.index(indexName).query(q -> q.term(t -> t.field("docId").value(docId))));} catch (IOException e) {log.error("查询ES异常:{}", e.getMessage());}return true;}
5.调用测试实现
实现索引的创建以及数据的存储查询示例
@Api(tags = {"ES操作"})@RestController@RequestMapping("/es")public class TestEsCurdCtrl {@Autowiredpublic ElasticsearchHandle elasticsearchHandle;@ApiOperation(value = "添加es文件", notes = "添加es文件")@GetMapping(value = "/add")public ResponseHandle deleteDocument(@RequestParam(value = "id") String id) {DocumentPartESDto doc = DocumentPartESDto.builder().id(id).docId(id).content("这是文本内容" + id).type("doc").build();elasticsearchHandle.insertDocument("doc", doc, id);return ResponseHandle.SUCCESS("成功");}@ApiOperation(value = "查询es文件", notes = "查询es文件")@GetMapping(value = "/search")public ResponseHandle searchDocument(@RequestParam(value = "id") String id) {GetResponse<DocumentPartESDto> doc = elasticsearchHandle.searchDocument("doc", id);DocumentPartESDto docDto = doc.source();return ResponseHandle.SUCCESS(docDto);}@ApiOperation(value = "创建索引", notes = "创建索引")@GetMapping(value = "/index")public ResponseHandle createIndex(@RequestParam(value = "indexName") String indexName) {elasticsearchHandle.createIndex(indexName);return ResponseHandle.SUCCESS("成功");} /** * 创建mapping索引 * * @param indexName */ public static String esmappingV2 = "{\"properties\":{\"docId\":{\"type\":\"keyword\"},\"docName\":{\"type\":\"text\",\"analyzer\":\"ik_max_word\",\"search_analyzer\":\"ik_smart\",\"copy_to\":\"all\"},\"categoryId\":{\"type\":\"keyword\"},\"libVersionList\":{\"type\":\"keyword\"},\"content\":{\"type\":\"text\",\"analyzer\":\"ik_max_word\",\"search_analyzer\":\"ik_smart\",\"copy_to\":\"all\"},\"title\":{\"type\":\"text\",\"analyzer\":\"ik_max_word\",\"search_analyzer\":\"ik_smart\",\"copy_to\":\"all\"},\"all\":{\"type\":\"text\",\"analyzer\":\"ik_max_word\",\"search_analyzer\":\"ik_smart\"}}}";public void createIndexAndMapping(String indexName){try {JsonpMapper mapper = client._transport().jsonpMapper();JsonParser parser = mapper.jsonProvider().createParser(new StringReader(esmappingV2));client.indices().create(c -> c.index(indexName).mappings(TypeMapping._DESERIALIZER.deserialize(parser, mapper)));} catch (Exception e) {if (StringUtils.contains(e.getMessage(), "resource_already_exists_exception")) {log.warn("索引存在不创建");return;}log.error("es新增mapping索引异常:{}", e.getMessage());throw new SkynetException(HttpCode.ES_INDEX_ERROR.code(), HttpCode.ES_INDEX_ERROR.message());}}}
总结
以上就是SpringBoot集成Elasticsearch数据库内容,项目已经经过测试,主要类全部都在上面。大家可以参考