初学elasticsearch

ES

文章目录

一、初识elasticsearch

1、什么是elasticsearch,elastic static,Lucene

​ elasticsearch是一个开源的分布式搜索引擎,可以用来实现搜索,日志统计、分析,系统监控等功能

​ elasticsearch结合kibana,logstach,beats也就是elastic static,被广泛应用在日志数据分析,实时监控等领域。

​ elasticsearch是elastic static的核心,底层实现是通过Lucene,负责存储、搜索、分析数据。beats,logstach负责数据抓取。Kibana负责数据可视化。

​ elastic static是以elastic search为核心的技术栈,包括:beats,logstach,kibana,elasticsearch。

​ Lucene是Apache的来源引擎类库,提供了搜索 引擎的核心api。优势:易扩展,高性能(基于倒排序索引)。缺点:只限java语言开发,学习路线陡峭,不支持水平扩展

2、倒排索引

2.1、正向索引和倒排序索引

正向索引:基于文档id创建索引。查询词条时必须先找到文档,再判断文档是否包含词条。mysql会基于id创建一个索引生成一棵B+树,根据id查询数据速度非常快。

缺点:假如搜索的是title字段,因为title比较长所以一般不会给title加索引。即便加了索引,如果不是精确查找而是如下图的搜索,此时索引会失效,数据库会采用逐条扫描的方式 来判断是否包含手机,如果包含就放到结果集中, 否则丢弃。如果数据量庞大, 那么查找的性能就非常低下。

**倒排索引:**先对文档内容进行分词,对词条创建索引。并记录词条所在的文档信息。查询时先根据词条查找到文档id,而后获取文档。

  • 文档(document):每条数据就是一个文档
  • 词条(term):按照语义分成的词语。对文档中的内容进行分词得到的词语就是词条


3、es与mysql的概念对比

3.1、文档

​ elasticsearch面向的是文档的存储,可以是数据库中的一条商品数据,一个订单信息。文档中的数据会被序列化为json格式后存储在elasticsearch中。

  • 文档:一条数据就是一个文档,es中是json格式
  • 字段:json文档中的字段
3.2、索引
  • 索引(index):相同类型的文档的集合
  • 映射(mapping):索引中文档的字段约束信息,类似表的结构约束。比如字段名称,类型。


3.3、es与数据库中的关系
  • Mysql:擅长事务类型操作,可以确保数据的安全和一致性
  • Elasticsearch:擅长海量数据的搜索、分析、计算

二、索引库操作

1、mapping属性

Mapping是索引库中文档的约束,常见的Mapping属性包括:

  • type:字段数据类型,常见的简单类型有:
    • 字符串:text(可分词的文本)、keyword(精确值,例如:品牌、国家、ip地址)
    • 数值:long、integer、short、byte、double、float
    • 布尔:boolean
    • 日期:date
    • 对象:object
  • index:是否创建索引,默认为true
  • analyzer:使用哪种分词器
  • properties:该字段的子字段
json 复制代码
{
  "age": 21,
    "weight": 52.1,
    "isMarried": false,
    "info": "黑马程序员Java讲师",
    "email": "zy@itcast.cn",
    "score": [99.1, 99.5, 98.9],
    "name": {
        "firstName": "云",
        "lastName": "赵"
    }
}
字段名 字段类型 类型说明 是否参与搜索 是否参与分词 分词器
age integer 整数 ------
weight float 浮点数 ------
isMarried boolean 布尔 ------
info text 字符串, 但需要分词 IK
email keyword 字符串, 但是不分词 ------
score float 只看数组中 元素类型 ------
firstName keyword 字符串, 但是不分词 ------
lastName keyword 字符串, 但是不分词 ------

2、创建索引库和映射

基本语法:
  • 请求方式:PUT
  • 请求路径:/索引库名,可以自定义
  • mapping映射
格式:
json 复制代码
PUT /索引库名称
{
  "mappings": {
    "properties": {
      "字段名":{
        "type": "text",
        "analyzer": "ik_smart"
      },
      "字段名2":{
        "type": "keyword",
        "index": "false"
      },
      "字段名3":{
        "properties": {
          "子字段": {
            "type": "keyword"
          }
        }
      },
      // ...略
    }
  }
}
示例:
json 复制代码
# PUT /heima
{
  "mappings": {
    "properties": {
      "info":{
        "type": "text",
        "analyzer": "ik_smart"
      },
      "email":{
        "type": "keyword",
        "index": "false"
      },
      "name":{
        "properties": {
          "firstName": {
            "type": "keyword"
          }
        }
      }
    }
  }
}

