当前位置: 首页 > article >正文

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以及更早之前版本依赖
<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版本依赖
<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集成依赖

<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文件引入依赖

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

application.yml配置

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

ES初始化配置类实现

@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工具类

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

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

1.判断es索引是否存在
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.删除索引
@SneakyThrows
public static void delIndex(String indexName) {
    if (existIndex(indexName)) {
        return;
    }
    esClient.indices().delete(d -> d.index(indexName));
}
3.创建索引
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.新增文档
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.更新文档
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查询文档
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删除文档
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.查询文档列表
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详解

定义接口创建索引

定义业务方法
@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中不存在该用户");
    }
}
定义请求接口
@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版本的学习完成了


http://www.kler.cn/a/443878.html

相关文章:

  • Redis常见阻塞原因总结
  • gpu硬件架构
  • [LeetCode-Python版] 定长滑动窗口1(1456 / 643 / 1343 / 2090 / 2379)
  • linux 使用zip unzip命令
  • Elasticsearch-DSL高级查询操作
  • C++版实用时间戳类(Timestamp)
  • 分布式链路追踪-03-分布式系统跟踪工具,如何设计 span?
  • 基于JavaWeb(SSM+MySQL)问卷调查管理系统设计与实现毕业论文
  • 不同协议下的接口测试方案设计
  • CEF127 编译指南 MacOS 篇 - 编译 CEF(六)
  • 【计算机视觉基础CV】02-入门详解图像分类、经典数据集、比赛与冠军图像模型演进史
  • OpenCV DCT图像去噪(SIMD加速)
  • linux中 umask 命令
  • 流式处理,为什么Flink比Spark Streaming好?
  • 前端JavaScript(六)---JS中的事件
  • 中软高科身份证云解码金融(银行)解决方案介绍
  • 智源大模型通用算子库FlagGems四大能力升级 持续赋能AI系统开源生态
  • 简单工厂、工厂方法、抽象工厂的区别
  • 哪些视频媒体平台可给企业直播间做分发拉流转播宣传?提升流量数据!
  • 如何配置防火墙提高服务器安全性
  • 【C语言】常见的scanf()接收异常及注意事项
  • websocket的心跳检测和断线重连
  • 开源 AI 智能名片 S2B2C 商城小程序中运营与产品的关系剖析
  • PHP基于Google Authenticator双因素身份验证实现动态码验证
  • 江协科技 OLED库 OLED_Print( )函数自动换行
  • uniapp获取内容高度