ElasticSearch客户端JavaRestClient③(SpringBoot整合ES、结合spring-boot-test测试ES操作、索引库操作、文档操作)

目录

一、SpringBoot整合ES

1.1 创建SpringBoot项目

1.2 引入依赖  

1.3 客户端的初始化

二、索引库操作

2.1 创建索引库Mapping映射

2.2 索引库的CRUD

2.2.1 创建索引库

 2.2.2 判断索引库是否存在

2.2.3 删除索引库

2.2.4 获取和修改索引库

2.3 总结

三、文档操作

 3.1 创建实体类

3.2 新增文档

3.3 查询文档 

3.4 删除文档

3.5 修改文档

3.5.1 全量修改

3.5.2 局部修改

3.6 批处理文档

3.6.1 语法说明

3.6.2 批量新增文档 

3.6.3 批量删除文档 

3.6.4 批量修改文档 

3.7 DSL查询

3.8 小结


        在前面我们已经学习了ES当中各种各样的增删改查的接口,但是这些接口我们之前都是通过Kibana中的DevTools去调用的,在真正业务开发的时候,肯定需要用代码的方式调用这些api的接口,所以我们接下来就要学习一下ES给我们提供的Java客户端。这个Java客户名字叫做JavaRestClient。

        ES官方提供了各种不同语言的客户端,用来操作ES。这些客户端的本质就是组装DSL语句,通过http请求发送给ES。

官方文档地址:Elasticsearch Clients | Elastic

        由于ES目前最新版本是8.8,提供了全新版本的客户端,不过大多数企业使用的还是8以下版本,而我们采用的是7.12版本,所以我们选择使用早期的JavaRestClient客户端来学习。

一、SpringBoot整合ES

1.1 创建SpringBoot项目

1)New Project

2) 选择Spring项目,填写好项目信息点击下一步

3)选择SpringBoot的web依赖,点击创建

1.2 引入依赖  

引入ES的RestHighLevelClient依赖(依赖的版本号需要和安装的es版本保持一致)

<!-- https://mvnrepository.com/artifact/org.elasticsearch.client/elasticsearch-rest-high-level-client -->
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>7.12.0</version>
</dependency>

1.3 客户端的初始化

        在elasticsearch提供的API中,与elasticsearch一切交互都封装在一个名为RestHighLevelClient的类中,必须先完成这个对象的初始化,建立与elasticsearch的连接。 

初始化的代码如下: 

RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(
        HttpHost.create("http://192.168.150.101:9200")
));

在config文件夹下创建ES配置类

代码如下,es地址记得换成自己的ip


import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ESConfig {

    @Bean
    public RestHighLevelClient restHighLevelClient() {
        RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(
                HttpHost.create("http://127.0.0.1:9200")
        ));
        return client;
    }


}

测试ES配置是否成功,运行测试方法,打印如下,说明前面的配置没有问题,连接建立成功。

二、索引库操作

Index就类似数据库表,Mapping映射就类似表的结构。我们要向es中存储数据,必须先创建Index和Mapping

对Mapping映射属性不熟悉的可以看前面的章节:

ElasticSearch索引库操作②(索引库CRUD,文档CRUD)_es 索引crud-CSDN博客

2.1 创建索引库Mapping映射

这里我们创建一个商品索引库,供我们后面学习使用。

我们先把mapping的映射写好,然后以代码的方式通过Java客户端的Api创建索引库

# 名为goods的商品索引库映射
PUT /goods
{
  "mappings":{
    "properties":{
      "id":{
        "type":"keyword"
      },
      "name":{
        "type":"text",
        "analyzer":"ik_smart",
        "search_analyzer":"ik_smart"
      },
      "price":{
        "type":"integer"
      },
      "image":{
        "type":"keyword",
        "index":false
      },
      "category":{
        "type":"keyword"
      },
      "brand":{
        "type":"keyword"
      },
      "sold":{
        "type":"integer"
      },
      "commentCount":{
        "type":"integer",
        "index":false
      },
      "isPromotion":{
        "type":"boolean"
      },
      "updateTime":{
        "type":"date"
      }
    }
  }
}

