项目1在线交流平台-6.Elasticsearch分布式搜索引擎-3.ES结合Kafka应用-开发社区搜索功能

2023-05-16

文章目录

    • 功能需求
    • 一、Service层处理操作ES服务器的数据
    • 二、Controller层处理帖子添加和评论事件请求
      • 1.添加帖子时-触发事件-发布消息
      • 2. 添加评论时-触发发帖事件-发布消息
    • 三、kafka消费者订阅消息并提交到ES服务器
    • 四、处理搜索结果
      • 1. Controller处理搜索请求
      • 2. 处理模板页面
        • 主页头部的搜索栏链接
        • 搜索网页设置
      • 测试结果:

参考牛客网高级项目教程
狂神说Elasticsearch教程笔记
尚硅谷Elasticsearch教程笔记

功能需求

  • 1.在业务层处理好搜索帖子的服务
    • 包括保存帖子到ES服务器
    • 从服务器中删除帖子
    • 从服务器中查询帖子
  • 2.发布事件
    • 在controller层,结合kafka,发布帖子、增加评论时,数据放入消息队列
    • 异步消费消息,将数据同步到ES服务器
  • 3.处理模板页面的显示,搜索帖子时,根据关键字显示出满足条件的帖子列表
在这里插入图片描述

一、Service层处理操作ES服务器的数据

  • 向服务器添加一条帖子
  • 删除一条帖子
  • 根据关键字查询帖子列表
  • 注意,keyword本身为字符串,不能再加”“号
@Service
public class ElasticSearchService {
    @Autowired
    DiscussPostMapper discussPostMapper;
    @Autowired
    DiscussPostRepository repository;
    @Autowired
    ElasticsearchTemplate elasticTemplate;

    /**
     * 向服务器添加一条帖子
     */
    public void savePost(DiscussPost discussPost) {
        repository.save(discussPost);
    }

    /**
     * 删除一条帖子
     */
    public void deletePost(DiscussPost discussPost) {
        repository.delete(discussPost);
    }

    /**
     * 根据关键字查询帖子列表
     */
    public Page<DiscussPost> searchPosts(String keyword, int current, int limit) {
        // 1.构建查询条件
        SearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.multiMatchQuery(keyword, "title", "content")) // 注意符号
                .withSort(SortBuilders.fieldSort("type").order(SortOrder.DESC))
                .withSort(SortBuilders.fieldSort("score").order(SortOrder.DESC))
                .withSort(SortBuilders.fieldSort("createTime").order(SortOrder.DESC))
                .withPageable(PageRequest.of(current, limit))
                .withHighlightFields(
                        new HighlightBuilder.Field("title").preTags("<em>").postTags("</em>"),
                        new HighlightBuilder.Field("content").preTags("<em>").postTags("</em>")
                ).build();
        // 2.处理查询的结果-拼接高亮显示的部分
        return elasticTemplate.queryForPage(searchQuery, DiscussPost.class, new SearchResultMapper() {
            @Override
            public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> aClass, Pageable pageable) {
                SearchHits hits = response.getHits();
                if (hits.getTotalHits() <= 0) {
                    return null;
                }

                List<DiscussPost> list = new ArrayList<>();
                for (SearchHit hit : hits) {
                    DiscussPost post = new DiscussPost();

                    String id = hit.getSourceAsMap().get("id").toString();
                    post.setId(Integer.valueOf(id));

                    String userId = hit.getSourceAsMap().get("userId").toString();
                    post.setUserId(Integer.valueOf(userId));

                    String title = hit.getSourceAsMap().get("title").toString();
                    post.setTitle(title);

                    String content = hit.getSourceAsMap().get("content").toString();
                    post.setContent(content);

                    String status = hit.getSourceAsMap().get("status").toString();
                    post.setStatus(Integer.valueOf(status));

                    String createTime = hit.getSourceAsMap().get("createTime").toString();
                    post.setCreateTime(new Date(Long.valueOf(createTime)));

                    String commentCount = hit.getSourceAsMap().get("commentCount").toString();
                    post.setCommentCount(Integer.valueOf(commentCount));

                    // 处理高亮显示的结果
                    HighlightField titleField = hit.getHighlightFields().get("title");
                    if (titleField != null) {
                        post.setTitle(titleField.getFragments()[0].toString());
                    }

                    HighlightField contentField = hit.getHighlightFields().get("content");
                    if (contentField != null) {
                        post.setContent(contentField.getFragments()[0].toString());
                    }

                    list.add(post);
                }

                return new AggregatedPageImpl(list, pageable,
                        hits.getTotalHits(), response.getAggregations(), response.getScrollId(), hits.getMaxScore());
            }
        });
    }
}

