• 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

    在这里插入图片描述

    • 数据结构如下:
    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
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    1.2 导入项目
    • 导入资料提供的项目:
      见专栏 -> 全栈资料包 -> 资源包/02_cloud

    在这里插入图片描述

    1.3 mapping 映射分析
    • 创建索引库,最关键的是 mapping 映射,而 mapping 映射要考虑的信息包括:

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

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

    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"
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 几个特殊字段说明:

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

    在这里插入图片描述

    • copy_to 说明:

    请添加图片描述

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

    • 分为三步:

    1)引入 es 的 RestHighLevelClient 依赖:

    <dependency>
        <groupId>org.elasticsearch.clientgroupId>
        <artifactId>elasticsearch-rest-high-level-clientartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4

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

    <properties>
        <java.version>1.8java.version>
        <elasticsearch.version>7.12.1elasticsearch.version>
    properties>
    
    • 1
    • 2
    • 3
    • 4

    3)初始化 RestHighLevelClient:

    • 初始化的代码如下:
    RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(
            HttpHost.create("http://192.168.150.101:9200")
    ));
    
    • 1
    • 2
    • 3
    • 这里为了单元测试方便,我们创建一个测试类 HotelIndexTest,然后将初始化的代码编写在@BeforeEach 方法中:
    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();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    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 字符串常量:
    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" +
                "}";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 在 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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    3. 删除索引库

    • 删除索引库的 DSL 语句非常简单:
    DELETE /hotel
    
    • 1
    • 与创建索引库相比:

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

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

    @Test
    void testDeleteHotelIndex() throws IOException {
        // 1.创建Request对象
        DeleteIndexRequest request = new DeleteIndexRequest("hotel");
        // 2.发送请求
        client.indices().delete(request, RequestOptions.DEFAULT);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    4. 判断索引库是否存在

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

      • 创建 Request 对象。这次是 GetIndexRequest 对象
      • 准备参数。这里是无参
      • 发送请求。改用 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 ? "索引库已经存在!" : "索引库不存在!");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    5. 总结

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

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

      • 初始化 RestHighLevelClient
      • 创建 XxxIndexRequest。XXX 是 Create、Get、Delete
      • 准备 DSL( Create 时需要,其它是无参)
      • 发送请求。调用 RestHighLevelClient#indices().xxx()方法,xxx 是 create、exists、delete
  • 相关阅读:
    圣普伦数字项目管理大师课:3重核心技能,2个月学会,这波很值
    爆款视频怎么做?这里或许有答案
    正则核心知识点
    破解35岁中年危机
    蓝桥杯-粘木棍-DFS
    Vue选项: Methods方法
    文献阅读快速法-ChatPDF
    MD5加密算法
    万界星空科技商业开源MES,技术支持+项目合作
    Python在工业自动化领域的应用详解
  • 原文地址:https://blog.csdn.net/sgsgkxkx/article/details/134280158