java与es8实战之四:SpringBoot应用中操作es8(无安全检查)

打印 上一主题 下一主题

主题 904|帖子 904|积分 2712

欢迎访问我的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内容如下
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3.          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  4.    
  5.     <parent>
  6.         <artifactId>elasticsearch-tutorials</artifactId>
  7.         <groupId>com.bolingcavalry</groupId>
  8.         <version>1.0-SNAPSHOT</version>
  9.         <relativePath>../pom.xml</relativePath>
  10.     </parent>
  11.     <modelVersion>4.0.0</modelVersion>
  12.    
  13.     <artifactId>basic-crud</artifactId>
  14.     <packaging>jar</packaging>
  15.    
  16.     <name>basic-crud</name>
  17.     <url>https://github.com/zq2599</url>
  18.    
  19.     <dependencyManagement>
  20.         <dependencies>
  21.             <dependency>
  22.                 <groupId>org.springframework.boot</groupId>
  23.                 <artifactId>spring-boot-dependencies</artifactId>
  24.                 <version>${springboot.version}</version>
  25.                 <type>pom</type>
  26.                 <scope>import</scope>
  27.             </dependency>
  28.         </dependencies>
  29.     </dependencyManagement>
  30.     <dependencies>
  31.         <dependency>
  32.             <groupId>org.springframework.boot</groupId>
  33.             <artifactId>spring-boot-starter-actuator</artifactId>
  34.         </dependency>
  35.         
  36.         <dependency>
  37.             <groupId>org.springframework.boot</groupId>
  38.             <artifactId>spring-boot-configuration-processor</artifactId>
  39.             <optional>true</optional>
  40.         </dependency>
  41.         <dependency>
  42.             <groupId>org.projectlombok</groupId>
  43.             <artifactId>lombok</artifactId>
  44.         </dependency>
  45.         <dependency>
  46.             <groupId>org.springframework.boot</groupId>
  47.             <artifactId>spring-boot-starter-web</artifactId>
  48.         </dependency>
  49.         <dependency>
  50.             <groupId>org.springframework.boot</groupId>
  51.             <artifactId>spring-boot-starter-test</artifactId>
  52.             <scope>test</scope>
  53.             
  54.             <exclusions>
  55.                 <exclusion>
  56.                     <groupId>junit</groupId>
  57.                     <artifactId>junit</artifactId>
  58.                 </exclusion>
  59.             </exclusions>
  60.         </dependency>
  61.         
  62.         <dependency>
  63.             <groupId>org.junit.jupiter</groupId>
  64.             <artifactId>junit-jupiter-api</artifactId>
  65.             <scope>test</scope>
  66.         </dependency>
  67.         <dependency>
  68.             <groupId>org.junit.jupiter</groupId>
  69.             <artifactId>junit-jupiter-engine</artifactId>
  70.             <scope>test</scope>
  71.         </dependency>
  72.         
  73.         <dependency>
  74.             <groupId>co.elastic.clients</groupId>
  75.             <artifactId>elasticsearch-java</artifactId>
  76.         </dependency>
  77.         <dependency>
  78.             <groupId>com.fasterxml.jackson.core</groupId>
  79.             <artifactId>jackson-databind</artifactId>
  80.         </dependency>
  81.         
  82.         <dependency>
  83.             <groupId>jakarta.json</groupId>
  84.             <artifactId>jakarta.json-api</artifactId>
  85.         </dependency>
  86.         <dependency>
  87.             <groupId>org.springframework.boot</groupId>
  88.             <artifactId>spring-boot-starter-web</artifactId>
  89.         </dependency>
  90.     </dependencies>
  91.     <build>
  92.         <plugins>
  93.             
  94.             <plugin>
  95.                 <groupId>org.apache.maven.plugins</groupId>
  96.                 <artifactId>maven-surefire-plugin</artifactId>
  97.                 <version>3.0.0-M4</version>
  98.                 <configuration>
  99.                     <skipTests>false</skipTests>
  100.                 </configuration>
  101.             </plugin>
  102.             <plugin>
  103.                 <groupId>org.springframework.boot</groupId>
  104.                 <artifactId>spring-boot-maven-plugin</artifactId>
  105.                 <configuration>
  106.                     <excludes>
  107.                         <exclude>
  108.                             <groupId>org.projectlombok</groupId>
  109.                             <artifactId>lombok</artifactId>
  110.                         </exclude>
  111.                     </excludes>
  112.                 </configuration>
  113.             </plugin>
  114.         </plugins>
  115.         <resources>
  116.             <resource>
  117.                 <directory>src/main/resources</directory>
  118.                 <includes>
  119.                     <include>**/*.*</include>
  120.                 </includes>
  121.             </resource>
  122.         </resources>
  123.     </build>
  124. </project>
复制代码
编码:配置文件


  • 先准备好配置文件application.yml,内容如下,很简单,只有es的地址信息
  1. elasticsearch:
  2.   # 多个IP逗号隔开
  3.   hosts: 127.0.0.1:9200
复制代码
编码:配置类


  • 首先把启动类写好,平平无奇的启动类BasicCrudApplication.java
  1. @SpringBootApplication
  2. public class BasicCrudApplication {
  3.     public static void main(String[] args) {
  4.         SpringApplication.run(BasicCrudApplication.class, args);
  5.     }
  6. }
复制代码

  • 然后是配置类ClientConfig.java,这是本篇的关键,操作ES所需的ElasticsearchClient实例如何创建,ES的IP地址如何传入,全部写在这里了
  1. package com.bolingcavalry.basic.config;
  2. import co.elastic.clients.elasticsearch.ElasticsearchAsyncClient;
  3. import co.elastic.clients.elasticsearch.ElasticsearchClient;
  4. import co.elastic.clients.json.jackson.JacksonJsonpMapper;
  5. import co.elastic.clients.transport.rest_client.RestClientTransport;
  6. import lombok.Setter;
  7. import org.apache.http.HttpHost;
  8. import org.elasticsearch.client.RestClient;
  9. import org.springframework.boot.context.properties.ConfigurationProperties;
  10. import org.springframework.context.annotation.Bean;
  11. import org.springframework.context.annotation.Configuration;
  12. import org.springframework.util.StringUtils;
  13. @ConfigurationProperties(prefix = "elasticsearch") //配置的前缀
  14. @Configuration
  15. public class ClientConfig {
  16.     @Setter
  17.     private String hosts;
  18.     /**
  19.      * 解析配置的字符串,转为HttpHost对象数组
  20.      * @return
  21.      */
  22.     private HttpHost[] toHttpHost() {
  23.         if (!StringUtils.hasLength(hosts)) {
  24.             throw new RuntimeException("invalid elasticsearch configuration");
  25.         }
  26.         String[] hostArray = hosts.split(",");
  27.         HttpHost[] httpHosts = new HttpHost[hostArray.length];
  28.         HttpHost httpHost;
  29.         for (int i = 0; i < hostArray.length; i++) {
  30.             String[] strings = hostArray[i].split(":");
  31.             httpHost = new HttpHost(strings[0], Integer.parseInt(strings[1]), "http");
  32.             httpHosts[i] = httpHost;
  33.         }
  34.         return httpHosts;
  35.     }
  36.     @Bean
  37.     public ElasticsearchClient elasticsearchClient() {
  38.         HttpHost[] httpHosts = toHttpHost();
  39.         RestClient restClient = RestClient.builder(httpHosts).build();
  40.         RestClientTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
  41.         return new ElasticsearchClient(transport);
  42.     }
  43.     @Bean
  44.     public ElasticsearchAsyncClient elasticsearchAsyncClient() {
  45.         HttpHost[] httpHosts = toHttpHost();
  46.         RestClient restClient = RestClient.builder(httpHosts).build();
  47.         RestClientTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
  48.         return new ElasticsearchAsyncClient(transport);
  49.     }
  50. }