3、查找、删除、修改索引

3.1、查询索引库:
基本语法:
  • 请求方式:GET
  • 请求路径:/索引库名
  • 请求参数:无
格式:
Plain 复制代码
GET/索引库名
3.2、修改索引库

​ 倒排索引结构虽然不复杂,但是一旦数据结改变(比如改变哩分词器),就需要重新创建倒排索引。因此索引库一旦创建,无法修改mapping。

​ 虽然无法修改mapping中已有的字段,但是却允许添加新的字段到mapping中,因为不会对倒排索引产生影响。因此修改索引库能做的就是向索引库中添加新字段,或者更新索引库的基础属性。

语法说明:
json 复制代码
PUT /索引库名/_mapping
{
  "properties": {
    "新字段名":{
      "type": "integer"
    }
  }
}
示例:
json 复制代码
PUT /heima/_mapping
{
  "properties": {
    "age":{
      "type": "integer"
    }
  }
}
3.3、删除索引库
语法:
  • 请求方式:DELETE
  • 请求路径:/索引库名
  • 请求参数:无
格式:
Plain 复制代码
DELETE/索引库名

三、文档操作

1、查询、新增、删除文档

1.1、新增文档
语法:
json 复制代码
POST /索引库名/_doc/文档id
{
    "字段1": "值1",
    "字段2": "值2",
    "字段3": {
        "子属性1": "值3",
        "子属性2": "值4"
    },
}
1.2、查询文档
语法:
json 复制代码
GET /{索引库名称}/_doc/{id}
1.3、删除文档
语法:
javascript 复制代码
DELETE /{索引库名}/_doc/id值

2、修改文档

2.1、全量修改

全量修改是覆盖原来的文档,其本质是两步操作:

  • 根据指定的id删除文档
  • 新增一个相同id的文档

**注意**:如果根据id删除时,id不存在,第二步的新增也会执行,也就从修改变成了新增操作了。

语法:
json 复制代码
PUT /{索引库名}/_doc/文档id
{
    "字段1": "值1",
    "字段2": "值2",
    // ... 略
}

示例:

json 复制代码
PUT /heima/_doc/1
{
    "info": "黑马程序员高级Java讲师",
    "email": "zy@itcast.cn",
    "name": {
        "firstName": "云",
        "lastName": "赵"
    }
}

​ 如果id为1的文档已经被删除,那么第一次执行时,得到的反馈是created。如果执行第2次时,得到的反馈则是update。

2.2、局部修改

局部修改是指只修改指定id匹配的文档中的部分字段。

语法:
json 复制代码
POST /{索引库名}/_update/文档id
{
    "doc": {
         "字段名": "新的值",
    }
}
示例:
json 复制代码
POST /heima/_update/1
{
  "doc": {
    "email": "ZhaoYun@itcast.cn"
  }
}

3、批处理

批处理采用POST请求,基本语法如下:

json 复制代码
POST _bulk
{ "index" : { "_index" : "test", "_id" : "1" } }
{ "field1" : "value1" }
{ "delete" : { "_index" : "test", "_id" : "2" } }
{ "create" : { "_index" : "test", "_id" : "3" } }
{ "field1" : "value3" }
{ "update" : {"_id" : "1", "_index" : "test"} }
{ "doc" : {"field2" : "value2"} }

其中:

  • index代表新增操作
    • _index:指定索引库名
    • _id:指定要操作的文档id
    • {"field1":"value1"}:要新增的文档内容
  • delete:代表删除操作
    • _index:指定索引库名
    • _id:指定要操作的文档id
  • update代表更新操作
    • _index:指定索引库名
    • _id:指定要操作的文档id
    • { "doc" : {"field2" : "value2"} }:要更新的文档字段

示例,批量新增:

json 复制代码
POST /_bulk
{"index": {"_index":"heima", "_id": "3"}}
{"info": "黑马程序员C++讲师", "email": "ww@itcast.cn", "name":{"firstName": "五", "lastName":"王"}}
{"index": {"_index":"heima", "_id": "4"}}
{"info": "黑马程序员前端讲师", "email": "zhangsan@itcast.cn", "name":{"firstName": "三", "lastName":"张"}}

批量删除:

json 复制代码
POST /_bulk
{"delete":{"_index":"heima", "_id": "3"}}
{"delete":{"_index":"heima", "_id": "4"}}