2.2 索引库的CRUD

2.2.1 创建索引库

代码分为三步:

1)创建Request对象。

        因为是创建索引库的操作,因此Request是CreateIndexRequest

2)添加请求参数

        其实就是Json格式的Mapping映射参数。因为json字符串很长,这里是定义了静态字符串常量MAPPING_TEMPLATE,让代码看起来更加优雅。

3)发送请求

        client.indices()方法的返回值是IndicesClient类型,封装了所有与索引库操作有关的方法。例如创建索引、删除索引、判断索引是否存在等

在IndexTest类中,具体代码如下:


@SpringBootTest
public class IndexTest {

    public static final String MAPPING_TEMPLATE = "{\n" +
            "  \"mappings\":{\n" +
            "    \"properties\":{\n" +
            "      \"id\":{\n" +
            "        \"type\":\"keyword\"\n" +
            "      },\n" +
            "      \"name\":{\n" +
            "        \"type\":\"text\",\n" +
            "        \"analyzer\":\"ik_smart\"\n" +
            "      },\n" +
            "      \"price\":{\n" +
            "        \"type\":\"integer\"\n" +
            "      },\n" +
            "      \"image\":{\n" +
            "        \"type\":\"keyword\",\n" +
            "        \"index\":false\n" +
            "      },\n" +
            "      \"category\":{\n" +
            "        \"type\":\"keyword\"\n" +
            "      },\n" +
            "      \"brand\":{\n" +
            "        \"type\":\"keyword\"\n" +
            "      },\n" +
            "      \"sold\":{\n" +
            "        \"type\":\"integer\"\n" +
            "      },\n" +
            "      \"commentCount\":{\n" +
            "        \"type\":\"integer\",\n" +
            "        \"index\":false\n" +
            "      },\n" +
            "      \"isPromotion\":{\n" +
            "        \"type\":\"boolean\"\n" +
            "      },\n" +
            "      \"updateTime\":{\n" +
            "        \"type\":\"date\"\n" +
            "      }\n" +
            "    }\n" +
            "  }\n" +
            "}";

    @Resource
    private RestHighLevelClient restHighLevelClient;

    @Test
    public void testCreateIndex() throws IOException {
        // 1.准备Request对象,参数为要创建索引库的名称
        CreateIndexRequest request = new CreateIndexRequest("goods");
        // 2.准备请求参数
        request.source(MAPPING_TEMPLATE, XContentType.JSON);
        // 3.发送请求
        restHighLevelClient.indices().create(request, RequestOptions.DEFAULT);
    }


}

这里需要注意:CreateIndexRequest对象是org.elasticsearch.client.indices.CreateIndexRequest这个包下的,导错包可能会出响create方法过时

接下来我们就来验证一下,可以看到控制台没有异常,说明索引库创建成功了

 2.2.2 判断索引库是否存在

流程如下:

1)创建Request对象。这次是GetIndexRequest对象

2)准备参数。这里是无参,直接省略

3)发送请求。改用exists方法

    /**
     * 查询索引库是否存在
     */
    @Test
    public void testGetIndex() throws IOException {
        // 1.准备Request对象,参数为要查询的索引库名称
        GetIndexRequest request = new GetIndexRequest("goods");
        // 2.发送请求
        boolean exists = restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT);
        System.out.println("exists = " + exists);
    }

2.2.3 删除索引库

流程如下:

1)创建Request对象。这次是DeleteIndexRequest对象

2)准备参数。这里是无参,因此省略

3)发送请求。改用delete方法

    /**
     * 删除索引库
     */
    @Test
    public void testDeleteIndex() throws IOException {
        // 1.准备Request对象,参数为要删除的索引库名称
        DeleteIndexRequest request = new DeleteIndexRequest("goods");
        // 2.发送请求
        restHighLevelClient.indices().delete(request, RequestOptions.DEFAULT);
    }

