【Elasticsearch】学习笔记-p3(RestClient操作文档)

视频指路?
B站黑马微服务超级推荐!!

RestClient操作文档

1.初始化RestClient

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

分为三步:

(1)引入es的RestHighLevelClient依赖:

<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
</dependency>

(2)因为SpringBoot默认的ES版本是7.6.2,所以我们需要覆盖默认的ES版本:

<properties>
    <java.version>1.8</java.version>
    <elasticsearch.version>7.12.1</elasticsearch.version>
</properties>

(3)初始化RestHighLevelClient

RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(
    //填自己的服务器ip地址
    HttpHost.create("http://192.168.150.101:9200")
));

这里为了单元测试方便,我们创建一个测试类HotelIndexTest,然后将初始化的代码编写在@BeforeEach方法中:

public class HotelIndexTest {
    private RestHighLevelClient client;

    //初始化
    @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();
    }
}

2.索引库操作

2.1 创建索引库

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jeCM4g79-1637227465025)(file://C:Users30287DesktopJava%E5%AD%A6%E4%B9%A0%E8%A7%86%E9%A2%91day05-Elasticsearch01%E8%AE%B2%E4%B9%89assetsimage-20210720223049408.png?lastModify=1637161343)]

代码分为三步:

  1. 创建Request对象。因为是创建索引库的操作,因此Request是CreateIndexRequest
  2. 添加请求参数,其实就是DSL的JSON参数部分。因为json字符串很长,这里是定义了静态字符串常量MAPPING_TEMPLATE,让代码看起来更加优雅。
  3. 发送请求,client.indices()方法的返回值是IndicesClient类型,封装了所有与索引库操作有关的方法。

hotel-demo的cn.itcast.hotel.constants包下,创建一个类,定义mapping映射的JSON字符串常量:

public class HotelConstants {
    public 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" +
            "        "copy_to": "all"n" +
            "      },n" +
            "      "address":{n" +
            "        "type": "keyword",n" +
            "        "index": falsen" +
            "      },n" +
            "      "price":{n" +
            "        "type": "integer"n" +
            "      },n" +
            "      "score":{n" +
            "        "type": "integer"n" +
            "      },n" +
            "      "brand":{n" +
            "        "type": "keyword",n" +
            "        "copy_to": "all"n" +
            "      },n" +
            "      "city":{n" +
            "        "type": "keyword",n" +
            "        "copy_to": "all"n" +
            "      },n" +
            "      "starName":{n" +
            "        "type": "keyword"n" +
            "      },n" +
            "      "business":{n" +
            "        "type": "keyword"n" +
            "      },n" +
            "      "location":{n" +
            "        "type": "geo_point"n" +
            "      },n" +
            "      "pic":{n" +
            "        "type": "keyword",n" +
            "        "index": falsen" +
            "      },n" +
            "      "all":{n" +
            "        "type": "text",n" +
            "        "analyzer": "ik_max_word"n" +
            "      }n" +
            "    }n" +
            "  }n" +
            "}";
}

hotel-demo中的HotelIndexTest测试类中,编写单元测试,实现创建索引:

@Test
void createHotelIndex() throws IOException {
    // 1.创建Request对象
    CreateIndexRequest request = new CreateIndexRequest("hotel");
    // 2.准备请求的参数:DSL语句
    request.source(MAPPING_TEMPLATE, XContentType.JSON);
    // 3.发送请求
    client.indices().create(request, RequestOptions.DEFAULT);
}

2.2 删除索引库

删除索引库的DSL语句:

DELETE /hotel

代码分三步:

  1. 创建Request对象。这次是DeleteIndexRequest对象
  2. 准备参数。这里是无参
  3. 发送请求。改用delete方法
@Test
void testDeleteHotelIndex() throws IOException {
    // 1.创建Request对象
    DeleteIndexRequest request = new DeleteIndexRequest("hotel");
    // 2.发送请求
    client.indices().delete(request, RequestOptions.DEFAULT);
}

2.3 判断索引库是否存在

判断索引库是否存在,本质就是查询,对应的DSL是:

GET /hotel

代码分三步:

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

2.4 总结

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

索引库操作的基本步骤:

  1. 初始化RestHighLevelClient
  2. 创建XxxIndexRequest。XXX是Create、Get、Delete
  3. 准备DSL( Create时需要,其它是无参)
  4. 发送请求。调用RestHighLevelClient#indices().xxx()方法,xxx是create、exists、delete

3.文档操作

在创建一个测试类HotelDocumentTest

  • 初始化RestHighLevelClient
  • 我们的酒店数据在数据库,需要利用IHotelService去查询,所以注入这个接口
@SpringBootTest
public class HotelDocumentTest {
    @Autowired
    private IHotelService hotelService;

    private RestHighLevelClient client;

    @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();
    }
}

