【SpringBoot】整合Elasticsearch 操作索引及文档

news2025/1/15 16:00:52

官网操作文档:Elasticsearch Clients | Elastic      

         踩坑太多了。。。这里表明一下Spring Boot2.4以上版本可能会出现问题,所以我降到了2.2.1.RELEASE。对于现在2023年6月而言,Es版本已经到了8.8,而SpringBoot版本已经到了3.x版本。如果是高版本的Boot在配置类的时候会发现RestHighLevelClient已过时。从官网也可以看的出来RestHighLevelClient已过时。所以这篇博文中不会用到关于RestHighLevelClient的Api。

        此篇博文的对应版本关系:Elasticsearch 8.2.0 + Spring Boot 2.7.5。在进入到下面的案例,我需要在这之前先介绍RestClient、RestHighLevelClient、RestClientTransport、ElasticsearchClient。

RestClient

        这个类主要是用作于与服务端IP以及端口的配置,在其的builder()方法可以设置登陆权限的账号密码、连接时长等等。总而言之就是服务端配置

RestClientTransport

        这是Jackson映射器创建传输。建立客户端与服务端之间的连接传输数据。这是在创建ElasticsearchClient需要的参数,而创建RestClientTransport就需要上面创建的RestClient。

ElasticsearchClient

        这个就是Elasticsearch的客户端。调用Elasticsearch语法所用到的类,其就需要传入上面介绍的RestClientTransport。

引入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<!-- 高版本还需引入此依赖 -->
<dependency>
    <groupId>jakarta.json</groupId>
    <artifactId>jakarta.json-api</artifactId>
    <version>2.0.0</version>
</dependency>

修改yml

        需要注意的是账号和密码可以不需要,看自己的Elasticsearch是否有配置账号密码。具体对Elasticsearch的登陆操作可以看:中偏下的位置就是对账号密码的设置。【Linux】Docker部署镜像环境 (持续更新ing)_小白的救赎的博客-CSDN博客

server:
  port: 8080

elasticsearch:
  hostAndPort: 192.168.217.128:9200 # 低版本使用的
  ip: 192.168.217.128
  port: 9200
  username: elastic
  password: 123456
  connectionTimeout: 1000
  socketTimeout: 30000

配置类    

        这里演示两种情况的配置:第一个代码块是SpringBoot2.4以下 + 7.x版本Elasticsearch的配置。第二个代码块是Spring2.4以上 + 8.x版本Elasticsearch的配置。

@Configuration
public class ElasticConfig extends AbstractElasticsearchConfiguration {

    @Value("${elasticsearch.hostAndPort}")
    private String hostAndPort;

    @Value("${elasticsearch.username}")
    private String username;

    @Value("${elasticsearch.password}")
    private String password;

    @Value("${elasticsearch.connectionTimeout}")
    private String connectTimeout;

    @Value("${elasticsearch.socketTimeout}")
    private String socketTimeout;

    /**
     * create Elasticsearch client
     * @return RestHighLevelClient
     */
    @Bean
    public RestHighLevelClient elasticsearchClient() {
        final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(AuthScope.ANY,new UsernamePasswordCredentials(username, password));
        ClientConfiguration clientConfiguration = ClientConfiguration.builder()
                .connectedTo(hostAndPort)
                .withConnectTimeout(Long.parseLong(connectTimeout))
                .withSocketTimeout(Long.parseLong(socketTimeout))
                .withBasicAuth(username, password)
                .build();
        return RestClients.create(clientConfiguration).rest();
    }

    /**
     * 将连接传入 Elasticsearch在 Spring Boot的模板类中
     * @return 返回 Es的模板类
     */
    @Bean
    public ElasticsearchRestTemplate elasticsearchRestTemplate() {
        return new ElasticsearchRestTemplate(elasticsearchClient());
    }
}
@Configuration
public class ElasticConfig {

    @Value("${elasticsearch.ip}")
    private String ip;

    @Value("${elasticsearch.port}")
    private String port;

    @Value("${elasticsearch.username}")
    private String username;

    @Value("${elasticsearch.password}")
    private String password;

    @Value("${elasticsearch.connectionTimeout}")
    private String connectTimeout;

    @Value("${elasticsearch.socketTimeout}")
    private String socketTimeout;

    /**
     * create Elasticsearch client
     * @return RestHighLevelClient
     */
    @Bean
    public ElasticsearchClient elasticsearchClient() {
        final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(AuthScope.ANY,new UsernamePasswordCredentials(username, password));

        RestClient restClient = RestClient.builder(
                new HttpHost(ip, Integer.parseInt(port)))
                .setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider))
                .setRequestConfigCallback(new RestClientBuilder.RequestConfigCallback() {
                    @Override
                    public RequestConfig.Builder customizeRequestConfig(RequestConfig.Builder builder) {
                        return builder.setConnectTimeout(Integer.parseInt(connectTimeout)).setSocketTimeout(Integer.parseInt(socketTimeout));
                    }
                }).build();

        ElasticsearchTransport transport 
                        = new RestClientTransport(restClient, new JacksonJsonpMapper());

        return new ElasticsearchClient(transport);
    }
}

控制层

        这里为了方便快速入门,就把所有业务代码都放在控制层中了。这篇博文主要是对索引进行操作,所以说获取到ElasticsearchClient后会调用indices()方法,这个方法就是操作索引的方法。次代码块是展示变量以及类注解。后面逐一暂时各个测试代码块Api以及返回结果。

@RestController
@RequestMapping("/es")
@Slf4j
public class EsController{

    @Autowired
    private ElasticConfig elasticConfig;
}

创建索引

/**
 * create index
 * @return is success?
 */
@PutMapping("/createIndex")
public boolean createIndex() throws IOException {
    CreateIndexRequest indexRequest 
                        = new CreateIndexRequest.Builder().index("user").build();
    CreateIndexResponse indexResponse 
                        = elasticConfig.esClient().indices().create(indexRequest);

    boolean isSuccess = indexResponse.acknowledged();
    if(isSuccess) {
        log.info("创建索引成功");
    } else {
        log.info("创建索引失败");
    }
    return isSuccess;
}

查询单个索引数据

/**
 * get one index data by id
 */
@GetMapping("/getIndex")
public void getIndex() throws IOException {
   GetResponse<User> response = elasticConfig.esClient().get(g -> g
           .index("user")
           .id("1000")
           ,User.class
   );
   if(response.found()) {
       log.info("此用户的姓名为,{}",response.source().getUsername());
   } else {
       log.info("未查询到此用户");
   }
}

删除索引

        这里我测试删除索引成功后又把索引添加了回去。为了后面的其它操作做准备。

/**
 * delete one index
 */
@DeleteMapping("/deleteIndex")
public boolean deleteIndex() throws IOException {
    DeleteIndexRequest indexRequest 
                        = new DeleteIndexRequest.Builder().index("user").build();
    DeleteIndexResponse deleteResponse 
                        = elasticConfig.esClient().indices().delete(indexRequest);
    boolean isSuccess = deleteResponse.acknowledged();
    if(isSuccess) {
        log.info("删除索引成功");
    } else {
        log.info("删除索引失败");
    }
    return isSuccess;
}

增加索引内容

        这里我新增了个实体类,方便添加到索引内容中。这里大概有四种方式可以创建,这里我演示了三种方式,第四种是使用到了ElasticsearchAsyncClient ,这是Elastic异步客户端。

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private String username;
    private String sex;
    private Integer age;
}
/**
 * 向索引内容插入数据
 */
@PostMapping("/insertIndexData")
public void insertIndexData() throws IOException {
    User user = new User("zhangSan","男",18);
    /*
    第一种方式:使用DSL语法创建对象
    IndexRequest<User> indexRequest = IndexRequest.of(i -> i
            .index("user")
            .id("1000")
            .document(user)
    IndexResponse indexResponse = elasticConfig.esClient().index(indexRequest.build());
    );
     */
    /*
    第二种方式:使用Elasticsearch客户端上配置的对象映射器映射到JSON。
    IndexResponse indexResponse = elasticConfig.esClient().index(i -> i
            .index("user")
            .id("1000")
            .document(user)
    );
     */
    // 第三种方式:使用构造器模式
    IndexRequest.Builder<User> indexRequest = new IndexRequest.Builder<>();
    indexRequest.index("user");
    indexRequest.id("1000");
    indexRequest.document(user);
    IndexResponse indexResponse = elasticConfig.esClient().index(indexRequest.build());
    log.info("index,{}",indexResponse.index());
    log.info("id,{}",indexResponse.id());
    log.info("version,{}",indexResponse.version());
}

批量添加索引数据

        BulkRequest包含一组操作,每个操作都是具有多个变体的类型。为了创建这个请求,可以方便地将构建器对象用于主请求,并将流利的DSL用于每个操作。下面的示例显示了如何为列表或应用程序对象编制索引。

        operations是BulkOperation的生成器,BulkOperation是一种变体类型。此类型具有索引创建更新删除变体。

/**
 * 批量插入索引数据
 */
@PostMapping("/batchInsertIndex")
public void batchInsertIndex() throws IOException {
    // 将需要批量添加的数据放到List中
    List<User> list = new ArrayList<>();
    list.add(new User("liSi","女",20));
    list.add(new User("wangWu","男",22));
    // 使用BulkRequest的构造器
    BulkRequest.Builder request = new BulkRequest.Builder();
    for(User user : list) {
        request.operations(l -> l
                .index(i -> i
                        .index("user")
                        .document(user)
                )
        );
    }
    BulkResponse response = elasticConfig.esClient().bulk(request.build());
    if(response.errors()) {
        log.info("批量插入报错");
    } else {
        log.info("批量插入成功");
    }
}

批量删除索引数据

/**
 * 批量删除索引数据
 */
@DeleteMapping("/batchDeleteIndex")
public void batchDeleteIndex() throws IOException {
    BulkRequest.Builder request = new BulkRequest.Builder();
    // 根据id做到删除索引的数据
    request.operations(l -> l
            .delete(i -> i
                    .index("user")
                    .id("vGK5sogBM87kk5Mw8V0P")
            )
    );
    request.operations(l -> l
            .delete(i -> i
                    .index("user")
                    .id("u2K5sogBM87kk5Mw8V0P")
            )
    );
    BulkResponse response = elasticConfig.esClient().bulk(request.build());
    if(response.errors()) {
        log.info("批量删除报错");
    } else {
        log.info("批量删除成功");
    }
}

          这里批量删除接口测试完后,我又批量添加了几行数据,方便下面方法的测试。

// 以下就是我添加的数据
list.add(new User("liSi","女",20));
list.add(new User("wangWu","男",22));
list.add(new User("zhaoLiu","男",20));
list.add(new User("xiaoQi","女",21));

简单查询/单条件

        可以组合多种类型的搜索查询。我们将从简单的文本匹配查询开始。单条件准确查询主要用到的关键字是term。而模糊查询就需要用到match。而match这里就不演示了。

/**
 * 单条件查询
 */
@GetMapping("/search")
public void search() throws IOException {
    SearchResponse<User> response = elasticConfig.esClient().search(s -> s
            .index("user")
            .query(q -> q
                    .term(e -> e
                            .field("age")
                            .value("20")
                    )
            ), User.class
    );
    // 获取查询后的命中条数:其中包括 TotalHitsRelation 以及 total
    TotalHits total = response.hits().total();
    boolean isExactResult = total.relation() == TotalHitsRelation.Eq;
    if (isExactResult) {
        log.info("There are " + total.value() + " results");
    } else {
        log.info("There are more than " + total.value() + " results");
    }
    // 解析查询到的所有信息
    List<Hit<User>> hits = response.hits().hits();
    for(Hit<User> hit : hits) {
        log.info("id,{}", hit.id());
    }
}

多条件查询 / 范围查询

        Elasticsearch允许将单个查询组合起来,以构建更复杂的搜索请求。当前数据有五条,为了更好的多条件查询,我又增加了5条数据。多条件查询用到的关键字主要就是bool

// 起初的5条数据
list.add(new User("zhangSan","男",18));
list.add(new User("liSi","女",20));
list.add(new User("wangWu","男",22));
list.add(new User("zhaoLiu","男",20));
list.add(new User("xiaoQi","女",21));
// 以下就是我添加的数据
list.add(new User("zhangSan","男",20));
list.add(new User("zhangSan","男",21));
list.add(new User("zhangSan","男",22));
list.add(new User("zhangSan","男",23));
list.add(new User("zhangSan","男",24));
/**
 * 多条件查询
 */
@GetMapping("/batchSearch")
public void batchSearch() throws IOException {
    // 查询性别
    Query sex = MatchQuery.of(m -> m
            .field("sex")
            .query("男")
    )._toQuery();
    // 查询年龄区间
    Query age = RangeQuery.of(r -> r
            .field("age")
            .lte(JsonData.of(20))
            .gte(JsonData.of(18))
    )._toQuery();
    // 结合性别和年龄区间查询来搜索用户索引
    SearchResponse<User> response = elasticConfig.esClient().search(s -> s
            .index("user")
            .query(q -> q
                .bool(b -> b
                    .must(sex)
                    .must(age)
                )
            ),User.class
    );
    // 获取查询后的命中条数:其中包括 TotalHitsRelation 以及 total
    TotalHits total = response.hits().total();
    boolean isExactResult = total.relation() == TotalHitsRelation.Eq;
    if (isExactResult) {
        log.info("There are " + total.value() + " results");
    } else {
        log.info("There are more than " + total.value() + " results");
    }
    // 解析查询到的所有信息
    List<Hit<User>> hits = response.hits().hits();
    for(Hit<User> hit : hits) {
        log.info("id,{}", hit.id());
    }
}

分页查询

        主要就是Elasticsearch语法中的from与size表示:当前页的开始索引处以及每页条数。

/**
 * 分页查询
 */
@GetMapping("/searchByPage")
public void searchByPage() throws IOException {
    // 假设每页3条数据 那么查询第二页的参数就是:开始索引处为(2 - 1) * 3 = 3 以及 每页条数3
    SearchResponse<User> response = elasticConfig.esClient().search(b -> b
            .index("user")
            .from(3)
            .size(3)
            ,User.class
    );
    log.info("查询到的总条数为,{}",response.hits().total().value());
    List<Hit<User>> hits = response.hits().hits();
    for(Hit<User> hit : hits) {
        log.info("查询到的id,{}", hit.id());
    }
}

查询所有索引数据

/**
 * get all index data
 */
@GetMapping("/getAllIndex")
public void getAllIndex() throws IOException {
    SearchResponse<User> response = elasticConfig.esClient().search(s -> s
            .index("user")
            ,User.class);
    // 解析查询到的所有信息
    List<Hit<User>> hits = response.hits().hits();
    for(Hit<User> hit : hits) {
        log.info(String.valueOf(hit.source()));
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/666742.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Hyper-v 虚拟机挂载物理硬盘的方法-Windows Server 2022/2025

起因&#xff1a; 之前我写过一篇介绍在KVM虚拟机体系下&#xff0c;如何直接挂载物理硬盘和物理分区的方法&#xff1a;KVM虚拟机直接挂栽物理硬盘分区的方法_给libvirt虚机挂载磁盘_lggirls的博客-CSDN博客。近期帮助一个朋友搭建局域网&#xff0c;其中有OA系统要用到window…

【安全】awvs使用(二)

目录 一、设置目标 二、设置登录 三、扫描引擎 四、开启扫描 五、扫描结束 六、报告 前言&#xff1a;怎么使用awvs进行扫描出报告呢&#xff1f; 一、设置目标 二、设置登录 因为扫描的网站需要登录的&#xff0c;这里需要设置这个 三、扫描引擎 四、开启扫描 翻译的页面…

【正点原子STM32连载】第三十六章 SPI实验 摘自【正点原子】STM32F103 战舰开发指南V1.2

1&#xff09;实验平台&#xff1a;正点原子stm32f103战舰开发板V4 2&#xff09;平台购买地址&#xff1a;https://detail.tmall.com/item.htm?id609294757420 3&#xff09;全套实验源码手册视频下载地址&#xff1a; http://www.openedv.com/thread-340252-1-1.html# 第三…

测试实战总结,性能测试-秒杀系统实战与优化,彻底打通性能测试...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 对于大并发量的系…

小程序跳转

小程序的路由跳转 一、路由跳转的方式 1.1 wx.navigateTo wx.navigateTo 保留当前页面&#xff0c;跳转到应用内的某个页面。会将页面缓放在页面栈中&#xff0c;最多十个。 wx.navigateTo({url: test })1.2 wx.redirectTo wx.redirectTo 关闭当前页面&#xff0c;跳转到应…

电商项目,订单如何测试?软件测试实战场景,所有测试点汇总...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 订单测试作为常见…

scanpy单细胞分析流程

梳理一下scanpy单细胞分析流程&#xff08;处理的是scRNA-seq&#xff09;。 先上一张流程图&#xff1a; scanpy单细胞分析流程 import scanpy as scRead data 常用的文件格式有两种&#xff0c;分别是h5ad和10X mtx # read h5ad adata sc.read()# read 10X mtx adata …

从小白到大神之路之学习运维第44天---第三阶段----拓展知识-----文件管理命令(find+sed+awk)、pycharm工具

第三阶段基础 时 间&#xff1a;2023年6月20日 参加人&#xff1a;全班人员 内 容&#xff1a; 目录 一、文件管理命令 find 1. 根据文件名查找文件 2. 根据文件类型查找文件 3. 根据文件大小查找文件 4. 根据时间戳查找文件 5. 组合多个条件查找文件 Sed 1. 替…

【Vue】学习笔记-创建Vue3.0工程

创建Vue3.0工程 使用vue-cli创建查看vue/cli版本&#xff0c;确保vue/cli版本在4.5.0以上安装或者升级你的vue/cli创建启动 使用vite创建创建工程进入工程目录安装依赖运行 使用vue-cli创建 官方文档&#xff1a;https://cli.vuejs.org/zh/guide/creating-a-project.html#vue-…

【性能测试】压力测试指标全解之TPS、响应时间

hello&#xff0c;大家好&#xff01;我是磨磨唧唧小蘑菇~ 接上期阐述了《TP50/90/99/999》的含义及计算方式&#xff0c;本期将阐述压力测试的其他指标&#xff0c;如TPS、响应时间等。 目录 一、TPS 二、响应时间 三、TPS与响应时间RT的关系 一、TPS 1、TPS的含义 …

vscode折叠代码展开快捷键

1.折叠所有代码 (按住ctrl 分别点击k和0) ctrlk,ctrl0 2.展开所有代码 (按住ctrl 分别点击k和j) ctrlk,ctrlj 3. 折叠鼠标竖线所在位置的节点以及当前节点下的子节点&#xff08;递归折叠&#xff09; ctrlk,ctrl[ 4. 展开鼠标竖线所在位置的节点以及当前节点下的子节点&#x…

【Springboot】关于Spring和SpringBoot的那些事儿

参考javaguide的学习笔记~ 1 怎么那么多名字呀~ 一开始看到这个图太劝退了&#xff0c;但实际上一开始只需要理解它是一个框架&#xff0c;包含很多个模块&#xff0c;能够简化开发。 使得接收HTTP请求&#xff0c;查数据库&#xff0c;写业务逻辑三部分能够分开。 并且能很…

【2023最全最叼教程】Selenium 自动化测试环境搭建

【导语】Selenium是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中&#xff0c;就像真正的用户在操作一样。支持自动录制动作和自动生成 .Net、Java、Perl等不同语言的测试脚本。本文详细介绍了搭建自动化测试环境所需的工具&#xff0c;让你学习自动化测试不…

人脸检测——基于机器学习3】AdaBoost算法

简介 主要工作AdaBoost算法的人脸检测算法包含的主要工作:(1)通过积分图快速求得Haar特征;(2)利用AdaBoost算法从大量的特征中选择出判别能力较强的少数特征用于人脸检测分类;(3)提出一个级联结构模型,将若干个弱分类器集成一个强分类器,其能够快速排除非人脸区域,…

系统架构设计师-系统工程与信息系统基础(2)

一、电子政务类型 电子政务主要有3类角色&#xff1a;政府&#xff08;Government&#xff09;、企&#xff08;事&#xff09;业单位&#xff08;Business&#xff09;及公民&#xff08;Citizen&#xff09;。如果有第4类就是公务员&#xff08;Employee&#xff09;。 二、企…

CMIP6降尺度方法

气候变化关系到农业、生态系统、社会经济和人类生存与发展&#xff0c;是当今世界关注的重点问题之一。IPCC&#xff08;Intergovernmental Panel on Climate Change&#xff09;第6次评估报告指出&#xff0c;自 20 世纪 50 年代以来&#xff0c;从全球平均气温和海温升高、大…

Unity核心10——导航寻路系统

Unity 中的导航寻路系统是能够让我们在游戏世界当中&#xff0c;让角色能够从一个起点准确的到达另一个终点&#xff0c;并且能够自动避开两个点之间的障碍物选择最近最合理的路径进行前往 ​ Unity 中的导航寻路系统的本质&#xff0c;就是在 A 星寻路算法的基础上进行了拓展和…

国家加强互联网广告监管

我是卢松松&#xff0c;点点上面的头像&#xff0c;欢迎关注我哦&#xff01; 5月1日《互联网广告管理办法》正式实施。 6月19日&#xff0c;市场监督总局要求加强广告监管。 主要针对直播带货广告、弹窗广告、“软文”广告等新型广告形式&#xff0c;加大互联网广告乱象清理…

HDLBits自学笔记3:Verilog language.Modules Hierarchy

Modules 在顶层模块中实例化模块mod_a&#xff0c;其端口描述&#xff1a; module mod_a ( input in1, input in2, output out ); module top_module ( input a, input b, output out );// 按信号名称连线mod_a u1(.in1(a),.in2(b),.out(out));// 按信号位置连线// mod_a u…

基于数据驱动 U-Net 模型的大气污染物扩散快速预测,提升计算速度近6000倍

项目背景 当前&#xff0c;常见的大气污染预测模型大多是基于物理机理构建的&#xff0c;比如空气质量预测模型 Calpuff、AERMOD、CMAQ 等。然而&#xff0c;这些模型运算较为复杂&#xff0c;对于输入数据的要求非常高&#xff0c;运算耗时也比较长&#xff0c;适合用于常规固…