删除索引库之后,再次查询,索引库已近不存在了

2.2.4 获取和修改索引库

        通常我们不需要拿到索引库的完整信息和修改索引库Mapping结构,我这边就不演示了,感兴趣的同学可以自己操作一下。

2.3 总结

        JavaRestClient操作elasticsearch的流程基本类似。核心是client.indices()方法来获取索引库的操作对象。

索引库操作的基本步骤:

  • 初始化RestHighLevelClient

  • 创建XxxIndexRequest。XXX是CreateGetDelete

  • 准备请求参数( Create时需要,其它是无参,可以省略)

  • 发送请求。调用RestHighLevelClient#indices().xxx()方法,xxx是createexistsdelete

三、文档操作

 3.1 创建实体类

我们要定义一个索引库结构对应的实体,方便后顺序的操作。

/**
 * goods索引库实体类
 */
@Data
public class GoodsDoc{

    private String id;
    private String name;
    private Integer price;
    private String image;
    private String category;
    private String brand;
    private Integer sold;
    private Integer commentCount;
    private Boolean isAD;
    private LocalDateTime updateTime;

}

引入Lombok依赖和Hutool工具包,方便后续操作

<!--引入Lombok依赖,自动生成Getter和Setter方法 -->
<dependency>
   <groupId>org.projectlombok</groupId>
   <artifactId>lombok</artifactId>
   <optional>true</optional>
</dependency>
<!--引入Hutool工具类-->
<dependency>
   <groupId>cn.hutool</groupId>
   <artifactId>hutool-all</artifactId>
   <version>5.8.16</version>
</dependency>

3.2 新增文档

步骤如下:

1)创建Request对象,这里是IndexRequest,因为添加文档就是创建倒排索引的过程

2)准备请求参数

3)发送请求


import cn.hutool.json.JSONUtil;
import com.zhijia.domain.dto.GoodsDoc;
import jakarta.annotation.Resource;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import java.io.IOException;
import java.util.Date;

@SpringBootTest
public class EsDocumentTest {

    @Resource
    private RestHighLevelClient restHighLevelClient;

    @Test
    public void testIndexDocument() throws IOException {
        // 1.准备文档数据,这里的数据我就写固定的了,实际开发中要从其他数据库获取
        GoodsDoc goodsDoc = new GoodsDoc();
        goodsDoc.setId("001");
        goodsDoc.setName("华为手机");
        goodsDoc.setCategory("手机");
        goodsDoc.setBrand("华为");
        goodsDoc.setImage("https://www.abc.com");
        goodsDoc.setSold(123);
        goodsDoc.setPrice(2000);
        goodsDoc.setCommentCount(100);
        goodsDoc.setIsPromotion(false);
        goodsDoc.setUpdateTime(new Date());

        // 2.创建Request对象,goods为要新增到的索引库名称,id()指定这条文档的id
        IndexRequest request = new IndexRequest("goods").id(goodsDoc.getId());
        // 3.准备JSON文档参数
        request.source(JSONUtil.toJsonStr(goodsDoc), XContentType.JSON);
        // 4.发送新增请求,这里的index()方法就是新增文档的方法
        restHighLevelClient.index(request, RequestOptions.DEFAULT);
    }
}

运行测试方法,没有任何异常就是创建成功了

3.3 查询文档 

与之前的流程类似:

  1. 创建Request对象

  2. 准备请求参数,这里是无参,直接省略

  3. 发送请求

    /**
     * 查询文档
     */
    @Test
    public void testGetDocument() throws IOException {
        // 1.创建Request对象,第一个参数为索引库名称,第二个参数为文档的id
        GetRequest request = new GetRequest("goods","001");
        // 2.发送查询请求
        GetResponse response = restHighLevelClient.get(request, RequestOptions.DEFAULT);
        // 3.获取响应结果,source里面才是我们要的信息
        String sourceAsString = response.getSourceAsString();
        // 4.将JSON字符串转成Java实体类
        GoodsDoc goodsDoc = JSONUtil.toBean(sourceAsString, GoodsDoc.class);

        System.out.println(goodsDoc);
    }