二、Controller层处理帖子添加和评论事件请求

1.添加帖子时-触发事件-发布消息

// 发布帖子后,触发发帖事件-向kafka服务器发布消息
Event event = new Event()
        .setTopic(TOPIC_PUBLISH)
        .setFromUserId(user.getId())
        .setEntityType(ENTITY_TYPE_POST)
        .setEntityId(discussPost.getId());
eventProducer.sendEvent(event);

2. 添加评论时-触发发帖事件-发布消息

  • 因为对帖子发布评论后,帖子的字段需要更新,为保证数据一致性,需要重新发布事件
if (comment.getEntityType() == ENTITY_TYPE_POST) {
    // 触发发帖事件
    event = new Event()
            .setTopic(TOPIC_PUBLISH)
            .setFromUserId(comment.getUserId())
            .setEntityType(ENTITY_TYPE_POST)
            .setEntityId(discussPostId);
    eventProducer.sendEvent(event);
}

三、kafka消费者订阅消息并提交到ES服务器

/**
 * 消费发布帖子的消息-将帖子数据提交到ES服务器
 * @param record
 */
@KafkaListener(topics = TOPIC_PUBLISH)
public void handlePublishMessage(ConsumerRecord record) {
    // 1.边界条件:先检查有无取到消息
    if (record == null || record.value() == null) {
        logger.error("消息的内容为空!");
        return;
    }
    // 2.将拿到的消息恢复成Object类型,方便操作
    Event event = JSONObject.parseObject(record.value().toString(), Event.class);
    if(event == null) {
        logger.error("消息的格式错了!");
        return;
    }

    // 3. 将拿到的消息添加到ES服务器中
    DiscussPost discussPost = discussPostService.selectPostById(event.getEntityId());
    elasticSearchService.savePost(discussPost);
}

四、处理搜索结果

1. Controller处理搜索请求

  • 搜索帖子-分页搜索-页面默认设置当前页为1,limit为10

  • 注意-需要的分页信息是-当前页码和当前页数量

    • 与mysql查询的分页条件不同(起始行-当前页显示多少行)

    在这里插入图片描述

/**
 * 根据关键字搜索查询帖子请求
 * @param keyword
 * @param model
 * @param page
 * @return
 */
@RequestMapping(value = "/search", method = RequestMethod.GET)
public String search(String keyword, Model model, Page page) {
    // 搜索帖子-分页搜索-页面默认设置当前页为1,limit为10
    // 注意-需要的分页信息是-当前页码和当前页数量,与mysql查询的分页条件不同(起始行-当前页显示多少行)
    org.springframework.data.domain.Page<DiscussPost> searchResult
            = elasticSearchService.searchPosts(keyword, page.getCurrent() - 1, page.getLimit());

    // 聚合数据
    List<Map<String, Object>> discussPosts = new ArrayList<>();
    if (searchResult != null) {
        for (DiscussPost post : searchResult) {
            Map<String, Object> map = new HashMap<>();
            // 帖子
            map.put("post", post);
            // 作者
            map.put("user", userService.findUserById(post.getUserId()));
            // 对帖子的点赞数量
            map.put("likeCount", likeService.findEntityLikeCount(ENTITY_TYPE_POST, post.getId()));

            discussPosts.add(map);
        }
    }
    model.addAttribute("discussPosts", discussPosts);
    model.addAttribute("keyword", keyword);
    // 页面设置
    page.setPath("/search?keyword=" + keyword);
    page.setRows(searchResult == null ? 0 : (int) searchResult.getTotalElements());
    return "/site/search";
}

2. 处理模板页面

主页头部的搜索栏链接

<!-- 搜索 -->
<form class="form-inline my-2 my-lg-0" method="get" th:action="@{/search}">
   <input class="form-control mr-sm-2" type="search" aria-label="Search" name="keyword" th:value="${keyword}"/>
   <button class="btn btn-outline-light my-2 my-sm-0" type="submit">搜索</button>
</form>

搜索网页设置

