欢迎访问我的GitHub
这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos
本篇概览
- 本篇是《java与es8实战》系列的第四篇,系列文章写到现在,连个HelloWorld都没运行起来,实在说不过去了...
- 因此,本篇总体目标明确:实战在SpringBoot应用中操作elasticsearch8
- 为了降低难度,本篇部署的elasticsearch8未设置安全检查,无需证书、账号、密码,只要连接到es的IP和端口就能执行操作
- 总体目标可以拆解为两个子任务
- 在SpringBoot中连接elasticsearch8
- 在SpringBoot中使用elasticsearch8官方的Java API Client
部署elasticsearch集群(无安全检查)
Java应用连接elasticsearch的核心套路
- 不论是直连,还是带安全检查的连接,亦或是与SpringBoot的集成使之更方便易用,都紧紧围绕着一个不变的核心套路,该套路由两部分组成,掌握了它们就能在各种条件下成功连接es
- 首先,是builder pattern,连接es有关的代码,各种对象都是其builder对象的build方法创建的,建议您提前阅读《java与es8实战之一》一文,看完后,满屏的builder代码可以从丑变成美...
- 其次,就是java应用能向es发请求的关键:ElasticsearchClient对象,该对象的创建是有套路的,如下图,先创建RestClient,再基于RestClient创建ElasticsearchTransport,最后基于ElasticsearchTransport创建ElasticsearchClient,这是个固定的套路,咱们后面的操作都是基于此的,可能会加一点东西,但不会改变流程和图中的对象

