SpringBoot集成Elasticsearch8.x(7)|(新版本Java API Client使用完整示例)
章节
第一章链接: 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
@Configuration
public class ElasticSearchConfig {
@Value("${es.hosts}")
private String hosts;
@Value("${es.name:elastic}")
private String name;
@Value("${es.password:aimind}")
private String password;
@Bean
public 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
@Component
public class ElasticsearchHandle {
@Autowired
private 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<String, Property> buildMapping( Map<String, String> propertyKeys) {
// Map<String, Property> documentMap = new HashMap<>();
// for (Map.Entry<String, String> 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
@AllArgsConstructor
public 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("<em>")
.postTags("</em>")
)
)
.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;
}
4.4.查询多条件OR匹配查询
参数介绍
docNo:文档编号
docTitle:文档标题
docContext:文档内容
输入参数:query
实现查询上述字段中含有query关键词操作,
类似于: docNo like query or docTitlelike query or docContextlike query
List<Query> list = Lists.newArrayList();
list.add(MatchQuery.of(t -> t.field("docNo").query(query).boost(1.2F))._toQuery());
list.add(MatchQuery.of(t -> t.field(" docTitle ").query(query).boost(1.5F))._toQuery());
list.add(MatchQuery.of(t -> t.field("docContext ").query(query).boost(1.8F))._toQuery());
try {
SearchResponse<DocumentParagraph> search = client.search(s -> s
.index(indexName)
.query(q -> q
.bool(b -> b
.should(list)
)
)
.from(0)
.size(top)
, DocumentParagraph.class
);
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.调用测试实现
实现索引的创建以及数据的存储查询示例文章来源:https://www.toymoban.com/news/detail-563376.html
@Api(tags = {"ES操作"})
@RestController
@RequestMapping("/es")
public class TestEsCurdCtrl {
@Autowired
public 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数据库内容,项目已经经过测试,主要类全部都在上面。大家可以参考文章来源地址https://www.toymoban.com/news/detail-563376.html
到了这里,关于SpringBoot集成Elasticsearch8.x(7)|(新版本Java API Client使用完整示例)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!