• 027-从零搭建微服务-搜索服务(一)


    写在最前

    如果这个项目让你有所收获,记得 Star 关注哦,这对我是非常不错的鼓励与支持。

    源码地址(后端):https://gitee.com/csps/mingyue-springcloud-learning

    源码地址(前端):https://gitee.com/csps/mingyue-springcloud-ui

    文档地址:https://gitee.com/csps/mingyue-springcloud-learning/wikis

    搭建 ELK 环境

    Docker 安装 ELK 7.17.2

    https://blog.csdn.net/csp732171109/article/details/124413138

    Docker 安装 ELK 7.17.7

    参考 mingyue/docker/elk 目录结构,以及 mingyue/docker/docker-compose.yml 部署 ELK

    version: '3.8'
    services:
    	 mingyue-elasticsearch:
        image: elasticsearch:7.17.7
        container_name: mingyue-elasticsearch
        ports:
          - "9200:9200"
          - "9300:9300"
        environment:
          # 设置集群名称
          cluster.name: elasticsearch
          # 以单一节点模式启动
          discovery.type: single-node
          ES_JAVA_OPTS: "-Xms512m -Xmx512m"
        volumes:
          - ./elk/elasticsearch/plugins:/usr/share/elasticsearch/plugins
          - ./elk/elasticsearch/data:/usr/share/elasticsearch/data
          - ./elk/elasticsearch/logs:/usr/share/elasticsearch/logs
    
      mingyue-kibana:
        image: kibana:7.17.7
        container_name: mingyue-kibana
        ports:
          - "5601:5601"
        depends_on:
          # kibana在elasticsearch启动之后再启动
          - mingyue-elasticsearch
        environment:
          #设置系统语言文中文
          I18N_LOCALE: zh-CN
          # 访问域名
          # SERVER_PUBLICBASEURL: https://kibana.cloud.com
        volumes:
          - ./elk/kibana/config/kibana.yml:/usr/share/kibana/config/kibana.yml
        links:
          - mingyue-elasticsearch:es #可以用es这个域名访问elasticsearch服务
    
      mingyue-logstash:
        image: logstash:7.17.7
        container_name: mingyue-logstash
        ports:
          - "4560:4560"
        volumes:
          - ./elk/logstash/pipeline/logstash.conf:/usr/share/logstash/pipeline/logstash.conf
          - ./elk/logstash/config/logstash.yml:/usr/share/logstash/config/logstash.yml
        depends_on:
          - mingyue-elasticsearch
    
    • 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

    测试环境

    • Elasticsearch

    访问:http://esIP:9200/

    见到如下打印即可

    {
        "name": "1cc13d88bfe7",
        "cluster_name": "elasticsearch",
        "cluster_uuid": "1vZhSxDGTA-oJd-IlqZjWQ",
        "version": {
            "number": "7.17.7",
            "build_flavor": "default",
            "build_type": "docker",
            "build_hash": "78dcaaa8cee33438b91eca7f5c7f56a70fec9e80",
            "build_date": "2022-10-17T15:29:54.167373105Z",
            "build_snapshot": false,
            "lucene_version": "8.11.1",
            "minimum_wire_compatibility_version": "6.8.0",
            "minimum_index_compatibility_version": "6.0.0-beta1"
        },
        "tagline": "You Know, for Search"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • Kibana
      • 访问首页可以打开即可:http://esIP:5601/app/home#/

    Easy-Es

    Easy-Es(简称EE)是一款基于 ElasticSearch(简称Es)官方提供的 RestHighLevelClient 打造的 ORM 开发框架,在 RestHighLevelClient 的基础上,只做增强不做改变,为简化开发、提高效率而生,您如果有用过 Mybatis-Plus(简称MP),那么您基本可以零学习成本直接上手EE,EE 是 MP 的 Es 平替版,在有些方面甚至比 MP 更简单,同时也融入了更多 Es 独有的功能,助力您快速实现各种场景的开发。

    框架架构

    优势

    • 全自动索引托管: 全球开源首创的索引托管模式,开发者无需关心索引的创建更新及数据迁移等繁琐步骤,索引全生命周期皆可托管给框架,由框架自动完成,过程零停机,用户无感知,彻底解放开发者
    • 智能字段类型推断: 根据索引类型和当前查询类型上下文综合智能判断当前查询是否需要拼接.keyword 后缀,减少小白误用的可能
    • 屏蔽语言差异: 开发者只需要会 MySQL 语法即可使用 Es,真正做到一通百通,无需学习枯燥易忘的 Es 语法,Es 使用相对 MySQL 较低频,学了长期不用也会忘,没必要浪费这时间.开发就应该专注于业务,省下的时间去撸铁,去陪女朋友陪家人,不做资本家的韭菜
    • 代码量极少: 与直接使用 RestHighLevelClient 相比,相同的查询平均可以节省3-5倍左右的代码量
    • 零魔法值: 字段名称直接从实体中获取,无需输入字段名称字符串这种魔法值,提高代码可读性,杜绝因字段名称修改而代码漏改带来的Bug
    • 零额外学习成本: 开发者只要会国内最受欢迎的 Mybatis-Plus 语法,即可无缝迁移至EE,EE采用和前者相同的语法,消除使用者额外学习成本,直接上手,爽
    • 降低开发者门槛: Es 通常需要中高级开发者才能驾驭,但通过接入 EE,即便是只了解 ES 基础的初学者也可以轻松驾驭 ES 完成绝大多数需求的开发,可以提高人员利用率,降低企业成本

    特性

    • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
    • 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
    • 强大的 CRUD 操作:内置通用 Mapper,仅仅通过少量配置即可实现大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
    • 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错段
    • 支持主键自动生成:支持2 种主键策略,可自由配置,完美解决主键问题
    • 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
    • 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
    • 内置分页插件:基于RestHighLevelClient 物理分页,开发者无需关心具体操作,且无需额外配置插件,写分页等同于普通 List 查询,且保持和PageHelper插件同样的分页返回字段,无需担心命名影响
    • MySQL功能全覆盖:MySQL中支持的功能通过EE都可以轻松实现
    • 支持ES高阶语法:支持高亮搜索,分词查询,权重查询,Geo地理位置查询,IP查询,聚合查询等高阶语法
    • 良好的拓展性:底层仍使用RestHighLevelClient,可保持其拓展性,开发者在使用EE的同时,仍可使用RestHighLevelClient的功能

    集成 Easy-Es

    新建模块 mingyue-common-es

    引入依赖

    <dependencies>
        <dependency>
            <groupId>cn.easy-esgroupId>
            <artifactId>easy-es-boot-starterartifactId>
        dependency>
    dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    添加 Easy-Es 配置

    @AutoConfiguration
    @ConditionalOnProperty(value = "easy-es.enable", havingValue = "true")
    @EsMapperScan("com.csp.mingyue.**.esmapper")
    public class EasyEsConfiguration {
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    自动注入

    com.csp.mingyue.common.config.EasyEsConfiguration
    
    • 1

    搜索服务

    新建模块 mingyue-searchmingyue-search-apimingyue-search-biz

    引入依赖

    mingyue-search-biz 引入 mingyue-common-es 模块

    <dependencies>
        
        <dependency>
            <groupId>com.alibaba.cloudgroupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
        dependency>
    
        
        <dependency>
            <groupId>com.alibaba.cloudgroupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-configartifactId>
        dependency>
    
        
        <dependency>
            <groupId>com.csp.mingyuegroupId>
            <artifactId>mingyue-common-webartifactId>
        dependency>
    
        
        <dependency>
            <groupId>com.csp.mingyuegroupId>
            <artifactId>mingyue-common-docartifactId>
        dependency>
    
        
        <dependency>
            <groupId>com.csp.mingyuegroupId>
            <artifactId>mingyue-common-securityartifactId>
        dependency>
    
        <dependency>
            <groupId>com.csp.mingyuegroupId>
            <artifactId>mingyue-search-apiartifactId>
        dependency>
    
        
        <dependency>
            <groupId>com.csp.mingyuegroupId>
            <artifactId>mingyue-common-esartifactId>
        dependency>
    dependencies>
    
    • 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

    添加 Document Mapper

    public interface DocumentMapper extends BaseEsMapper<Document> {
    }
    
    • 1
    • 2

    添加 application.yml

    # 端口
    server:
        port: 7400
    
    spring:
        application:
            name: @artifactId@
        profiles:
            # 环境配置
            active: @profiles.active@
        cloud:
            nacos:
                # nacos 服务地址
                server-addr: @nacos.server@
                username: @nacos.username@
                password: @nacos.password@
                discovery:
                    # 注册组
                    group: @nacos.discovery.group@
                    namespace: ${spring.profiles.active}
                config:
                    # 配置组
                    group: @nacos.config.group@
                    namespace: ${spring.profiles.active}
        config:
            import:
                - optional:nacos:application-common.yml
                - optional:nacos:${spring.application.name}.yml
    
    • 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

    Nacos 配置添加

    新建 mingyue-search-biz.yml nacos 配置

    # 搜索服务配置
    easy-es:
      # 是否开启EE自动配置
      enable: true
      # es连接地址+端口 格式必须为ip:port,如果是集群则可用逗号隔开
      address : mingyue-es:9200
      # 默认为http
      schema: http
      # 注意ES建议使用账号认证 不使用会报警告日志
      # 如果无账号密码则不配置此行
      #username:
      # 如果无账号密码则不配置此行
      #password:
      # 心跳策略时间 单位:ms
      keep-alive-millis: 18000
      # 连接超时时间 单位:ms
      connectTimeout: 5000
      # 通信超时时间 单位:ms
      socketTimeout: 5000
      # 请求超时时间 单位:ms
      requestTimeout: 5000
      # 连接请求超时时间 单位:ms
      connectionRequestTimeout: 5000
      # 最大连接数 单位:个
      maxConnTotal: 100
      # 最大连接路由数 单位:个
      maxConnPerRoute: 100
      global-config:
        # 开启控制台打印通过本框架生成的DSL语句,默认为开启,生产环境建议关闭,以提升少量性能
        print-dsl: true
        # 异步处理索引是否阻塞主线程 默认阻塞 数据量过大时调整为非阻塞异步进行 项目启动更快
        asyncProcessIndexBlocking: true
        db-config:
          # 是否开启下划线转驼峰 默认为false
          map-underscore-to-camel-case: true
          # id生成策略 customize为自定义,id值由用户生成,比如取MySQL中的数据id,如缺省此项配置,则id默认策略为es自动生成
          id-type: customize
          # 字段更新策略 默认为not_null
          field-strategy: not_null
          # 默认开启,查询若指定了size超过1w条时也会自动开启,开启后查询所有匹配数据,若不开启,会导致无法获取数据总条数,其它功能不受影响.
          enable-track-total-hits: true
          # 数据刷新策略,默认为不刷新
          refresh-policy: immediate
          # 是否全局开启must查询类型转换为filter查询类型 默认为false不转换
          enable-must2-filter: false
    
    • 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

    单元测试测试 Easy-Es Api

    测试新增

    断言通过即可

    @DisplayName("测试新增一条数据")
    @Test
    public void testTest() {
      // 测试插入数据
      Document document = new Document();
      document.setId("1");
      document.setTitle("登高");
      document.setContent("风急天高猿啸哀,渚清沙白鸟飞回。");
      Assertions.assertTrue(documentMapper.insert(document) > 0);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    测试查询

    断言通过即可

    @DisplayName("测试查询一条数据")
    @Test
    public void testSelect() {
      // 测试查询 写法和MP一样 可以用链式,也可以非链式 根据使用习惯灵活选择即可
      String title = "登高";
      LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
      wrapper.like(Document::getTitle, title);
    
      Document document = documentMapper.selectOne(wrapper);
      Assertions.assertEquals(title, document.getTitle());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    执行日志如下:

    2023-09-19 15:22:10.708  INFO 43316 --- [           main] easy-es                                  : ===> Execute By Easy-Es: 
    index-name: document
    DSL:{"size":10000,"query":{"bool":{"must":[{"wildcard":{"title":{"wildcard":"*登高*","boost":1.0}}}],"adjust_pure_negative":true,"boost":1.0}},"track_total_hits":2147483647}
    
    • 1
    • 2
    • 3

    测试更新

    断言通过即可

    @DisplayName("测试更新一条数据")
    @Test
    public void testUpdateById() {
      // 测试更新 更新有两种情况 1.已知id, 根据id更新;2.id未知, 根据条件更新
      Document document = new Document();
      document.setId("1");
      document.setContent("风急天高猿啸哀,渚清沙白鸟飞回。无边落木萧萧下,不尽长江滚滚来。");
    
      Assertions.assertTrue(documentMapper.updateById(document) > 0);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    测试删除

    断言通过即可

    @DisplayName("测试删除一条数据")
    @Test
    public void testDeleteById() {
      // 测试删除数据 删除有两种情况:根据id删或根据条件删
      Assertions.assertTrue(documentMapper.deleteById("1") > 0);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    小结

    现在通过单元测试打通了代码与 Elasticsearch 服务,完成了增删改查。接下来通过接口的方式来支持代码对 Elasticsearch 服务的增删改查,完善服务。

  • 相关阅读:
    JavaScript基础
    C++:扫描线算法​(附完整源码)
    4.java的IO流技术(2/2)
    钓鱼邮件的防范
    《MLB棒球创造营》:走近棒球运动·德州游骑兵队
    工程化(产研流程规范)
    Spring中的多线程魔法:探索@Async注解的妙用
    卷积神经网络CNN中的卷积操作详解
    Android开发超详细介绍
    Doris学习--1、Doris简介、操作Doris、Doris架构(数据模型)
  • 原文地址:https://blog.csdn.net/csp732171109/article/details/133043403