SpringCloud 微服务全栈体系(十四)

第十一章 分布式搜索引擎 elasticsearch

四、RestAPI

  • ES 官方提供了各种不同语言的客户端,用来操作 ES。这些客户端的本质就是组装 DSL 语句,通过 http 请求发送给 ES。官方文档地址:https://www.elastic.co/guide/en/elasticsearch/client/index.html

  • 其中的 Java Rest Client 又包括两种:

    • Java Low Level Rest Client
    • Java High Level Rest Client
  • 此处使用的是 Java HighLevel Rest Client 客户端 API

1. 导入 Demo 工程

1.1 导入数据
  • 导入资料提供的数据库数据:
    见专栏 -> 全栈资料包 -> 资源包/02_cloud
  • 数据结构如下:
sql 复制代码
CREATE TABLE `tb_hotel` (
  `id` bigint(20) NOT NULL COMMENT '酒店id',
  `name` varchar(255) NOT NULL COMMENT '酒店名称;例:7天酒店',
  `address` varchar(255) NOT NULL COMMENT '酒店地址;例:航头路',
  `price` int(10) NOT NULL COMMENT '酒店价格;例:329',
  `score` int(2) NOT NULL COMMENT '酒店评分;例:45,就是4.5分',
  `brand` varchar(32) NOT NULL COMMENT '酒店品牌;例:如家',
  `city` varchar(32) NOT NULL COMMENT '所在城市;例:上海',
  `star_name` varchar(16) DEFAULT NULL COMMENT '酒店星级,从低到高分别是:1星到5星,1钻到5钻',
  `business` varchar(255) DEFAULT NULL COMMENT '商圈;例:虹桥',
  `latitude` varchar(32) NOT NULL COMMENT '纬度;例:31.2497',
  `longitude` varchar(32) NOT NULL COMMENT '经度;例:120.3925',
  `pic` varchar(255) DEFAULT NULL COMMENT '酒店图片;例:/img/1.jpg',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
1.2 导入项目
  • 导入资料提供的项目:
    见专栏 -> 全栈资料包 -> 资源包/02_cloud
1.3 mapping 映射分析
  • 创建索引库,最关键的是 mapping 映射,而 mapping 映射要考虑的信息包括:

    • 字段名
    • 字段数据类型
    • 是否参与搜索
    • 是否需要分词
    • 如果分词,分词器是什么?
  • 其中:

    • 字段名、字段数据类型,可以参考数据表结构的名称和类型
    • 是否参与搜索要分析业务来判断,例如图片地址,就无需参与搜索
    • 是否分词呢要看内容,内容如果是一个整体就无需分词,反之则要分词
    • 分词器,我们可以统一使用 ik_max_word
  • 看下酒店数据的索引库结构:

json 复制代码
PUT /hotel
{
  "mappings": {
    "properties": {
      "id": {
        "type": "keyword"
      },
      "name":{
        "type": "text",
        "analyzer": "ik_max_word",
        "copy_to": "all"
      },
      "address":{
        "type": "keyword",
        "index": false
      },
      "price":{
        "type": "integer"
      },
      "score":{
        "type": "integer"
      },
      "brand":{
        "type": "keyword",
        "copy_to": "all"
      },
      "city":{
        "type": "keyword",
        "copy_to": "all"
      },
      "starName":{
        "type": "keyword"
      },
      "business":{
        "type": "keyword"
      },
      "location":{
        "type": "geo_point"
      },
      "pic":{
        "type": "keyword",
        "index": false
      },
      "all":{
        "type": "text",
        "analyzer": "ik_max_word"
      }
    }
  }
}
  • 几个特殊字段说明:

    • location:地理坐标,里面包含精度、纬度
    • all:一个组合字段,其目的是将多字段的值利用 copy_to 合并,提供给用户搜索
  • 地理坐标说明:

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

  • 分为三步:

1)引入 es 的 RestHighLevelClient 依赖:

xml 复制代码
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
</dependency>

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

xml 复制代码
<properties>
    <java.version>1.8</java.version>
    <elasticsearch.version>7.12.1</elasticsearch.version>
</properties>

3)初始化 RestHighLevelClient:

  • 初始化的代码如下:
java 复制代码
RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(
        HttpHost.create("http://192.168.150.101:9200")
));
  • 这里为了单元测试方便,我们创建一个测试类 HotelIndexTest,然后将初始化的代码编写在@BeforeEach 方法中:
java 复制代码
package com.alex.hotel;

import org.apache.http.HttpHost;
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 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 代码解读
  • 创建索引库的 API 如下:
  • 代码分为三步:

    • 创建 Request 对象。因为是创建索引库的操作,因此 Request 是 CreateIndexRequest。
    • 添加请求参数,其实就是 DSL 的 JSON 参数部分。因为 json 字符串很长,这里是定义了静态字符串常量 MAPPING_TEMPLATE,让代码看起来更加优雅。
    • 发送请求,client.indices()方法的返回值是 IndicesClient 类型,封装了所有与索引库操作有关的方法。
2.2 完整示例
  • 在 hotel-demo 的 com.alex.hotel.constants 包下,创建一个类,定义 mapping 映射的 JSON 字符串常量:
java 复制代码
package com.alex.hotel.constants;

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\": false\n" +
            "      },\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\": false\n" +
            "      },\n" +
            "      \"all\":{\n" +
            "        \"type\": \"text\",\n" +
            "        \"analyzer\": \"ik_max_word\"\n" +
            "      }\n" +
            "    }\n" +
            "  }\n" +
            "}";
}
  • 在 hotel-demo 中的 HotelIndexTest 测试类中,编写单元测试,实现创建索引:
java 复制代码
@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);
}

3. 删除索引库

  • 删除索引库的 DSL 语句非常简单:
json 复制代码
DELETE /hotel
  • 与创建索引库相比:

    • 请求方式从 PUT 变为 DELTE
    • 请求路径不变
    • 无请求参数
  • 所以代码的差异,注意体现在 Request 对象上。依然是三步走:

    • 创建 Request 对象。这次是 DeleteIndexRequest 对象
    • 准备参数。这里是无参
    • 发送请求。改用 delete 方法
  • 在 hotel-demo 中的 HotelIndexTest 测试类中,编写单元测试,实现删除索引:

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

4. 判断索引库是否存在

  • 判断索引库是否存在,本质就是查询,对应的 DSL 是:
json 复制代码
GET /hotel
  • 因此与删除的 Java 代码流程是类似的。依然是三步走:

    • 创建 Request 对象。这次是 GetIndexRequest 对象
    • 准备参数。这里是无参
    • 发送请求。改用 exists 方法
java 复制代码
@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 ? "索引库已经存在!" : "索引库不存在!");
}

5. 总结

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

  • 索引库操作的基本步骤:

    • 初始化 RestHighLevelClient
    • 创建 XxxIndexRequest。XXX 是 Create、Get、Delete
    • 准备 DSL( Create 时需要,其它是无参)
    • 发送请求。调用 RestHighLevelClient#indices().xxx()方法,xxx 是 create、exists、delete
相关推荐
Miketutu2 小时前
Spring MVC消息转换器
java·spring
小小虫码4 小时前
项目中用的网关Gateway及SpringCloud
spring·spring cloud·gateway
带刺的坐椅9 小时前
无耳科技 Solon v3.0.7 发布(2025农历新年版)
java·spring·mvc·solon·aop
精通HelloWorld!12 小时前
使用HttpClient和HttpRequest发送HTTP请求
java·spring boot·网络协议·spring·http
LUCIAZZZ13 小时前
基于Docker以KRaft模式快速部署Kafka
java·运维·spring·docker·容器·kafka
拾忆,想起13 小时前
如何选择Spring AOP的动态代理?JDK与CGLIB的适用场景
spring boot·后端·spring·spring cloud·微服务
zhuyasen13 小时前
多维度详细比较 kratos、go-zero、goframe、sponge 框架
后端·http·微服务·rpc·golang
鱼骨不是鱼翅14 小时前
Spring Web MVC基础第一篇
前端·spring·mvc
掘金-我是哪吒15 小时前
分布式微服务系统架构第90集:现代化金融核心系统
分布式·微服务·金融·架构·系统架构
hong_zc16 小时前
Spring MVC (三) —— 实战演练
java·spring·mvc