四、RestAPI

4.1、初始化RestClient

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

​ 分三步:

  • item-service模块中引入es的RestHighLevel Client依赖:
xml 复制代码
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
</dependency>
  • 覆盖掉SpringBoot默认的ES版本7.17.0
xml 复制代码
  <properties>
      <maven.compiler.source>11</maven.compiler.source>
      <maven.compiler.target>11</maven.compiler.target>
      <elasticsearch.version>7.12.1</elasticsearch.version>
  </properties>
  • 初始化RestHighLevelClient
java 复制代码
RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(
        HttpHost.create("http://192.168.150.101:9200")
));

​ 创建一个测试类IndexTest,然后将初始化的代码编写在@BeforeEach方法中:

java 复制代码
package com.hmall.item.es;

import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.io.IOException;

public class IndexTest {

    private RestHighLevelClient client;

    @BeforeEach
    void setUp() {
        this.client = new RestHighLevelClient(RestClient.builder(
                HttpHost.create("http://192.168.150.101:9200")
        ));
    }

    @Test
    void testConnect() {
        System.out.println(client);
    }

    @AfterEach
    void tearDown() throws IOException {
        this.client.close();
    }
}

4.2、创建索引库

​ 由于要实现对商品搜索,所以我们需要将商品添加到Elasticsearch中,不过需要根据搜索业务的需求来设定索引库结构,而不是一股脑的把MySQL数据写入Elasticsearch.

4.2.1、Mapping映射

搜索页面的效果如图所示:

实现搜索功能需要的字段包括三大部分:

  • 搜索过滤字段
    • 分类
    • 品牌
    • 价格
  • 排序字段:
    • 默认:按照更新时间降序排序
    • 销量
    • 价格
  • 展示字段
    • 商品id:用于点击后跳转
    • 图片地址
    • 是否是广告推广商品
    • 名称
    • 价格
    • 评价数量
    • 销量

​ 对应的商品表结构如下,索引库无关字段已经划掉:

​ 结合数据库表结构,以上字段对应的mapping映射属性如下:

字段名 字段类型 类型说明 是否参与搜索 是否参与分词 分词器
id long 长整数 ------
name text 字符串,参与分词搜索 IK
price integer 以分为单位,所以是整数 ------
stock integer 字符串,但需要分词 ------
image keyword 字符串,但是不分词 ------
category keyword 字符串,但是不分词 ------
brand keyword 字符串,但是不分词 ------
sold integer 销量,整数 ------
commentCount integer 评价,整数 ------
isAD boolean 布尔类型 ------
updateTime Date 更新时间

​ 因此,最终我们的索引库文档结构应该是:

json 复制代码
PUT /items
{
  "mappings": {
    "properties": {
      "id": {
        "type": "keyword"
      },
      "name":{
        "type": "text",
        "analyzer": "ik_max_word"
      },
      "price":{
        "type": "integer"
      },
      "stock":{
        "type": "integer"
      },
      "image":{
        "type": "keyword",
        "index": false
      },
      "category":{
        "type": "keyword"
      },
      "brand":{
        "type": "keyword"
      },
      "sold":{
        "type": "integer"
      },
      "commentCount":{
        "type": "integer",
        "index": false
      },
      "isAD":{
        "type": "boolean"
      },
      "updateTime":{
        "type": "date"
      }
    }
  }
}
4.2.2、创建索引

创建索引库的API如下:

代码分为三步:

  • 创建Request对象

    • 因为是创建索引库的操作,因此Request是CreateIndexRequest。
  • 添加请求参数

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

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

    item-service中的IndexTest测试类中,具体代码如下:

java 复制代码
@Test
void testCreateIndex() throws IOException {
    // 1.创建Request对象
    CreateIndexRequest request = new CreateIndexRequest("items");
    // 2.准备请求参数
    request.source(MAPPING_TEMPLATE, XContentType.JSON);
    // 3.发送请求
    client.indices().create(request, RequestOptions.DEFAULT);
}

static final String MAPPING_TEMPLATE = "{\n" +
            "  \"mappings\": {\n" +
            "    \"properties\": {\n" +
            "      \"id\": {\n" +
            "        \"type\": \"keyword\"\n" +
            "      },\n" +
            "      \"name\":{\n" +
            "        \"type\": \"text\",\n" +
            "        \"analyzer\": \"ik_max_word\"\n" +
            "      },\n" +
            "      \"price\":{\n" +
            "        \"type\": \"integer\"\n" +
            "      },\n" +
            "      \"stock\":{\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" +
            "      },\n" +
            "      \"isAD\":{\n" +
            "        \"type\": \"boolean\"\n" +
            "      },\n" +
            "      \"updateTime\":{\n" +
            "        \"type\": \"date\"\n" +
            "      }\n" +
            "    }\n" +
            "  }\n" +
            "}";