复制代码

  • 从上面的代码可以看出,配置类已经向Spring容器注册了ElasticsearchClient实例,后面的业务都可以使用此实例来操作ES
编码:服务类


  • 本篇只是为了演示SpringBoot应用如何连接和操作ES,还不会深入ES操作的细节,因此只对索引做一些基本操作即可
  • 先写一个接口IndexService.java,里面定义了多个索引操作的方法
  1. package com.bolingcavalry.basic.service;
  2. import co.elastic.clients.elasticsearch._types.mapping.TypeMapping;
  3. import co.elastic.clients.elasticsearch.indices.IndexSettings;
  4. import co.elastic.clients.util.ObjectBuilder;
  5. import java.io.IOException;
  6. import java.util.function.Function;
  7. public interface IndexService {
  8.     /**
  9.      * 新建指定名称的索引
  10.      * @param name
  11.      * @throws IOException
  12.      */
  13.     void addIndex(String name) throws IOException;
  14.     /**
  15.      * 检查指定名称的索引是否存在
  16.      * @param name
  17.      * @return
  18.      * @throws IOException
  19.      */
  20.     boolean indexExists(String name) throws IOException;
  21.     /**
  22.      * 删除指定索引
  23.      * @param name
  24.      * @throws IOException
  25.      */
  26.     void delIndex(String name) throws IOException;
  27.     /**
  28.      * 创建索引,指定setting和mapping
  29.      * @param name 索引名称
  30.      * @param settingFn 索引参数
  31.      * @param mappingFn 索引结构
  32.      * @throws IOException
  33.      */
  34.     void create(String name,
  35.                 Function<IndexSettings.Builder, ObjectBuilder<IndexSettings>> settingFn,
  36.                 Function<TypeMapping.Builder, ObjectBuilder<TypeMapping>> mappingFn) throws IOException;
  37. }
