Elasticsearch 8.x 集成与 Java API 使用指南

目录

背景

版本区别

安装elaticsearch8.x服务

启动es服务

安装es管理平台

项目集成

pom.xml文件引入依赖

application.yml配置

ES初始化配置类实现

ES8.x常用API实现

1.判断es索引是否存在

2.删除索引

3.创建索引

4.新增文档

5.更新文档

6.根据id查询文档

7.根据id删除文档

8.查询文档列表

定义接口创建索引

定义业务方法

定义请求接口

操作接口


背景

随着 Elasticsearch 8.x 的发布,公司决定将现有的 Elasticsearch 7.x 版本升级到 8.x。然而,在升级过程中,我们发现许多 API 和功能发生了不兼容的变化,导致系统在迁移过程中遇到了大量问题。虽然官方文档提供了基本的操作指南,但实际应用中涉及的细节和调整却并未得到充分覆盖。为了帮助大家更顺利地过渡到 8.x,并有效应对这些变化, 本文将详细探讨 Elasticsearch 8.x 与 7.x 版本之间的主要差异,特别是在 Java 开发中的实际应用与迁移问题。

版本区别

依赖差异

  • 版本7.x以及更早之前版本依赖
XML 复制代码
<dependency>
  <groupId>org.elasticsearch</groupId>
  <artifactId>elasticsearch</artifactId>
  <version>7.x.x</version>
</dependency>
<dependency>
  <groupId>org.elasticsearch.client</groupId>
  <artifactId>elasticsearch-rest-high-level-client</artifactId>
  <version>7.x.x</version>
</dependency>
  • 8.x版本依赖
XML 复制代码
<dependency>
  <groupId>co.elastic.clients</groupId>
  <artifactId>elasticsearch-java</artifactId>
  <version>8.x.x</version>
</dependency>

**安全性增强 :**与 7.x 的默认无安全配置不同,8.x 默认启用安全功能,包括用户认证、授权、TLS 加密等,给开发者带来了更多的配置和管理任务。

查询和聚合优化:某些查询接口和聚合方法发生了变化,特别是对于大规模数据集的支持和性能提升方面有了显著进步,但这些变化需要开发者重新调整代码实现。

安装elaticsearch8.x服务

本文试例在window系统本地安装服务

启动es服务

elaticsearch版本为:8.16

官方下载地址:Past Releases of Elastic Stack Software | Elastic

百度云网盘:百度网盘 请输入提取码 提取码: 92h6

下载完解压目录如下

进入config目录修改yml文件

因为8.x版本默认开启权限校验以及ssl证书校验,为了方便后续使用,这里只保留权限校验,关闭ssl证书校验

进入bin目录执行cmd打开命令行重置登录密码

.\elasticsearch-reset-password -u elastic

默认账号:elastic

记得保存好密码,以免遗忘

进入bin目录双击elasticsearch.bat启动es服务

安装es管理平台

  1. 可自行安装es官方面板:kibana
  2. 本文使用的是google浏览器插件:Multi Elasticsearch Heads(可在google插件市场下载)

打开插件并连接es服务

连接成功

项目集成

这里通过集成在spring boot项目中来了解es8.x的配置连接以及api的使用

注:虽然基于springboot,但是我们这里不使用 spring boot data提供的es集成依赖

XML 复制代码
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
  <version>x.x.x</version>
</dependency>

因为data只提供了一些es简单操作的api,对于复杂的只有通过script手写DSL语句来完成,扩展性和维护性都不是很好,对不熟悉DSL语句的也很不友好,所以我们还是选择使用原生依赖 elasticsearch-java

可下载博主github源码参考: GitHub - RemainderTime/spring-boot-base-demo: 拿来即用springboot基础框架项目

pom.xml文件引入依赖

XML 复制代码
<!-- elasticsearch8.x 搜索引擎 -->
<dependency>
  <groupId>co.elastic.clients</groupId>
  <artifactId>elasticsearch-java</artifactId>
  <version>8.16.0</version>
</dependency>

application.yml配置

bash 复制代码
elasticsearch:
  host: localhost
  port: 9200
  username: elastic
  password: 8wVPrsP=9vlQWHBuHniH  #window系统本地启动 es8.x 重置密码命令:.\elasticsearch-reset-password -u elastic

ES初始化配置类实现

java 复制代码
@Component
public class EsConfig {

    @Value("${elasticsearch.host}")
    private String elasticsearchHost;
    @Value("${elasticsearch.port}")
    private int elasticsearchPort;
    @Value("${elasticsearch.username}")
    private String username;
    @Value("${elasticsearch.password}")
    private String password;