4.3、删除索引库

删除索引库的请求非常简单:

json 复制代码
DELETE/hotel

与创建索引库相比:

  • 请求方式从PUT变为DELETE
  • 请求路径不变
  • 无请求参数

所以代码的差异,集中体现在Request对象上。流程如下:

  • 创建Request对象。这次是DeleteIndexRequest对象
  • 准备参数。这里是无参,因此省略
  • 发送请求。改用delete方法

item-service中的IndexTest测试类中,编写单元测试,实现删除索引:

java 复制代码
@Test
void testDeleteIndex() throws IOException {
    // 1.创建Request对象
    DeleteIndexRequest request = new DeleteIndexRequest("items");
    // 2.发送请求
    client.indices().delete(request, RequestOptions.DEFAULT);
}

4.4、判断索引库是否存在

判断索引库是否存在,本质就是查询,对应的请求语句:

json 复制代码
GET/hotel

因此与删除的Java代码流程是类似的,流程如下:

  • 创建Request对象。这次是GetIndexRequest对象
  • 准备参数。这里是无参,直接省略
  • 发送请求。改用exists方法
java 复制代码
@Test
void testExistsIndex() throws IOException {
    // 1.创建Request对象
    GetIndexRequest request = new GetIndexRequest("items");
    // 2.发送请求
    boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
    // 3.输出
    System.err.println(exists ? "索引库已经存在!" : "索引库不存在!");
}

4.5、总结

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

索引库操作的基本步骤:

  • 初始化RestHighLevelClient
  • 创建xxxIndexRequest。xxx是CreateGetDelete
  • 准备请求参数(Create时需要,其他是无参,可以省略)
  • 发送请求。调用RestHighLevelClient#indices().xxx()方法,xxx是createexistsdelete

五、RestClient操作文档

索引库准备好以后,就可以操作文档了。为了与索引库操作分离,我们再创建一个测试类,做两件事情:

  • 初始化RestHighLevelClient
  • 我们的商品数据在数据库,需要利用IHOtelService去查询,所以注入这个接口
java 复制代码
package com.hmall.item.es;

import com.hmall.item.service.IItemService;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.io.IOException;

@SpringBootTest(properties = "spring.profiles.active=local")
public class DocumentTest {

    private RestHighLevelClient client;
    @Autowired
    private IItemService itemService;

    @BeforeEach
    void setUp() {
        this.client = new RestHighLevelClient(RestClient.builder(
                HttpHost.create("http://192.168.150.101:9200")
        ));
    }
    
    @AfterEach
    void tearDown() throws IOException {
        this.client.close();
    }
}

5.1、新增文档

我们需要将数据库中的商品信息导入elasticsearch中,而不是造假数据。

5.1.1、实体类

索引结构与数据库结构还存在一些差异,因此我们定义一个索引库结构对应的实体。在hm-service模块的com.hmall.item.domain.dto包中定义一个新的DTO:

java 复制代码
package com.hmall.item.domain.po;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.time.LocalDateTime;

@Data
@ApiModel(description = "索引库实体")
public class ItemDoc{

    @ApiModelProperty("商品id")
    private String id;

    @ApiModelProperty("商品名称")
    private String name;

    @ApiModelProperty("价格(分)")
    private Integer price;

    @ApiModelProperty("商品图片")
    private String image;

    @ApiModelProperty("类目名称")
    private String category;

    @ApiModelProperty("品牌名称")
    private String brand;

    @ApiModelProperty("销量")
    private Integer sold;

    @ApiModelProperty("评论数")
    private Integer commentCount;

    @ApiModelProperty("是否是推广广告,true/false")
    private Boolean isAD;

    @ApiModelProperty("更新时间")
    private LocalDateTime updateTime;
}
5.1.2、API语法

新增文档的请求语法如下:

json 复制代码
POST /{索引库名}/_doc/1
{
    "name": "Jack",
    "age": 21
}

对应的JavaAPI如下:

  • 创建Request对象,这里是IndexRequest,因为添加文档就是创建倒排序索引的过程
  • 准备请求参数,本例中就是Json文档
  • 发送请求

变化的地方在于,这里直接使用client.xxx()的API,不再需要client.indices()了。

5.1.3、完整代码

导入商品数据,出了参考API模板"三步走"以外,还要做以下准备工作:

  • 商品数据来自于数据库,我们需要先查询出来,得到Item对象
  • Item对象需要转为ItemDoc
  • ItemDTO需要序列化为json格式

因此,代码整体步骤如下:

  • 根据id查询商品数据Item
  • Item封装为ItemDoc
  • ItemDoc序列化为JSON
  • 创建IndexRequest,指定索引库名和id
  • 准备请求参数,也就是JSON文档
  • 发送请求

item-serviceDocumentTest测试类中,编写单元测试:

java 复制代码
@Test
void testAddDocument() throws IOException {
    // 1.根据id查询商品数据
    Item item = itemService.getById(100002644680L);
    // 2.转换为文档类型
    ItemDoc itemDoc = BeanUtil.copyProperties(item, ItemDoc.class);
    // 3.将ItemDTO转json
    String doc = JSONUtil.toJsonStr(itemDoc);

    // 1.准备Request对象
    IndexRequest request = new IndexRequest("items").id(itemDoc.getId());
    // 2.准备Json文档
    request.source(doc, XContentType.JSON);
    // 3.发送请求
    client.index(request, RequestOptions.DEFAULT);
}

5.2、查询文档

5.2.1、语法说明

查询的请求语句如下:

json 复制代码
GET/{索引库名}/_doc/{id}

步骤如下:

  • 创建Request对象
  • 发送请求

不过查询的目的是得到结果,解析为ItemDTO,还要再加一步对结果的解析。示例代码如下:

响应结果是一个JSON,其中文档放在一个_source属性中,因此解析就是拿到_source,反序列化为Java对象即可。

流程如下:

  • 准备Request对象。这次是查询,所以是GetRequest
  • 发送请求,得到结果。因为是查询,这里调用client.get()方法
  • 解析结果就是对JSON做反序列化
5.2.2、完整代码

在测试类中,编写单元测试:

java 复制代码
@Test
void testGetDocumentById() throws IOException {
    // 1.准备Request对象
    GetRequest request = new GetRequest("items").id("100002644680");
    // 2.发送请求
    GetResponse response = client.get(request, RequestOptions.DEFAULT);
    // 3.获取响应结果中的source
    String json = response.getSourceAsString();
    
    ItemDoc itemDoc = JSONUtil.toBean(json, ItemDoc.class);
    System.out.println("itemDoc= " + ItemDoc);
}

5.3、删除文档

请求语句如下:

json 复制代码
DELETE/hotel/_doc/{id}

与查询相比,仅仅是请求方式从GET变成DELETE,java代码依然是两步走:

  • 准备Request对象,因为是删除,所以通过DeleteRequest对象,指定索引库名和id
  • 发送请求。因为是删除,所以是client.delete()方法

在测试类中,编写单元测试:

java 复制代码
@Test
void testDeleteDocument() throws IOException {
    // 1.准备Request,两个参数,第一个是索引库名,第二个是文档id
    DeleteRequest request = new DeleteRequest("item", "100002644680");
    // 2.发送请求
    client.delete(request, RequestOptions.DEFAULT);
}

5.4、修改文档

  • 全量修改:本质是先根据ID删除,再新增
  • 局部修改:修改文档中的指定字段值

在RestClient的API中,全量修改与新增的API完全一致,判断依据是id:

  • 如果新增时,ID已经存在,则修改
  • 如果新增时,ID不存在,则新增
5.4.1、语法说明:

局部修改的请求语法如下:

json 复制代码
POST /{索引库名}/_update/{id}
{
  "doc": {
    "字段名": "字段值",
    "字段名": "字段值"
  }
}

代码示例图:

步骤如下:

  • 准备Request对象。修改的对象是UpdateRequest
  • 准备参数。也就是JSON文档,里面包含要修改的字段
  • 发送请求。调用client.update()方法
5.4.2、完整代码

在测试类中,编写单元测试:

java 复制代码
@Test
void testUpdateDocument() throws IOException {
    // 1.准备Request,第一个参数时索引库名,第二个参数是id
    UpdateRequest request = new UpdateRequest("items", "100002644680");
    // 2.准备请求参数
    request.doc(
            "price", 58800,
            "commentCount", 1
    );
    // 3.发送请求
    client.update(request, RequestOptions.DEFAULT);
}