新建子工程
- 为了便于管理依赖库版本和源码,《java与es8实战》系列的所有代码都以子工程的形式存放在父工程elasticsearch-tutorials中
- 《java与es8实战之二:实战前的准备工作》一文说明了创建父工程的详细过程
- 在父工程elasticsearch-tutorials中新建名为basic-crud的子工程,其pom.xml内容如下
编码:配置文件
- 先准备好配置文件application.yml,内容如下,很简单,只有es的地址信息
- elasticsearch:
- # 多个IP逗号隔开
- hosts: 127.0.0.1:9200
复制代码 编码:配置类
- 首先把启动类写好,平平无奇的启动类BasicCrudApplication.java
- @SpringBootApplication
- public class BasicCrudApplication {
- public static void main(String[] args) {
- SpringApplication.run(BasicCrudApplication.class, args);
- }
- }
复制代码
- 然后是配置类ClientConfig.java,这是本篇的关键,操作ES所需的ElasticsearchClient实例如何创建,ES的IP地址如何传入,全部写在这里了
- package com.bolingcavalry.basic.config;
- import co.elastic.clients.elasticsearch.ElasticsearchAsyncClient;
- import co.elastic.clients.elasticsearch.ElasticsearchClient;
- import co.elastic.clients.json.jackson.JacksonJsonpMapper;
- import co.elastic.clients.transport.rest_client.RestClientTransport;
- import lombok.Setter;
- import org.apache.http.HttpHost;
- import org.elasticsearch.client.RestClient;
- import org.springframework.boot.context.properties.ConfigurationProperties;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.util.StringUtils;
- @ConfigurationProperties(prefix = "elasticsearch") //配置的前缀
- @Configuration
- public class ClientConfig {
- @Setter
- private String hosts;
- /**
- * 解析配置的字符串,转为HttpHost对象数组
- * @return
- */
- private HttpHost[] toHttpHost() {
- if (!StringUtils.hasLength(hosts)) {
- throw new RuntimeException("invalid elasticsearch configuration");
- }
- String[] hostArray = hosts.split(",");
- HttpHost[] httpHosts = new HttpHost[hostArray.length];
- HttpHost httpHost;
- for (int i = 0; i < hostArray.length; i++) {
- String[] strings = hostArray[i].split(":");
- httpHost = new HttpHost(strings[0], Integer.parseInt(strings[1]), "http");
- httpHosts[i] = httpHost;
- }
- return httpHosts;
- }
- @Bean
- public ElasticsearchClient elasticsearchClient() {
- HttpHost[] httpHosts = toHttpHost();
- RestClient restClient = RestClient.builder(httpHosts).build();
- RestClientTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
- return new ElasticsearchClient(transport);
- }
- @Bean
- public ElasticsearchAsyncClient elasticsearchAsyncClient() {
- HttpHost[] httpHosts = toHttpHost();
- RestClient restClient = RestClient.builder(httpHosts).build();
- RestClientTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
- return new ElasticsearchAsyncClient(transport);
- }
- }
复制代码
- 从上面的代码可以看出,配置类已经向Spring容器注册了ElasticsearchClient实例,后面的业务都可以使用此实例来操作ES
编码:服务类
- 本篇只是为了演示SpringBoot应用如何连接和操作ES,还不会深入ES操作的细节,因此只对索引做一些基本操作即可
- 先写一个接口IndexService.java,里面定义了多个索引操作的方法
- package com.bolingcavalry.basic.service;
- import co.elastic.clients.elasticsearch._types.mapping.TypeMapping;
- import co.elastic.clients.elasticsearch.indices.IndexSettings;
- import co.elastic.clients.util.ObjectBuilder;
- import java.io.IOException;
- import java.util.function.Function;
- public interface IndexService {
- /**
- * 新建指定名称的索引
- * @param name
- * @throws IOException
- */
- void addIndex(String name) throws IOException;
- /**
- * 检查指定名称的索引是否存在
- * @param name
- * @return
- * @throws IOException
- */
- boolean indexExists(String name) throws IOException;
- /**
- * 删除指定索引
- * @param name
- * @throws IOException
- */
- void delIndex(String name) throws IOException;
- /**
- * 创建索引,指定setting和mapping
- * @param name 索引名称
- * @param settingFn 索引参数
- * @param mappingFn 索引结构
- * @throws IOException
- */
- void create(String name,
- Function<IndexSettings.Builder, ObjectBuilder<IndexSettings>> settingFn,
- Function<TypeMapping.Builder, ObjectBuilder<TypeMapping>> mappingFn) throws IOException;
- }
复制代码
- 然后接口的实现,可见所有操作都是在调用ElasticsearchClient实例的API
- package com.bolingcavalry.basic.service.impl;
- import co.elastic.clients.elasticsearch.ElasticsearchClient;
- import co.elastic.clients.elasticsearch._types.mapping.TypeMapping;
- import co.elastic.clients.elasticsearch.indices.IndexSettings;
- import co.elastic.clients.util.ObjectBuilder;
- import com.bolingcavalry.basic.service.IndexService;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.context.ApplicationContext;
- import org.springframework.stereotype.Service;
- import java.io.IOException;
- import java.util.function.Function;
- @Service
- public class IndexServiceImpl implements IndexService {
- @Autowired
- private ElasticsearchClient elasticsearchClient;
- @Override
- public void addIndex(String name) throws IOException {
- ApplicationContext applicationContext;
- elasticsearchClient.indices().create(c -> c.index(name));
- }
- @Override
- public boolean indexExists(String name) throws IOException {
- ApplicationContext a;
- return elasticsearchClient.indices().exists(b -> b.index(name)).value();
- }
- @Override
- public void delIndex(String name) throws IOException {
- elasticsearchClient.indices().delete(c -> c.index(name));
- }
- @Override
- public void create(String name,
- Function<IndexSettings.Builder, ObjectBuilder<IndexSettings>> settingFn,
- Function<TypeMapping.Builder, ObjectBuilder<TypeMapping>> mappingFn) throws IOException {
- elasticsearchClient
- .indices()
- .create(c -> c
- .index(name)
- .settings(settingFn)
- .mappings(mappingFn)
- );
- }
- }
复制代码
- 以上就是本篇的功能代码了,连接ES在其上进行索引相关操作
编码:单元测试
- 为了验证上述代码是否生效,接下来写一个单元测试类IndexServiceTest.java,可以重点关注createIndex方法,里面演示了Builder pattern构建参数的详细步骤
- package com.bolingcavalry.basic.service;
- import co.elastic.clients.elasticsearch._types.mapping.Property;
- import co.elastic.clients.elasticsearch._types.mapping.TypeMapping;
- import co.elastic.clients.elasticsearch.indices.IndexSettings;
- import co.elastic.clients.util.ObjectBuilder;
- import org.junit.jupiter.api.Assertions;
- import org.junit.jupiter.api.Test;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.boot.test.context.SpringBootTest;
- import java.util.function.Function;
- @SpringBootTest
- class IndexServiceTest {
- @Autowired
- IndexService indexService;
- @Test
- void addIndex() throws Exception {
- String indexName = "test_index";
- Assertions.assertFalse(indexService.indexExists(indexName));
- indexService.addIndex(indexName);
- Assertions.assertTrue(indexService.indexExists(indexName));
- indexService.delIndex(indexName);
- Assertions.assertFalse(indexService.indexExists(indexName));
- }
- @Test
- void indexExists() throws Exception {
- indexService.indexExists("a");
- }
- @Test
- void createIndex() throws Exception {
- // 索引名
- String indexName = "product002";
- // 构建setting时,builder用到的lambda
- Function<IndexSettings.Builder, ObjectBuilder<IndexSettings>> settingFn = sBuilder -> sBuilder
- .index(iBuilder -> iBuilder
- // 三个分片
- .numberOfShards("3")
- // 一个副本
- .numberOfReplicas("1")
- );
- // 新的索引有三个字段,每个字段都有自己的property,这里依次创建
- Property keywordProperty = Property.of(pBuilder -> pBuilder.keyword(kBuilder -> kBuilder.ignoreAbove(256)));
- Property textProperty = Property.of(pBuilder -> pBuilder.text(tBuilder -> tBuilder));
- Property integerProperty = Property.of(pBuilder -> pBuilder.integer(iBuilder -> iBuilder));
- // // 构建mapping时,builder用到的lambda
- Function<TypeMapping.Builder, ObjectBuilder<TypeMapping>> mappingFn = mBuilder -> mBuilder
- .properties("name", keywordProperty)
- .properties("description", textProperty)
- .properties("price", integerProperty);
- // 创建索引,并且指定了setting和mapping
- indexService.create(indexName, settingFn, mappingFn);
- }
- }
复制代码
- 确保不做安全检查的ES集群运行正常,再执行单元测试,如下图,顺利通过,证明所有对ES的操作都符合预期

- 再用eshead观察product002索引的情况,如下图,三个分片,一个副本,与代码中设置的一致

- 至此最简单的连接和操作ES实战已经完成,希望本篇能给您一些参考,助您顺利完成基本操作
是不是线程安全的
源码下载
名称链接备注项目主页https://github.com/zq2599/blog_demos该项目在GitHub上的主页git仓库地址(https)https://github.com/zq2599/blog_demos.git该项目源码的仓库地址,https协议git仓库地址(ssh)git@github.com:zq2599/blog_demos.git该项目源码的仓库地址,ssh协议
- 这个git项目中有多个文件夹,本次实战的源码在elasticsearch-tutorials文件夹下,如下图红框

- elasticsearch-tutorials是个父工程,里面有多个module,本篇实战的module是basic-crud,如下图红框

欢迎关注博客园:程序员欣宸
学习路上,你不孤单,欣宸原创一路相伴...
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |