【SpringBoot】整合Elasticsearch 快速入门操作索引

官网操作文档: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()));
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Vue配置proxy代理,但接口报错2007 bad domain

1、排查proxy代理配置是否有误 排查 proxyTable 对象中配置的 target 是否正确。若正确&#xff0c;那可能就是请求头的问题。 无特殊配置的情况下&#xff0c;请求头是这样子的&#xff1a; Host 和 Referer 是本地地址&#xff0c;如果后端增加 CSRF 防御机制&#xff0c;…

to be delete

一、grafana版本升级 1.1 还是先跟着官网简单走一波 建议经常升级Grafana&#xff0c;以获取最新的修补程序和增强功能。 为了实现这一点&#xff0c;Grafana升级向后兼容&#xff0c;并且升级过程简单快捷。升级通常是安全的&#xff08;在许多次要版本和一个主要版本之间&a…

使用JSAPl来做一个倒计时的效果

今天的小案例需要做一个倒计时的效果 我们的时分秒需要一直进行倒计时&#xff0c;然后我们的页面颜色需要根据定时器的操作来进行更换&#xff0c;首先我们还是可以来分析一下我们的HTML步骤 <div class"countdown"><p class"next">今天是22…

线程的创建和使用(一)

1、线程 1.1、线程的概念 一个线程就是一个 "执行流". 每个线程之间都可以按照顺讯执行自己的代码. 多个线程之间 "同时" 执行着多份代码. 1.2、创建线程 方法一&#xff1a;继承Thread类 public class Exe_01 {public static void main(String[] args…

[论文阅读笔记76]GPT Understands, Too(P-tuning)

1. 基本信息 题目论文作者与单位来源年份GPT Understands, Too清华大学 Citations, References 论文链接&#xff1a;https://arxiv.org/pdf/2103.10385.pdf 论文代码&#xff1a; 2. 要点 研究主题问题背景核心方法流程亮点数据集结论论文类型关键字微调大模型采用传统微…

什么是HMI和SCADA?两者有什么区别

前言 几十年来&#xff0c;工业控制系统在工业自动化中发挥了重要作用&#xff0c;它允许过程制造商从生产车间采集、分析、处理数据。 在当今瞬息万变的工业环境中&#xff0c;制造商和公用事业公司必须采用现代HMI/SCADA和数字化转型&#xff0c;以跟上变化的步伐&#xff0…

Unity制作二次元卡通渲染角色材质——5、脸部的特殊处理

Unity制作二次元材质角色 回到目录 大家好&#xff0c;我是阿赵。 这里继续讲二次元角色材质的制作。这次是讲头部的做法。 1、脸部 之前在分析资源的时候&#xff0c;其实已经发现了这个模型的脸部法线有问题&#xff0c;导致在做光照模型的时候&#xff0c;脸部很奇怪。 把f…

NLP:词义分布的空间维度——从文本符号到词向量表征

自然语言处理的前提是文本表示&#xff08;Representation&#xff09;&#xff0c;即如何将人类符号化的文本转换成 计算机所能“理解”的表征形式。早期的自然语言表征主要采用离散表示。近年来&#xff0c;随着深度 学习的不断发展&#xff0c;基于神经网络的分布式词向量技…

概率论:方差、标准差、协方差、皮尔逊相关系数、线性相关

方差和标准差&#xff1a; 一个随机变量&#xff0c;的值的变化程度可以用方差计算&#xff1a; &#xff1b;其中 是期望。 另外一种等价表达式&#xff1a; 其中为均值&#xff0c;N为总体例数 我们举个例子&#xff1a; 服从均一分布&#xff0c;取值为0.1&#xff0c;0…

SpringSecurity多源认证之全部交给spring容器

文章目录 一. 前言二. 配置流程2.1 SecurityConfig.class2.2 JwtAuthenticationTokenFilter2.3 AuthenticationManagerProcessingFilter 疑问 一. 前言 相关文章: 认证/支付/优惠劵策略模式-security多源认证 这篇文章没有将自定义的认证管理器注入容器. spring-security2.6.…

CSS基础学习--7 fonts字体

一、CSS 字体 CSS字体属性定义字体系列&#xff0c;加粗&#xff0c;大小&#xff0c;文字样式。 二、字体系列 font-family 属性设置文本的字体系列 font-family 属性应该设置几个字体名称作为一种"后备"机制&#xff0c;如果浏览器不支持第一种字体&#xff0c;…

C++入门前必看,超详细

目录 前言 一.C的关键字 二.命名空间 2.1命名空间定义 2.2命名空间的使用 三.C的输入及输出 四.缺省参数 4.1概念 4.2缺省参数分类 4.3缺省参数的注意点 五.引用 5.1 概念 5.2引用的特性 六.内联函数 6.1概念 6.2内联函数的特性 七.auto 7.1auto概念 7.2auto的…

Unity入门5——Camera

一、参数面板 二、参数介绍 1. Clear Flags&#xff1a;清除背景 Skybox&#xff1a;天空盒背景&#xff08;通常用来做 3D 游戏&#xff09; Solid Color&#xff1a;使用 Background 颜色填充&#xff08;通常设置为全黑或全白&#xff0c;2D 使用&#xff09; Depth Only&am…

APP测试面试题快问快答(四)

16.App测试的实时日志如何获取&#xff1f; 考察点&#xff1a;是否有移动app测试的日志获取相关经验 一般可以通过以下方式获取&#xff1a; 1.可以使用adb命令&#xff1a;adb logcat | findstr "com.sankuai.meituan" >d:\test.txt 2.用ddms抓取&#xff0…

Postgresql源码(106)Generic Plan与Custom Plan的区别(以分区表为例)

相关&#xff1a; 《Postgresql源码&#xff08;105&#xff09;分区表剪枝代码分析》 《Postgresql源码&#xff08;106&#xff09;Generic Plan与Custom Plan的区别&#xff08;以分区表为例&#xff09;》 实例 CREATE TABLE measurement (city_id int not null,l…

FFmpeg音视频处理工具介绍及应用

1 FFmpeg介绍 FFmpeg项目由 Fabrice Bellard在2000年创立。到目前为止&#xff0c;FFmpeg项目的开发者仍然与VLC、MPV、dav1d、x264等多媒体开源项目有着广泛的重叠。Ffmpeg&#xff08;FastForward Mpeg&#xff09;是一款遵循GPL的开源软件&#xff0c;在音视频处理方面表现…

UDS关于0x37服务退出传输学习笔记

1.服务说明 客户端使用此服务来终止客户端和服务器之间的数据传输&#xff08;上传或下载&#xff09;。 2.请求消息 2.1请求消息子功能参数$Level&#xff08;LEV_&#xff09;定义 此服务不使用子函数参数。 2.2请求消息数据参数定义 transferRequestParameterRecord&a…

《微服务实战》 第二十九章 分布式事务框架seata AT模式

前言 本章节介绍微服务分布式项目中&#xff0c;使用的事务框架seata。 官网&#xff1a;http://seata.io/zh-cn/ springcloud-nacos-seata&#xff1a;https://github.com/seata/seata-samples/tree/master/springcloud-nacos-seata 1、概念 Seata 是一款开源的分布式事务解…

使用docker快速搭建redis哨兵模式

说明 本文主要参考&#xff1a; https://www.cnblogs.com/coderaniu/p/15352323.html https://developer.aliyun.com/article/892805 但是这两篇博客均缺失部分关键性细节&#xff0c;所以重新撰文。读者可以结合本文和上述文章一起阅读。 安装步骤 安装docker和docker-co…

小作文--流程图(练习1)

【【雅思写作】带你打破小作文‘流程图’的传说】 https://www.bilibili.com/video/BV1QP411Q7Gh/?share_sourcecopy_web&vd_source78768d4ae65c35ff26534bbaa8afc267 雅思小作文-流程图, 看这一篇就够了! - 冯凯文的文章 - 知乎 https://zhuanlan.zhihu.com/p/35868880 …