复制代码

  • 然后接口的实现,可见所有操作都是在调用ElasticsearchClient实例的API
  1. package com.bolingcavalry.basic.service.impl;
  2. import co.elastic.clients.elasticsearch.ElasticsearchClient;
  3. import co.elastic.clients.elasticsearch._types.mapping.TypeMapping;
  4. import co.elastic.clients.elasticsearch.indices.IndexSettings;
  5. import co.elastic.clients.util.ObjectBuilder;
  6. import com.bolingcavalry.basic.service.IndexService;
  7. import org.springframework.beans.factory.annotation.Autowired;
  8. import org.springframework.context.ApplicationContext;
  9. import org.springframework.stereotype.Service;
  10. import java.io.IOException;
  11. import java.util.function.Function;
  12. @Service
  13. public class IndexServiceImpl implements IndexService {
  14.     @Autowired
  15.     private ElasticsearchClient elasticsearchClient;
  16.     @Override
  17.     public void addIndex(String name) throws IOException {
  18.         ApplicationContext applicationContext;
  19.         elasticsearchClient.indices().create(c -> c.index(name));
  20.     }
  21.     @Override
  22.     public boolean indexExists(String name) throws IOException {
  23.         ApplicationContext a;
  24.         return elasticsearchClient.indices().exists(b -> b.index(name)).value();
  25.     }
  26.     @Override
  27.     public void delIndex(String name) throws IOException {
  28.         elasticsearchClient.indices().delete(c -> c.index(name));
  29.     }
  30.     @Override
  31.     public void create(String name,
  32.                        Function<IndexSettings.Builder, ObjectBuilder<IndexSettings>> settingFn,
  33.                        Function<TypeMapping.Builder, ObjectBuilder<TypeMapping>> mappingFn) throws IOException {
  34.        elasticsearchClient
  35.                .indices()
  36.                .create(c -> c
  37.                        .index(name)
  38.                        .settings(settingFn)
  39.                        .mappings(mappingFn)
  40.                );
  41.     }
  42. }
复制代码

  • 以上就是本篇的功能代码了,连接ES在其上进行索引相关操作
编码:单元测试


  • 为了验证上述代码是否生效,接下来写一个单元测试类IndexServiceTest.java,可以重点关注createIndex方法,里面演示了Builder pattern构建参数的详细步骤
  1. package com.bolingcavalry.basic.service;
  2. import co.elastic.clients.elasticsearch._types.mapping.Property;
  3. import co.elastic.clients.elasticsearch._types.mapping.TypeMapping;
  4. import co.elastic.clients.elasticsearch.indices.IndexSettings;
  5. import co.elastic.clients.util.ObjectBuilder;
  6. import org.junit.jupiter.api.Assertions;
  7. import org.junit.jupiter.api.Test;
  8. import org.springframework.beans.factory.annotation.Autowired;
  9. import org.springframework.boot.test.context.SpringBootTest;
  10. import java.util.function.Function;
  11. @SpringBootTest
  12. class IndexServiceTest {
  13.     @Autowired
  14.     IndexService indexService;
  15.     @Test
  16.     void addIndex() throws Exception {
  17.         String indexName = "test_index";
  18.         Assertions.assertFalse(indexService.indexExists(indexName));
  19.         indexService.addIndex(indexName);
  20.         Assertions.assertTrue(indexService.indexExists(indexName));
  21.         indexService.delIndex(indexName);
  22.         Assertions.assertFalse(indexService.indexExists(indexName));
  23.     }
  24.     @Test
  25.     void indexExists() throws Exception {
  26.         indexService.indexExists("a");
  27.     }
  28.     @Test
  29.     void createIndex() throws Exception {
  30.         // 索引名
  31.         String indexName = "product002";
  32.         // 构建setting时,builder用到的lambda
  33.         Function<IndexSettings.Builder, ObjectBuilder<IndexSettings>> settingFn = sBuilder -> sBuilder
  34.                 .index(iBuilder -> iBuilder
  35.                         // 三个分片
  36.                         .numberOfShards("3")
  37.                         // 一个副本
  38.                         .numberOfReplicas("1")
  39.                 );
  40.         // 新的索引有三个字段,每个字段都有自己的property,这里依次创建
  41.         Property keywordProperty = Property.of(pBuilder -> pBuilder.keyword(kBuilder -> kBuilder.ignoreAbove(256)));
  42.         Property textProperty = Property.of(pBuilder -> pBuilder.text(tBuilder -> tBuilder));
  43.         Property integerProperty = Property.of(pBuilder -> pBuilder.integer(iBuilder -> iBuilder));
  44.         // // 构建mapping时,builder用到的lambda
  45.         Function<TypeMapping.Builder, ObjectBuilder<TypeMapping>> mappingFn = mBuilder -> mBuilder
  46.                 .properties("name", keywordProperty)
  47.                 .properties("description", textProperty)
  48.                 .properties("price", integerProperty);
  49.         // 创建索引,并且指定了setting和mapping
  50.         indexService.create(indexName, settingFn, mappingFn);
  51.     }
  52. }
复制代码

  • 确保不做安全检查的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,如下图红框

欢迎关注博客园:程序员欣宸

学习路上,你不孤单,欣宸原创一路相伴...

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

北冰洋以北

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表