    /**
     -最大连接数 (maxConnTotal):设置总的最大连接数,取决于业务的并发量。500-2000 之间较为合理。
     -每个节点的最大连接数 (maxConnPerRoute):控制每个节点的最大连接数,建议 50-100 之间。
     -IO 线程数 (setIoThreadCount):根据 CPU 核心数设置,通常为 2-4 倍 CPU 核心数。
     -连接超时、套接字超时、获取连接超时:一般设置为 10-30 秒,复杂查询或大数据量操作可适当增加到 20-60 秒。
     -失败监听器 (setFailureListener):自定义重试和故障处理逻辑,确保高可用性。
     */
    @Bean
    public ElasticsearchClient elasticsearchClient() {
        // 创建凭证提供者
        CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(
            AuthScope.ANY,
            new UsernamePasswordCredentials(username, password)
        );
        // 自定义 RestClientBuilder 配置
        RestClientBuilder restClientBuilder = RestClient.builder(
            new HttpHost(elasticsearchHost, elasticsearchPort, "http")
        ).setHttpClientConfigCallback(httpClientBuilder ->
                                      httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider) // 配置认证信息
                                     );
        // 配置连接超时、套接字超时、获取连接超时
        restClientBuilder.setRequestConfigCallback(builder ->
                                                   builder.setConnectTimeout(20000)
                                                   .setSocketTimeout(20000)
                                                   .setConnectionRequestTimeout(20000)
                                                  );
        // 创建 RestClientTransport 和 ElasticsearchClient
        RestClient restClient = restClientBuilder.build();
        ElasticsearchTransport transport = new RestClientTransport(
            restClient,
            new JacksonJsonpMapper() // 使用 Jackson 进行 JSON 处理
        );
        return new ElasticsearchClient(transport);
    }
}

ES8.x常用API实现

先创建一个全局es工具类

java 复制代码
@Slf4j
@Component
public class EsUtil {
    public static ElasticsearchClient esClient;
    {
        esClient = (ElasticsearchClient) ApplicationContextUtils.getBean("elasticsearchClient");
    }
    /...
}

下面罗列工具类中实现的常用的操作方法。

1.判断es索引是否存在
java 复制代码
public static boolean existIndex(String indexName) {
        try {
            // 创建 ExistsRequest 请求
            ExistsRequest request = new ExistsRequest.Builder()
                    .index(indexName)
                    .build();
            // 发送请求并获取响应
            BooleanResponse response = esClient.indices().exists(request);
            // 返回索引是否存在
            return response.value();
        } catch (Exception e) {
            // 处理异常
            e.printStackTrace();
            return false;
        }
    }