<li class="media pb-3 pt-3 mb-3 border-bottom" th:each="map:${discussPosts}">
   <img th:src="${map.user.headerUrl}" class="mr-4 rounded-circle" style="width:50px;height:50px;" alt="用户头像">
   <div class="media-body">
      <h6 class="mt-0 mb-3">
         <a th:href="@{|/discuss/detail/${map.post.id}|}" th:utext="${map.post.title}">备战<em>春招</em>,面试刷题跟他复习,一个月全搞定!</a>
      </h6>
      <div class="mb-3" th:utext="${map.post.content}">帖子内容
      </div>
      <div class="text-muted font-size-12">
         <u class="mr-3" th:utext="${map.user.username}">寒江雪</u> 发布于
         <b th:text="${#dates.format(map.post.createTime,'yyyy-MM-dd HH:mm:ss')}">2019-04-15 15:32:18</b>
         <ul class="d-inline float-right">
            <li class="d-inline ml-2"><i th:text="${map.likeCount}">11</i></li>
            <li class="d-inline ml-2">|</li>
            <li class="d-inline ml-2">回复 <i th:text="${map.post.commentCount}">7</i></li>
         </ul>
      </div>
   </div>
</li>

测试结果:

在这里插入图片描述

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

项目1在线交流平台-6.Elasticsearch分布式搜索引擎-3.ES结合Kafka应用-开发社区搜索功能 的相关文章

  • 编译Linux内核数

    本文是参考了网上多篇帖子而写的算不上什么原创 唯一值得欣慰的只不过在本机上实现罢了 因为毕竟失败了几次 也因为本人是初学驱动编程 很多简单的问题在我来说是相当的困难的 望有识之士不要笑话 最后 xff0c 希望本文能给刚学驱动而还没开头的人
  • 构造内核源码树

    编写驱动程序时 xff0c 需要内核源码树的支持 内核源码树时从内核源代码编译得到的 下面开始构造内核源代码的步骤 以Ubuntu为例子 1 下载内源代码 xff0c 位置www kernel org 注意 xff1a 源码树内核的版本要和
  • 裁剪图像中感兴趣区域python

    题外话 xff1a 比较全面的缩略图及相应源码 http matplotlib org gallery html http www cnblogs com wei li archive 2012 05 23 2506940 html 题外外
  • Linux设备驱动程序(LDD)中snull的编译问题

    对LDD中snull程序 xff0c 编译的时候会有许多问题 xff0c 鉴于网上还没有合适的解决办法 xff0c 做此总结 xff0c 整理知识 本文在debian6 0上运行通过 xff0c 内核版本为2 6 32 学习LDD中网络驱动
  • 认识(大端--小端)端模式

    span style color 000000 端模式 xff08 Endian xff09 的这个词出自Jonathan Swift书写的 格列佛游记 这本书根据将鸡蛋敲开的方法不同将所有的人分为两类 xff0c 从圆头开始将鸡蛋敲开的人
  • HOW TO install nam for ns2 on debian

    Debian is convinent to install software packages for the tool aptl Like many other packages we can use apt get install n
  • c++ #pragma once和 #ifndef 优缺点对比分析

    pragma once ifndef方式为了避免同一个头文件被包含 xff08 include xff09 多次 pragma once 声明 定义语句 ifndef SOMEFILE H define SOMEFILE H 声明 定义语句
  • roslaunch找不到packge

    roslaunch找不到packge 尝试下面几种做法 1 source bashrc 2 source catkin ws devel setup bash 3 rospack profile 为确保ROS能找到新包 xff0c 常常在发
  • DSP:TMS320C6657 之 UART波特率问题

    6657 设置串口波特率 以614400为例 xff08 1 xff09 根据公式计算分频系数 xff08 2 xff09 1GHz 主频下 UART 输入频率 166666666Hz xff08 1 6 xff09 xff08 3 xff
  • 手写httpServer Demo案例

    相信每一个java程序猿在学习javaWeb的时候 xff0c 或多或少接触了Servlet 或者说通过Servlet来完成页面发送的请求 今天 xff0c 模仿Servlet接受和处理请求实现一个简单的httpServer 该Server
  • ubuntu18.04 查看在用串口

    1 终端输入cutecom 打开串口助手 xff0c 可能没有下载 xff0c 可根据提示下载安装 sudo cutecom 2 点击device旁边的下拉按钮即可查询当前在用的串口
  • Linux解决未定义的引用过程记录

    Linux解决未定义的引用过程记录 在摸索vscode使用的过程中 xff0c 编写的代码出现了为定义的引用错误 csdn上搜索了很多 xff0c 代码小白看完觉得写的非常的简略 xff0c 完全无从下手 xff08 应该是我太菜了 xff
  • 十一种室内定位传感器方案汇总介绍与对比(机器人、物联网领域)

    室内定位传感器方案汇总 目录 室内定位传感器方案汇总 1 定位方案概述 1 1 内定位系统有最基本的5种算法 xff1a 1 2 常用的室内定位技术主要包括以下几种 xff1a 1 3 定位理论 1 4 不同的定位方案对比 2 各种定位方案
  • C++中的unique函数

    STL中的unique函数的头文件 xff1a span class hljs preprocessor include lt iostream gt span unique 的作用是 去掉 容器中相邻元素的重复元素 xff0c 这里所说的
  • 单片机开发入门---从零开始玩转FRDM-KL25Z

    一 背景介绍 最近需要开发一个程序 xff0c 使用飞思卡尔的开发板FRDM KL25Z xff0c 来设计一款 西蒙游戏 的改进版 xff0c 下面我们先来了解一下西蒙游戏 西蒙游戏 是一款益智休闲类小游戏 xff0c 它的游戏规则是 x
  • SSD---系统架构

    SSD主要由两大模块构成 主控和闪存介质 另外可选的还有Cache缓存单元 主控是SSD的大脑 xff0c 承担着指挥 运算和协调的作用 xff0c 具体表现在 xff1a 前端实现标准主机接口与主机通信 xff0c 接口包括SATA SA
  • SSD核心技术---FTL

    FTL算法的优劣与否 xff0c 直接决定了SSD在性能 xff08 Performance xff09 可靠性 xff08 Reliability xff09 耐用性 xff08 Endurance xff09 等方面的好坏 xff0c
  • SSD---PCIe介绍

    SSD已经大跨步迈入PCIe时代 作为SSD的一项重要技术 xff0c 我们有必要对PCIe有个基本的了解
  • SSD---NVMe介绍

    何为NVMe xff1f NVMe即Non Volatile Memory Express xff0c 是非易失性存储器标准 xff0c 是跑在PCIe接口上的协议标准 NVMe的设计之初就有充分利用了PCIe SSD的低延时以及并行性 x
  • SSD---ECC原理

    我们知道 xff0c 所有型号的闪存都无法保证存储的数据会永久稳定 xff0c 这时候就需要ECC xff08 纠错码 xff09 去给闪存纠错 ECC能力的强弱直接影响到SSD的使用寿命和可靠性 本章将简单介绍ECC的基本原理和目前最主流