3.1 新增文档

目的:我们要将数据库的酒店数据查询出来,写入elasticsearch中。

数据库查询后的结果是一个Hotel类型的对象。结构如下:

@Data
@TableName("tb_hotel")
public class Hotel {
    @TableId(type = IdType.INPUT)
    private Long id;
    private String name;
    private String address;
    private Integer price;
    private Integer score;
    private String brand;
    private String city;
    private String starName;
    private String business;
    private String longitude;
    private String latitude;
    private String pic;
}

因为数据库与我们的索引库结构存在差异:longitudelatitude需要合并为location

因此,我们需要定义一个新的类型HotelDoc,与索引库结构吻合:

@Data
@NoArgsConstructor
public class HotelDoc {
    private Long id;
    private String name;
    private String address;
    private Integer price;
    private Integer score;
    private String brand;
    private String city;
    private String starName;
    private String business;
    private String location;
    private String pic;

    public HotelDoc(Hotel hotel) {
        this.id = hotel.getId();
        this.name = hotel.getName();
        this.address = hotel.getAddress();
        this.price = hotel.getPrice();
        this.score = hotel.getScore();
        this.brand = hotel.getBrand();
        this.city = hotel.getCity();
        this.starName = hotel.getStarName();
        this.business = hotel.getBusiness();
        this.location = hotel.getLatitude() + ", " + hotel.getLongitude();
        this.pic = hotel.getPic();
    }
}

新增文档的DSL语句如下:

POST /{索引库名}/_doc/1
{
    "name": "Jack",
    "age": 21
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VIML31Am-1637227465031)(file://C:Users30287DesktopJava%E5%AD%A6%E4%B9%A0%E8%A7%86%E9%A2%91day05-Elasticsearch01%E8%AE%B2%E4%B9%89assetsimage-20210720230027240.png?lastModify=1637222260)]

注意:

与创建索引库不同的是,这里直接使用client.xxx()的API,不再需要client.indices()了

我们导入酒店数据,基本流程一致,但是需要考虑几点变化:

  • 酒店数据来自于数据库,我们需要先查询出来,得到hotel对象
  • hotel对象需要转为HotelDoc对象
  • HotelDoc需要序列化为json格式

代码如下:

@Test
void testAddDocument() throws IOException {
    // 1.根据id查询酒店数据
    Hotel hotel = hotelService.getById(61083L);
    // 2.转换为文档类型
    HotelDoc hotelDoc = new HotelDoc(hotel);
    // 3.将HotelDoc转json
    String json = JSON.toJSONString(hotelDoc);

    // 1.创建IndexRequest,指定索引库名和id
    IndexRequest request = new IndexRequest("hotel").id(hotelDoc.getId().toString());
    // 2.准备请求参数,也就是JSON文档
    request.source(json, XContentType.JSON);
    // 3.发送请求
    client.index(request, RequestOptions.DEFAULT);
}

3.2 查询文档

查询文档的DSL语句如下:

GET /hotel/_doc/{id}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ut2xX5hl-1637227465035)(file://C:Users30287DesktopJava%E5%AD%A6%E4%B9%A0%E8%A7%86%E9%A2%91day05-Elasticsearch01%E8%AE%B2%E4%B9%89assetsimage-20210720230811674.png?lastModify=1637222783)]

注意:

查询的目的是得到结果,解析为HotelDoc,因此难点是结果的解析

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

代码如下:

@Test
void testGetDocumentById() throws IOException {
    // 1.准备Request。这次是查询,所以是GetRequest,要指定索引库名和id
    GetRequest request = new GetRequest("hotel", "61082");
    // 2.发送请求,得到响应。因为是查询,这里调用client.get()方法
    GetResponse response = client.get(request, RequestOptions.DEFAULT);
    // 3.解析响应结果。就是对JSON做反序列化
    String json = response.getSourceAsString();
    HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
   	//4.输出测试结果
    System.out.println(hotelDoc);
}

3.3 删除文档

删除文档的DSL语句如下:

DELETE /hotel/_doc/{id}

代码如下:

@Test
void testDeleteDocument() throws IOException {
    // 1.准备Request。次是DeleteRequest对象。要指定索引库名和id
    DeleteRequest request = new DeleteRequest("hotel", "61083");
    // 2.发送请求。因为是删除,所以是client.delete()方法
    client.delete(request, RequestOptions.DEFAULT);
}

3.4 修改文档

修改有两种方式:

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

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

  • 如果新增时,ID已经存在,则修改
  • 如果新增时,ID不存在,则新增

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LMATnexR-1637227465038)(file://C:Users30287DesktopJava%E5%AD%A6%E4%B9%A0%E8%A7%86%E9%A2%91day05-Elasticsearch01%E8%AE%B2%E4%B9%89assetsimage-20210720231040875.png?lastModify=1637223877)]

代码如下:

@Test
void testUpdateDocument() throws IOException {
    // 1.准备Request。这次是修改,所以是UpdateRequest。要指定索引库名和id
    UpdateRequest request = new UpdateRequest("hotel", "61083");
    // 2.准备请求参数。也就是JSON文档,里面包含要修改的字段
    request.doc(
        "price", "952", //两个一对
        "starName", "四钻"
    );
    // 3.发送请求。更新文档。这里调用client.update()方法
    client.update(request, RequestOptions.DEFAULT);
}

3.5 批量导入文档

案例需求:利用BulkRequest批量将数据库数据导入到索引库中。

步骤如下:

  • 利用mybatis-plus查询酒店数据

  • 将查询到的酒店数据(Hotel)转换为文档类型数据(HotelDoc)

  • 利用JavaRestClient中的BulkRequest批处理,实现批量新增文档

批量处理BulkRequest,其本质就是将多个普通的CRUD请求组合在一起发送。

其中提供了一个add方法,用来添加其他请求:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8sCULJyy-1637227465043)(file://C:Users30287DesktopJava%E5%AD%A6%E4%B9%A0%E8%A7%86%E9%A2%91day05-Elasticsearch01%E8%AE%B2%E4%B9%89assetsimage-20210720232105943.png?lastModify=1637225193)]

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

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

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pz6EC1m2-1637227465045)(file://C:Users30287DesktopJava%E5%AD%A6%E4%B9%A0%E8%A7%86%E9%A2%91day05-Elasticsearch01%E8%AE%B2%E4%B9%89assetsimage-20210720232431383.png?lastModify=1637225216)]

代码如下:

@Test
void testBulkRequest() throws IOException {
    // 批量查询酒店数据
    List<Hotel> hotels = hotelService.list();
    // 1.创建Request
    BulkRequest request = new BulkRequest();
    // 2.准备参数,添加多个新增的Request
    for (Hotel hotel : hotels) {
        // 2.1.转换为文档类型HotelDoc
        HotelDoc hotelDoc = new HotelDoc(hotel);
        // 2.2.创建新增文档的Request对象
        request.add(new IndexRequest("hotel")
                    .id(hotelDoc.getId().toString())
                    .source(JSON.toJSONString(hotelDoc), XContentType.JSON));
    }
    // 3.发送请求
    client.bulk(request, RequestOptions.DEFAULT);
}

3.6 总结

文档操作的基本步骤:

  • 初始化RestHighLevelClient
  • 创建XxxRequest。XXX是Index、Get、Update、Delete、Bulk
  • 准备参数(Index、Update、Bulk时需要)
  • 发送请求。调用RestHighLevelClient#.xxx()方法,xxx是index、get、update、delete、bulk
  • 解析结果(Get时需要)

在这里插入图片描述
最后喜欢的小伙伴,记得三连哦!???

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇

)">
下一篇>>