• Spring Boost + Elasticsearch 实现检索查询


    需求:对“昵称”进行“全文检索查询”,对“账号”进行“精确查询”。

    认识 Elasticsearch 

    1. ES 的倒排索引

    1. 正向索引
      1. 对 id 进行检索速度很快。
      2. 对其他字段即使加了索引,只能满足精确查询。
      3. 模糊查询时,逐条数据扫描,判断是否符合条件。速度很慢。
    2. 倒排索引
      1. 词条(Term)+包含词条的所有文档(Document)的id,这种存储形式。

    2. ES 与 mysql 的区别

    3. ES 的数据结构与表结构

    注:id不为long型,而是keyword。即,不参与分词。

    4. ES 分词器的种类:

    1. standard
      1. 中文是逐字分词
    2. ik_smart
      1. 粗粒度。
      2. “程序员” = “程序员”
    3. ik_max_word
      1. 细粒度。
      2. “程序员” = “程序员”、“程序”、“员”

    5. ES 增删改查:

    1. 指定索引库,对这个索引库进行
      1. 增:PUT
      2. 删:DELETE
      3. 改:PUT,只能新增字段,不能修改旧字段
      4. 查:GET
    2. 指定 id,对这个 id 的文档进行:
      1. 增:POST
      2. 删:DELETE
      3. 改:PUT:替换旧文档,可以实现增+改;POST:指定修改某些字段
      4. 查:GET

    6. ES 查询方式:

    1. 全文检索查询
      1. 数据结构:text
      2. 利用分词器对用户输入的内容进行分词,并在倒排查询库中匹配。
      3. match_query:支持一个字段
      4. multi_match_query:支持多个字段,性能不如 match_query。
    2. 精确查询
      1. 数据结构:keyword、数值、日期、boolean
      2. term:精确查询,即等于。
      3. range:只适用于数值、日期。
    3. 其他:地理查询、符合查询等。

    配置 Elasticsearch 

    1. 下载 Elasticsearch
      1. Windows10环境下安装Es7_windows安装es7-CSDN博客
      2. 7.x 和 8.x 差距比较大(8.x 版本默认有ssl 认证、用户密码登录,且在 Spring 中的操作差别有点大)。采用版本是7.12.1
      3. 有高、低版本。采用高版本。
      4. 已经不支持 java 访问 ES,而是 java request 请求的方式访问 ES。
    2. 在Spring boot 配置 ES
      1. 在 xml 中引入依赖。且需要在 properties 强制指定 ES 版本为 7.12.1。
    3. 在Spring boot 配置 FastJson
      1. 在 xml 中引入依赖。且需要指定版本为 1.2.68。1.1.x 不支持 LocalDateTime。
    4. 在Spring boot 配置 RabbitMQ
      1. 在 xml 中引入依赖。
      2. 在 yml 中配置 RabbitMQ。

    实现 Elasticsearch 

    1. 增删改:数据同步

    1. 如果是单体式项目:对数据库进行增删改查时,对ES也进行增删改查
    2. 如果是微服务项目:
      1. 同步调用:
        1. 服务层先操作数据库,再调用更新ES的接口。
        2. 该接口去更新ES。
        3. ES更新完成后,结果返回给接口。
        4. 接口返回给服务层。
        5. 缺点:业务耦合、耗时增加、性能下降。
      2. 异步通知
        1. 服务层操作数据库,再发布消息。
        2. ES监听并更新数据。
        3. 优点:低耦合。缺点:依赖于MQ的可靠性。
      3. 监听binlog:
        1. 服务层操作数据库。
        2. 数据库把操作记录到binlog。
        3. canal这个中间件去监听binlog,通知ES。
        4. ES更新数据。
        5. 优点:完全解除耦合度。缺点:依赖于中间件canal和mysql。mysql压力增大。

    异步通知的操作:

    1. 发送MQ:
      1. 采用topic交换机。
      2. 当进行新增和修改时,发送 id 给交换机,声明“新增”的路由键(routing key)。
      3. 当进行删除时,发送 id 给交换机,并声明“删除”的路由键(routing key)。
        1. 注:不发送整个数据,而是数据的 id,以减少信息传输的数据量。
    2. 监听MQ:
      1. 监听“新增”队列的监听器:对 ES 发送新增请求。
      2. 监听“删除”队列的监听器:对 ES 发送删除请求。

    单体式项目:

    示例,增的同步代码,在 Controller 层:

    1. // 增
    2. @PostMapping()
    3. public User save(@RequestBody User user) throws IOException {
    4. // 保存到mysql
    5. userService.save(user);
    6. // 保存到mysql后,id已经有了,可以直接插入到ES
    7. esService.AddDocument(user);
    8. return user;
    9. }

     注:前端发来的数据 user 无 id,通过Mybatis Plus 插入到 mysql 数据库后 user 有 id,可以直接插入到 ES(不需要从 mysql 数据库查询得到 user 数据,再插入 ES)。

    2. 查询 + 分页

    示例,对“昵称”进行全文检索查询:

    1. 创建一个配置类,注入一个 bean 方法,把向 ES 发送请求的 client 注入 IOC。

    1. @Configuration
    2. public class EsConfig {
    3. @Bean
    4. public RestHighLevelClient clien(){
    5. return new RestHighLevelClient(RestClient.builder(
    6. HttpHost.create("http://localhost:9200")
    7. ));
    8. }
    9. }

    2. POJO 中封装三个类:

    收到前端的类 EsPageParams

    1. @Data
    2. public class EsPageParams {
    3. private String key;
    4. private Integer page;
    5. private Integer size;
    6. }

    发给前端的类 EsPageResult 

    1. @Data
    2. @NoArgsConstructor
    3. @AllArgsConstructor
    4. public class EsPageResult {
    5. private Long total;
    6. private List users;
    7. }

    数据库的类 User 

    1. @Data
    2. @NoArgsConstructor
    3. @AllArgsConstructor
    4. public class User {
    5. @TableId(type = IdType.AUTO)
    6. private Long id; //ID
    7. private String username; //用户名
    8. private String password; //密码
    9. private String niCheng; //姓名
    10. private Integer gender;
    11. private String location;
    12. private String txImageName;
    13. @TableField(fill = FieldFill.INSERT)
    14. private LocalDateTime createTime;
    15. @TableField(fill = FieldFill.INSERT_UPDATE)
    16. private LocalDateTime updateTime;
    17. }

    (如果 ES 和 mysql 数据库不一致,还需要一个 ES 类) 

    3. Controller 层:接受请求,发送给 Service 层。

    4. Service 层:对 user 索引表的 niCheng 字段进行检索,检索方式是倒排索引。最终结果返回给 Controller 层。

    1. @Service
    2. public class EsService {
    3. @Autowired
    4. private RestHighLevelClient client;
    5. @Autowired
    6. private UserService userService;
    7. public EsPageResult search(EsPageParams esPageParams) throws IOException {
    8. // 1.准备request
    9. SearchRequest request = new SearchRequest("user");
    10. // 2. 准备DSL
    11. String key = esPageParams.getKey();
    12. request.source().query(QueryBuilders.matchQuery("niCheng",key));
    13. int page = esPageParams.getPage();
    14. int size = esPageParams.getSize();
    15. request.source().from((page - 1) * size).size(size);
    16. // 3. 发送请求
    17. SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    18. // 4.解析响应
    19. return handleResponse(response);
    20. }
    21. private EsPageResult handleResponse(SearchResponse response){
    22. SearchHits searchHits = response.getHits();
    23. long total = searchHits.getTotalHits().value;
    24. System.out.println("共搜索到"+total+"条数据");
    25. SearchHit[] hits = searchHits.getHits();
    26. List users = new ArrayList<>();
    27. for(SearchHit hit : hits){
    28. String json = hit.getSourceAsString();
    29. User user = JSON.parseObject(json, User.class);
    30. users.add(user);
    31. }
    32. return new EsPageResult(total, users);
    33. }

  • 相关阅读:
    Java程序员找工作需要掌握哪些技能
    [linux] SFTP文件传输基本命令 --- xshell 直接上传文件
    生成器和表达式
    github多个账号配置ssh
    JavaSE入门---认识Java数组
    Vue状态管理--Pinia使用详解
    SQL注入漏洞 | 数字型
    JUC05-AQS、ReentrantLock原理
    conductor 3.7以上 jedisCommands ArrayIndexOutOfBoundsException 解决分析
    字符串划分
  • 原文地址:https://blog.csdn.net/weixin_47173826/article/details/138168911