运行结果:

3.4 删除文档

与查询相比,仅仅是请求方式从DELETE变成GET

1)准备Request对象,因为是删除,这次是DeleteRequest对象。要指定索引库名和id

2)准备参数,无参,直接省略

3)发送请求。因为是删除,所以是client.delete()方法

     /**
     * 删除文档
     */
    @Test
    public void testDeleteDocument() throws IOException {
        // 1.创建Request对象,第一个参数是索引库名,第二个参数是要删除的文档id
        DeleteRequest request = new DeleteRequest("goods","001");
        // 2.发送请求
        restHighLevelClient.delete(request, RequestOptions.DEFAULT);
    }

执行方法之后,再次获取id为001文档,可以发现是空的

3.5 修改文档

修改文档数据有两种方式:

方式一:全量修改。写入id如果存在,就会删除旧文档,然后添加新文档。与新增的JavaAPI一致

方式二:局部修改。只更新指定部分字段。

3.5.1 全量修改

此时还没有id为001的文档,执行index方法,可以看到是新增操作(created)

在id存在的情况下,我将price改为666,再执行一次index方法,可以发现就是updated操作了

再次查询,可以看到id为001的文档,价格被改成666了

3.5.2 局部修改

与之前类似,也是三步走:

1)准备Request对象。这次是修改,所以是UpdateRequest

2)准备参数。也就是JSON文档,里面包含要修改的字段

3)更新文档。这里调用client.update()方法

    /**
     * 修改文档
     */
    @Test
    public void testUpdateDocument() throws IOException {
        // 1.创建Request对象,第一个参数是索引库名,第二个参数是要修改的文档id
        UpdateRequest request = new UpdateRequest("goods", "001");
        // 2.准备请求参数,每两个参数为一对 key,value
        request.doc(
                "price",999
        );
        // 3.更新文档
        restHighLevelClient.update(request, RequestOptions.DEFAULT);

    }

执行修改之后,可以看到价格被修改为999了

3.6 批处理文档

3.6.1 语法说明

BulkRequest本身其实并没有请求参数,其本质就是将多个普通的CRUD请求组合在一起发送。例如:

  • 批量新增文档:就是给每个文档创建一个IndexRequest请求,然后封装到BulkRequest中,一起发出。

  • 批量删除文档:就是创建N个DeleteRequest请求,然后封装到BulkRequest,一起发出 

 因此BulkRequest中提供了add方法,用以添加其它CRUD的请求:

可以看到,能添加的请求有:

  • IndexRequest,也就是新增

  • UpdateRequest,也就是修改

  • DeleteRequest,也就是删除

3.6.2 批量新增文档 

批处理与前面讲的文档的CRUD步骤基本一致:

  • 创建Request,但这次用的是BulkRequest

  • 准备请求参数

  • 发送请求,这次要用到client.bulk()方法

    /**
     * 批量新增文档
     */
    @Test
    public void testBulkDocument() throws IOException {
        // 1.准备文档数据,这里的数据我就写固定的了,实际开发中要从其他数据库获取
        List<GoodsDoc> goodsDocList = new ArrayList<>();
        for (int i = 1; i < 3; i++) {
            GoodsDoc goodsDoc = new GoodsDoc();
            goodsDoc.setId("00"+i);
            goodsDoc.setName("华为手机");
            goodsDoc.setCategory("手机");
            goodsDoc.setBrand("华为");
            goodsDoc.setImage("https://www.abc.com");
            goodsDoc.setSold(i * 123);
            goodsDoc.setPrice(i * 666);
            goodsDoc.setCommentCount(i * 100);
            goodsDoc.setIsPromotion(false);
            goodsDoc.setUpdateTime(new Date());
            goodsDocList.add(goodsDoc);
        }

        BulkRequest bulkRequest = new BulkRequest();

        bulkRequest.add(new IndexRequest("goods").id(goodsDocList.get(0).getId()).source(JSONUtil.toJsonStr(goodsDocList.get(0)), XContentType.JSON));
        bulkRequest.add(new IndexRequest("goods").id(goodsDocList.get(1).getId()).source(JSONUtil.toJsonStr(goodsDocList.get(1)), XContentType.JSON));

        restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);

    }