5.5、批量导入文档

​ 在之前的案例中,我们都是操作单个文档。而数据库中的商品数据实际会达到数十万条,某些项目中可能达到数百万条。

​ 将这些数据导入索引库,肯定不能逐条导入,而是采用批处理方案。常见的方案有:

  • 利用Logstash批量导入
    • 需要安装Logstash
    • 对数据的再加工能力弱
    • 无需编码,但要学习编写Logstash导入配置
  • 利用JavaAPI批量导入
    • 需要编码,但基于JavaAPI,学习成本低
    • 更加灵活,可以任意对数据做再加工处理后写入索引库
5.5.1、语法说明

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

  • 创建Request,批量使用的是BulkRequest
  • 准备参数
  • 发送请求,调用的方法是client.bulk()

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

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

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

能添加的请求有:

  • IndexRequest,也就是新增
  • UpdateRequest,也就是修改
  • DeleteRequest,也就是删除

因此Bulk中添加了多个IndexRequest,就是批量新增功能。

Java 复制代码
@Test
void testBulk() throws IOException {
    // 1.创建Request
    BulkRequest request = new BulkRequest();
    // 2.准备请求参数
    request.add(new IndexRequest("items").id("1").source("json doc1", XContentType.JSON));
    request.add(new IndexRequest("items").id("2").source("json doc2", XContentType.JSON));
    // 3.发送请求
    client.bulk(request, RequestOptions.DEFAULT);
}
5.5.2、完整代码

​ 当我们要导入商品数据时,由于商品数量达到数十万,因此不可能一次性全部导入。建议采用循环遍历方式,每次导入1000条左右的数据。

​ 在测试类中,编写单元测试:

java 复制代码
@Test
void testLoadItemDocs() throws IOException {
    // 分页查询商品数据
    int pageNo = 1;
    int size = 1000;
    while (true) {
        Page<Item> page = itemService.lambdaQuery().eq(Item::getStatus, 1).page(new Page<Item>(pageNo, size));
        // 非空校验
        List<Item> items = page.getRecords();
        if (CollUtils.isEmpty(items)) {
            return;
        }
        log.info("加载第{}页数据,共{}条", pageNo, items.size());
        // 1.创建Request
        BulkRequest request = new BulkRequest("items");
        // 2.准备参数,添加多个新增的Request
        for (Item item : items) {
            // 2.1.转换为文档类型ItemDTO
            ItemDoc itemDoc = BeanUtil.copyProperties(item, ItemDoc.class);
            // 2.2.创建新增文档的Request对象
            request.add(new IndexRequest()
                            .id(itemDoc.getId())
                            .source(JSONUtil.toJsonStr(itemDoc), XContentType.JSON));
        }
        // 3.发送请求
        client.bulk(request, RequestOptions.DEFAULT);

        // 翻页
        pageNo++;
    }
}

5.6、小结

基本步骤:

  • 初始化RestHighLevelClient
  • 创建xxxRequest
    • xxx是IndexGetUpdateDeleteBulk
  • 准备参数(IndexUpdateBulk时需要)
  • 发送请求
    • 调用RestHighLevelClient#.xxx()方法,xxx是indexgetupdatedeletebulk
  • 解析结果(Get时需要)
相关推荐
知识分享小能手1 天前
React学习教程,从入门到精通, React 属性(Props)语法知识点与案例详解(14)
前端·javascript·vue.js·学习·react.js·vue·react
qq_508823401 天前
金融量化指标--2Alpha 阿尔法
大数据·人工智能
好家伙VCC1 天前
数学建模模型 全网最全 数学建模常见算法汇总 含代码分析讲解
大数据·嵌入式硬件·算法·数学建模
茯苓gao1 天前
STM32G4 速度环开环,电流环闭环 IF模式建模
笔记·stm32·单片机·嵌入式硬件·学习
是誰萆微了承諾1 天前
【golang学习笔记 gin 】1.2 redis 的使用
笔记·学习·golang
DKPT1 天前
Java内存区域与内存溢出
java·开发语言·jvm·笔记·学习
aaaweiaaaaaa1 天前
HTML和CSS学习
前端·css·学习·html
看海天一色听风起雨落1 天前
Python学习之装饰器
开发语言·python·学习
tan180°1 天前
Boost搜索引擎 网络库与前端(4)
linux·网络·c++·搜索引擎
2301_781668611 天前
Elasticsearch 02
大数据·elasticsearch·搜索引擎