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

写在最前

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

源码地址(后端):gitee.com/csps/mingyu...

源码地址(前端):gitee.com/csps/mingyu...

文档地址:gitee.com/csps/mingyu...

搭建 ELK 环境

Docker 安装 ELK 7.17.2

blog.csdn.net/csp73217110...

Docker 安装 ELK 7.17.7

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

yaml 复制代码
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

测试环境

  • Elasticsearch

访问:http://esIP:9200/

见到如下打印即可

json 复制代码
{
    "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"
}

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

引入依赖

xml 复制代码
<dependencies>
    <dependency>
        <groupId>cn.easy-es</groupId>
        <artifactId>easy-es-boot-starter</artifactId>
    </dependency>
</dependencies>

添加 Easy-Es 配置

less 复制代码
@AutoConfiguration
@ConditionalOnProperty(value = "easy-es.enable", havingValue = "true")
@EsMapperScan("com.csp.mingyue.**.esmapper")
public class EasyEsConfiguration {
​
}

自动注入

arduino 复制代码
com.csp.mingyue.common.config.EasyEsConfiguration

搜索服务

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

引入依赖

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

xml 复制代码
<dependencies>
    <!-- SpringCloud Alibaba Nacos -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
​
    <!-- SpringCloud Alibaba Nacos Config -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    </dependency>
​
    <!-- web容器 -->
    <dependency>
        <groupId>com.csp.mingyue</groupId>
        <artifactId>mingyue-common-web</artifactId>
    </dependency>
​
    <!-- 接口文档 -->
    <dependency>
        <groupId>com.csp.mingyue</groupId>
        <artifactId>mingyue-common-doc</artifactId>
    </dependency>
​
    <!-- 认证工具类 -->
    <dependency>
        <groupId>com.csp.mingyue</groupId>
        <artifactId>mingyue-common-security</artifactId>
    </dependency>
​
    <dependency>
        <groupId>com.csp.mingyue</groupId>
        <artifactId>mingyue-search-api</artifactId>
    </dependency>
​
    <!-- ES 搜索依赖 -->
    <dependency>
        <groupId>com.csp.mingyue</groupId>
        <artifactId>mingyue-common-es</artifactId>
    </dependency>
</dependencies>

添加 Document Mapper

csharp 复制代码
public interface DocumentMapper extends BaseEsMapper<Document> {
}

添加 application.yml

yaml 复制代码
# 端口
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

Nacos 配置添加

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

yaml 复制代码
# 搜索服务配置
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

单元测试测试 Easy-Es Api

测试新增

断言通过即可

less 复制代码
@DisplayName("测试新增一条数据")
@Test
public void testTest() {
  // 测试插入数据
  Document document = new Document();
  document.setId("1");
  document.setTitle("登高");
  document.setContent("风急天高猿啸哀,渚清沙白鸟飞回。");
  Assertions.assertTrue(documentMapper.insert(document) > 0);
}

测试查询

断言通过即可

less 复制代码
@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());
}

执行日志如下:

dart 复制代码
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}

测试更新

断言通过即可

less 复制代码
@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);
}

测试删除

断言通过即可

less 复制代码
@DisplayName("测试删除一条数据")
@Test
public void testDeleteById() {
  // 测试删除数据 删除有两种情况:根据id删或根据条件删
  Assertions.assertTrue(documentMapper.deleteById("1") > 0);
}

小结

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

相关推荐
Full Stack Developme4 分钟前
Spring 发展历史
java·后端·spring
ClouGence13 分钟前
TiCDC 够用吗?聊聊 TiDB 同步的几个关键问题
数据库·分布式·后端
音符犹如代码39 分钟前
Docker 一键部署带有 TimescaleDB 插件的 PostgreSQL
java·运维·数据库·后端·docker·postgresql·容器
LucianaiB1 小时前
从模型护栏到工程门禁:基于 XGuard 二创一个 Agent/CI 动态策略安全护栏
后端
铁皮饭盒1 小时前
同样是算力巨头,为什么华为死磕英伟达,AMD 却 "躺平看戏"?
前端·后端
文心快码BaiduComate1 小时前
用Comate 7天完成”鹅鸭杀”游戏网站开发
前端·后端·程序员
倚栏听风雨1 小时前
Spring AI Alibaba 接入 OpenAI 兼容协议第三方大模型实战
后端
夕除1 小时前
spring boot 6
java·spring boot·后端
zhangxingchao1 小时前
AI应用开发二:Embedding与向量数据库
前端·人工智能·后端
倒流时光三十年2 小时前
Java String.split() 方法陷阱:为什么你应该始终使用 split(regex, -1)
后端