3.6.3 批量删除文档 

     /**
     * 批量删除文档
     */
    @Test
    public void testBulkDeleteDocument() throws IOException {
        // 1.准备文档数据,这里的数据我就写固定的了,实际开发中要从其他数据库获取
        List<GoodsDoc> goodsDocList = new ArrayList<>();
        for (int i = 1; i < 3; i++) {
            GoodsDoc goodsDoc = new GoodsDoc();
            goodsDoc.setId("00"+i);
            goodsDoc.setName("华为手机");
            goodsDoc.setCategory("手机");
            goodsDoc.setBrand("华为");
            goodsDoc.setImage("https://www.abc.com");
            goodsDoc.setSold(i * 123);
            goodsDoc.setPrice(i * 666);
            goodsDoc.setCommentCount(i * 100);
            goodsDoc.setIsPromotion(false);
            goodsDoc.setUpdateTime(new Date());
            goodsDocList.add(goodsDoc);
        }

        BulkRequest bulkRequest = new BulkRequest();
        
        bulkRequest.add(new DeleteRequest("goods", goodsDocList.get(0).getId()));
        bulkRequest.add(new DeleteRequest("goods", goodsDocList.get(1).getId()));

        restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);

    }

3.6.4 批量修改文档 

    /**
     * 批量删除文档
     */
    @Test
    public void testBulkDeleteDocument() throws IOException {
        // 1.准备文档数据,这里的数据我就写固定的了,实际开发中要从其他数据库获取
        List<GoodsDoc> goodsDocList = new ArrayList<>();
        for (int i = 1; i < 3; i++) {
            GoodsDoc goodsDoc = new GoodsDoc();
            goodsDoc.setId("00"+i);
            goodsDoc.setName("华为手机");
            goodsDoc.setCategory("手机");
            goodsDoc.setBrand("华为");
            goodsDoc.setImage("https://www.abc.com");
            goodsDoc.setSold(i * 123);
            goodsDoc.setPrice(i * 666);
            goodsDoc.setCommentCount(i * 100);
            goodsDoc.setIsPromotion(false);
            goodsDoc.setUpdateTime(new Date());
            goodsDocList.add(goodsDoc);
        }

        BulkRequest bulkRequest = new BulkRequest();

        bulkRequest.add(new UpdateRequest("goods", goodsDocList.get(0).getId()).doc("price",1000));
        bulkRequest.add(new UpdateRequest("goods", goodsDocList.get(1).getId()).doc("price",2000));

        restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);

    }

3.7 DSL查询

        在之前我们查询文档都是根据id查询,这种查询方式并不能满足业务的场景需求,一般我们的搜索会更复杂,这个时候就需要一种新的查询方式,ElasticSearch就给我们提供了DSL查询来实现这种复杂查询。由于DSL查询内容比较多,将在后续作为一个章节。

3.8 小结

文档操作的基本步骤:

  • 初始化RestHighLevelClient

  • 创建XxxRequest。

    • XXX是IndexGetUpdateDeleteBulk

  • 准备参数(IndexUpdateBulk时需要)

  • 发送请求。

    • 调用RestHighLevelClient#.xxx()方法,xxx是indexgetupdatedeletebulk

  • 解析结果(Get时需要)

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值