2.删除索引
java 复制代码
@SneakyThrows
public static void delIndex(String indexName) {
    if (existIndex(indexName)) {
        return;
    }
    esClient.indices().delete(d -> d.index(indexName));
}
3.创建索引
java 复制代码
public static void createIndex(String indexName) {
    if (existIndex(indexName)) {
        throw new RuntimeException("索引已经存在");
    }
    try {
        CreateIndexResponse createIndexResponse = esClient.indices().create(c -> c.index(indexName));
        // 处理响应
        if (createIndexResponse.acknowledged()) {
            log.info(" indexed create successfully.");
        } else {
            log.info("Failed to create index.");
        }
    } catch (Exception e) {
        // 捕获异常并打印详细错误信息
        e.printStackTrace();
        throw new RuntimeException("创建索引失败,索引名:" + indexName + ",错误信息:" + e.getMessage(), e);
    }
}
4.新增文档
java 复制代码
public static boolean addDocument(EsBaseModel esBaseModel) {
    try {
        // 创建 IndexRequest 实例
        IndexRequest request = new IndexRequest.Builder()
        .index(esBaseModel.getIndexName())
        .id(esBaseModel.getDocumentId()) //指定文档id,不指定会自动生成
        .document(esBaseModel.getDocumentModel())
        .opType(OpType.Create) // 只会在文档 ID 不存在时创建文档
        .build();
    
        IndexResponse response = esClient.index(request);
        if ("created".equals(response.result())) {
            log.info("Document created: " + response.id());
            return true;
        } else {
            log.info("Document already exists or failed to create.");
            return false;
        }
    } catch (Exception e) {
        log.error("es新增文档失败", e);
        e.printStackTrace();
    }
    return false;
}
5.更新文档
java 复制代码
public boolean updateDocument(EsBaseModel esBaseModel) {
    try {
        UpdateRequest updateRequest = new UpdateRequest.Builder<>()
        .index(esBaseModel.getIndexName())
        .id(esBaseModel.getDocumentId())
        .doc(esBaseModel.getDocumentModel()).build();
        UpdateResponse updateResponse = esClient.update(updateRequest, esBaseModel.getClazz());
        log.info("Document updated: " + updateResponse.id());
        return true;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return false;
}
6.根据id查询文档
java 复制代码
public static <T> T getDocumentById(EsBaseModel esBaseModel) {
    try {
        GetRequest getRequest = new GetRequest.Builder()
        .index(esBaseModel.getIndexName())
        .id(esBaseModel.getDocumentId())
        .build();
        GetResponse<T> getResponse = esClient.get(getRequest, esBaseModel.getClazz());
        if (getResponse.found()) {
            return getResponse.source();
        }
    } catch (Exception e) {
        log.error("es列表查询失败", e);
    }
    return null;
}
7.根据id删除文档
java 复制代码
public static Boolean deleteDocumentById(EsBaseModel esBaseModel) {
    try {
        DeleteRequest deleteRequest = new DeleteRequest.Builder()
        .index(esBaseModel.getDocumentId())
        .id(esBaseModel.getDocumentId())
        .build();
        DeleteResponse deleteResponse = esClient.delete(deleteRequest);
        if ("deleted".equals(deleteResponse.result())) {
            log.info("Document deleted: " + deleteResponse.id());
            return true;
        } else {
            log.info("Document delete failed: " + deleteResponse.id());
            return false;
        }
    } catch (Exception e) {
        log.error("es列表删除失败", e);
    }
    return false;
}
8.查询文档列表
java 复制代码
public static <T> List<T> getDocumentList(EsSearchModel searchModel) {
    List<T> eslist = new ArrayList<>();
    try {
        SearchResponse<T> search = esClient.search(buildSearchRequest(searchModel), searchModel.getClazz());
        if (Objects.isNull(search)) {
            return eslist;
        }
        HitsMetadata<T> hits = search.hits();
        if (Objects.isNull(hits)) {
            return eslist;
        }
        List<Hit<T>> sourceHitList = hits.hits();
        if (CollectionUtils.isEmpty(sourceHitList)) {
            return eslist;
        }
        sourceHitList.forEach(item -> {
            // 处理每个命中
            eslist.add(item.source());
        });
        return eslist;
    } catch (Exception e) {
        log.error("es列表查询失败", e);
    }
    return eslist;
}

注意!!!由于方法太多,文中就不一一列举,想了解更多方法可下载上面博主提供的github地址进行下载项目并找到EsUtil.class类查看,里面有更多场景的使用方法和api详解

定义接口创建索引

定义业务方法
java 复制代码
@Slf4j
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public RetObj syncEs(Long userId) {
        User user = userMapper.selectById(userId);
        if (Objects.isNull(user)) {
            return RetObj.error("用户不存在");
        }
        String index = StringUtil.camelToKebabCase(user.getClass().getSimpleName());
        if (!EsUtil.existIndex(index)) {
            EsUtil.createIndex(index);
        }
        EsUtil.addDocument(new EsBaseModel(index, String.valueOf(user.getId()), user, user.getClass()));
        return RetObj.success();
    }

    @Override
    public RetObj getEsId(Long userId) {
        Object user = EsUtil.getDocumentById(new EsBaseModel("user", String.valueOf(userId), null, User.class));
        if(Objects.nonNull(user)){
            return RetObj.success(user);
        }
        return RetObj.error("es中不存在该用户");
    }
}
定义请求接口
java 复制代码
@RestController(value = "用户控制器")
@RequestMapping("/user")
@Tag(name = "用户控制器")
public class UserController {

    @Autowired
    private UserService userService;

    @Operation(summary = "es同步用户信息", description = "用户信息")
    @GetMapping("/syncEs")
    public RetObj syncEs(Long userId){
        return userService.syncEs(userId);
    }

    @Operation(summary = "es查询用户信息", description = "用户信息")
    @GetMapping("/getEsId")
    public RetObj getEsId(Long userId){
        return userService.getEsId(userId);
    }
}
操作接口

请求接口插入一条数据到索引中

查看面板发现自动创建了一个user索引

查询user索引中的数据存在一条

请求接口查询es数据


至此对于Elaticsearch8.x版本的学习完成了

相关推荐
代码小鑫几秒前
【毕业设计】A079-基于Java的影院订票系统的设计与实现
java·开发语言·数据库·spring boot·后端·毕业设计·课程设计
忆枫呐♬9 分钟前
Java中的Consumer接口应该如何使用(通俗易懂图解)
java·开发语言
zyh_03052120 分钟前
GIN
开发语言·后端·golang·gin
齐朋23 分钟前
缓存的使用与双写一致性问题
后端
yuanbenshidiaos1 小时前
c语言-----函数知识点
java·c语言·前端
凌抆莂1 小时前
浏览器引入elasticsearch-head插件
大数据·elasticsearch·jenkins
大G哥1 小时前
使用 Elasticsearch 查询和数据同步的实现方法
大数据·elasticsearch·搜索引擎·oracle·全文检索
ahhhhaaaa-1 小时前
【AI图像生成网站&Golang】项目测试与优化
开发语言·后端·性能优化·golang·pprof·trace
有点困的拿铁2 小时前
Spring篇--xml方式整合第三方框架
xml·java·spring