随机推荐

  • 音响发烧友---HiFi音频功放

    最近一直想做个开源的电子项目 xff0c 思考许久还是选择做个HiFi音频功放 作为一个音响发烧友 xff0c 带大家DIY一台属于自己的功放 聆听一下 xff0c 纯正的音乐之美 首选需要了解一下功放的类型 xff1a 纯甲类功率放大器乙
  • Altium Designer20常用使用快捷键

    一 AD20常用快捷键 PCB布线常使用 xff1a ctrl 43 m 测量长度 Q 单位切换 shift 43 ctrl 43 r 取消显示标注 shift 43 S 显示层切换 ctrl 43 右击 高亮显示一条线 ctrl 43 D
  • Altium Designer20 交叉选择模式

    在使用Altium Designer进行PCB布局时 xff0c 首先我们需要将原理图元器件更新到PCB中 xff0c 所有的元件封装都会汇集到PCB中 xff0c 但并没有根据电路模块进行分类聚集 xff1b 我们可以使用AD的交叉选择模
  • Altium Designer20 批量修改元件丝印大小和位置

    在进行PCB布线时 xff0c 我们经常需要调整元件丝印的大小和位置 有了丝印才能在PCB焊接和调试板子的时候得心应手 xff0c 下面介绍一种便捷的方法 xff0c 来实现批量修改元件丝印和位置 1 修改元件丝印大小 xff08 1 xf
  • 图像重叠区域

    http www cnblogs com dwdxdy archive 2013 08 02 3232331 html
  • bat批处理---实现输入指定拷贝文件

    在windows平台下 xff0c 平常的给芯片下载程序过程中 xff0c 经常遇到需要在多个文件夹下面拷贝bin文件的情况 xff0c 为了实现能够通过输入参数 xff0c 来选择需要拷贝的问下 xff0c 写了一个 bat批处理文件 只
  • Altium Designer20 PCB规则设置

    我们在进行PCB布线之前 xff0c 需要对PCB布线进行规则设置 xff0c 如果大家只是DIY爱好者 xff0c 那我们将设置价格最经济的PCB规则 xff0c 我们可以以捷配官网的PCB工艺信息作为参考 xff1b 下面我将介绍常用的
  • 入门到放弃之 NVMe-MI --- 协议简介

    在学习NVMe MI协议之前 xff0c 感觉协议是如此的枯燥 xff0c 通过短时间的阅读Spec发现协议规范定义的精妙绝伦 xff1b 协议中各种细节处理的相当到位 xff0c 最有趣的是消息服务模型的状态机设计 xff0c 希望大家一
  • NVMe-MI --- Message Transport(消息传输)

    3 消息传输 该规范定义了一个支持多种消息传输的接口 消息格式与带外机制和带内隧道机制相同 3 1 NVMe MI消息 NVMe MI消息在带外机制和带内隧道机制中都有使用 NVMe MI消息的格式如图17和图18所示 在带外机制中 xff
  • NVMe-MI --- Message Servicing Model(消息服务模型)

    4 消息服务模型 4 1 NVMe MI 消息 图23展示了NVMe MI消息的分类 NVMe MI消息的两个主要类别是请求消息和响应消息 当使用带外机制时 xff0c 请求消息由管理控制器发送到管理端点 在使用带内隧道机制时 xff0c
  • NVMe-MI --- Management Interface Command Set

    Management Interface Command Set 命令集定义了当NMIMT值被设置为NVMe MI命令时 xff0c 请求者可以提交的命令信息 管理接口命令集同时适用于带外机制和带内隧道机制 NVMe MI消息结构以及所有N
  • PCIe总线引脚定义

    然后看一下PCI E的接口定义 这就是显卡插口前面的那段短的金手指 xff0c 就是这段 xff1a 这一段负责供电 SMBus和感知设备是否插上 xff0c 对于数据的传输作用不大 xff0c 所以不用深究 用浅绿色标出来的是检测插槽上设
  • Mbus新增主动报警功能,简单问题的波折路程。

    由于用到了主动报警上传功能 一个简单的if判断 xff0c 便实现了判断与上传功能 脱机测试 xff0c 上流量台测试 xff0c 都正常 以为这件事便了了 结果到了现场却给暴出了问题 xff0c 没法收到报警 于是 xff0c 一对一的现
  • 相机IMU联合标定

    单目相机内参标定 xff1a xff08 焦距 xff0c 光心 https blog csdn net qq 42399848 article details 89298212 ops request misc 61 257B 2522r
  • Hough变换理解

    reference http blog csdn net app 12062011 article details 11307053 一 简单介绍 Hough变换是图像处理中从图像识别几何形状的基本方法之一 xff0c 霍夫变换寻找直线和圆
  • 1.常见8种排序算法分析笔记之-空间O(1)三种(冒泡、选择、插入)

    文章目录 空间复杂度为O 1 的三种排序法一 冒泡排序法1 代码实现思想2 复杂度分析3 代码实现4 代码测试 二 选择排序法1 代码实现思想2 复杂度分析3 代码实现4 代码测试 三 插入排序法1 代码实现思想2 复杂度分析3 代码实现4
  • 2.常见8种排序算法分析笔记之-时间O(NlogN)三种(归并、快排、堆排序)

    文章目录 时间复杂度为 O N l o g
  • 3.常见8种排序算法分析笔记之-时间性能突破O(n^2)的原地排序法-希尔排序法

    文章目录 时间性能突破 O n 2
  • 项目1在线交流平台-6.Elasticsearch分布式搜索引擎-2.Spring整合Elasticsearch测试

    文章目录 一 导入依赖和配置1 导入依赖2 配置连接3 解决启动Netty冲突 二 SpringData集成ES测试1 配置实体类与ES索引字段相对应 96 64 Document indexName 61 34 discusspost 3
  • 项目1在线交流平台-6.Elasticsearch分布式搜索引擎-3.ES结合Kafka应用-开发社区搜索功能

    文章目录 功能需求一 Service层处理操作ES服务器的数据二 Controller层处理帖子添加和评论事件请求1 添加帖子时 触发事件 发布消息2 添加评论时 触发发帖事件 发布消息 三 kafka消费者订阅消息并提交到ES服务器四 处