实现高亮的全文分页检索

文章目录

  • 🌞 Sun Frame:SpringBoot 的轻量级开发框架(个人开源项目推荐)
    • 🌟 亮点功能
    • 📦 spring cloud模块概览
      • 常用工具
    • 🔗 更多信息
    • 1.sun-club-infra 模块
        • SubjectEsServiceImpl.java
          • 1.querySubjectList方法:根据查询请求进行查询
          • 2.convertHit2SubjectInfoEs方法:将每一个hit转换为SubjectInfoEs
          • 3.根据信息构建一个查询请求对象
    • 2.简单测试
        • 1.TestFeignController.java
        • 2.新增几条记录
        • 2.查询
        • 3.结果高亮显示
    • 3.加上控制层的实现
        • 1.DTO和BO都加上keyWord属性
        • 2.SubjectController.java
        • 3.sun-club-domain
          • 1.SubjectInfoDomainService.java
          • 2.SubjectInfoDomainServiceImpl.java
        • 4.测试
          • 1.es报错,requires query value
          • 2.发现转换器没有将keyWord转换,所以clean-package一下maven即可
          • 3.重新测试

🌞 Sun Frame:SpringBoot 的轻量级开发框架(个人开源项目推荐)

Sun Frame Banner

轻松高效的现代化开发体验

Sun Frame 是我个人开源的一款基于 SpringBoot 的轻量级框架,专为中小型企业设计。它提供了一种快速、简单且易于扩展的开发方式。

我们的开发文档记录了整个项目从0到1的任何细节,实属不易,请给我们一个Star!🌟
您的支持是我们持续改进的动力。

🌟 亮点功能

  • 组件化开发:灵活选择,简化流程。
  • 高性能:通过异步日志和 Redis 缓存提升性能。
  • 易扩展:支持多种数据库和消息队列。

📦 spring cloud模块概览

  • Nacos 服务:高效的服务注册与发现。
  • Feign 远程调用:简化服务间通信。
  • 强大网关:路由与限流。

常用工具

  • 日志管理:异步处理与链路追踪。
  • Redis 集成:支持分布式锁与缓存。
  • Swagger 文档:便捷的 API 入口。
  • 测试支持:SpringBoot-Test 集成。
  • EasyCode:自定义EasyCode模板引擎,一键生成CRUD。

🔗 更多信息

  • 开源地址:Gitee Sun Frame
  • 详细文档:语雀文档
    在这里插入图片描述

1.sun-club-infra 模块

SubjectEsServiceImpl.java
1.querySubjectList方法:根据查询请求进行查询
@Override
public PageResult<SubjectInfoEs> querySubjectList(SubjectInfoEs req) {// 构建一个返回的分页对象PageResult<SubjectInfoEs> pageResult = new PageResult<>();// 根据信息构建一个查询请求对象EsSearchRequest esSearchRequest = createSearchListQuery(req);// 获得分页查询结果SearchResponse searchResponse = EsRestClient.searchWithTermQuery(getEsIndexInfo(), esSearchRequest);// 构建一个要返回的数据对象List<SubjectInfoEs> subjectInfoEsList = new LinkedList<>();// 得到命中的数据SearchHits searchHits = searchResponse.getHits();if (searchHits == null || searchHits.getHits() == null) {pageResult.setPageNo(req.getPageNo());pageResult.setPageSize(req.getPageSize());pageResult.setRecords(subjectInfoEsList);pageResult.setTotal(0);return pageResult;}// 如果有命中的SearchHit[] hits = searchHits.getHits();for (SearchHit hit : hits) {// 将每个hit都转换为SubjectInfoEs,然后将其放到要返回的数据对象中SubjectInfoEs subjectInfoEs = convertHit2SubjectInfoEs(hit);subjectInfoEsList.add(subjectInfoEs);}// 构建分页对象pageResult.setPageNo(req.getPageNo());pageResult.setPageSize(req.getPageSize());pageResult.setRecords(subjectInfoEsList);pageResult.setTotal(Long.valueOf(searchHits.getTotalHits().value).intValue());return pageResult;
}
2.convertHit2SubjectInfoEs方法:将每一个hit转换为SubjectInfoEs
/*** 将每一个hit转换为SubjectInfoEs* @param hit* @return*/
private SubjectInfoEs convertHit2SubjectInfoEs(SearchHit hit) {Map<String, Object> sourceAsMap = hit.getSourceAsMap();if (CollectionUtils.isEmpty(sourceAsMap)) {return null;}SubjectInfoEs result = new SubjectInfoEs();// 封装基本数据result.setSubjectId(MapUtils.getLong(sourceAsMap, EsSubjectFields.SUBJECT_ID));result.setSubjectName(MapUtils.getString(sourceAsMap, EsSubjectFields.SUBJECT_NAME));result.setSubjectAnswer(MapUtils.getString(sourceAsMap, EsSubjectFields.SUBJECT_ANSWER));result.setDocId(MapUtils.getLong(sourceAsMap, EsSubjectFields.DOC_ID));result.setSubjectType(MapUtils.getInteger(sourceAsMap, EsSubjectFields.SUBJECT_TYPE));result.setScore(new BigDecimal(String.valueOf(hit.getScore())).multiply(new BigDecimal("100.00").setScale(2, RoundingMode.HALF_UP)));//处理name的高亮Map<String, HighlightField> highlightFields = hit.getHighlightFields();HighlightField subjectNameField = highlightFields.get(EsSubjectFields.SUBJECT_NAME);if(Objects.nonNull(subjectNameField)){Text[] fragments = subjectNameField.getFragments();StringBuilder subjectNameBuilder = new StringBuilder();for (Text fragment : fragments) {subjectNameBuilder.append(fragment);}result.setSubjectName(subjectNameBuilder.toString());}//处理答案高亮HighlightField subjectAnswerField = highlightFields.get(EsSubjectFields.SUBJECT_ANSWER);if(Objects.nonNull(subjectAnswerField)){Text[] fragments = subjectAnswerField.getFragments();StringBuilder subjectAnswerBuilder = new StringBuilder();for (Text fragment : fragments) {subjectAnswerBuilder.append(fragment);}result.setSubjectAnswer(subjectAnswerBuilder.toString());}return result;
}
3.根据信息构建一个查询请求对象
    /*** 根据信息构建一个查询请求对象* @param req* @return*/private EsSearchRequest createSearchListQuery(SubjectInfoEs req) {EsSearchRequest esSearchRequest = new EsSearchRequest();// bq用来组合查询条件BoolQueryBuilder bq = new BoolQueryBuilder();// 查询条件1是根据题目名称查询MatchQueryBuilder subjectNameQueryBuilder =QueryBuilders.matchQuery(EsSubjectFields.SUBJECT_NAME, req.getKeyWord());// 查询条件2是根据题目的答案查询MatchQueryBuilder subjectAnswerQueryBuilder =QueryBuilders.matchQuery(EsSubjectFields.SUBJECT_ANSWER, req.getKeyWord());// 使用bq关联两个查询条件,should就相当于或者,就是两个都查bq.should(subjectNameQueryBuilder);// 让题目名的权重高2subjectNameQueryBuilder.boost(2);bq.should(subjectAnswerQueryBuilder);// 查询条件3是只查询简答题MatchQueryBuilder subjectTypeQueryBuilder =QueryBuilders.matchQuery(EsSubjectFields.SUBJECT_TYPE, SubjectInfoTypeEnum.BRIEF.getCode());// 必须是简答题bq.must(subjectTypeQueryBuilder);// 至少命中一个shouldbq.minimumShouldMatch(1);// 增加高亮HighlightBuilder highlightBuilder = new HighlightBuilder().field("*").requireFieldMatch(false);highlightBuilder.preTags("<span style = \"color:red\">");highlightBuilder.postTags("</span>");// 组装请求// bqesSearchRequest.setBq(bq);// 高亮esSearchRequest.setHighlightBuilder(highlightBuilder);// 匹配字段(一般是全部)esSearchRequest.setFields(EsSubjectFields.FIELD_QUERY);// ==========返回分页查询的结果==========// 当前页是从第几条记录开始,下标从1开始esSearchRequest.setFrom((req.getPageNo() - 1) * req.getPageSize());// 页面大小esSearchRequest.setSize(req.getPageSize());// ==========返回分页查询的结果==========// 不需要快照缓存esSearchRequest.setNeedScroll(false);return esSearchRequest;}

2.简单测试

1.TestFeignController.java
    @RequestMapping("/querySubjectByKeyword")public void querySubjectByKeyword() {SubjectInfoEs subjectInfoEs = new SubjectInfoEs();subjectInfoEs.setKeyWord("简答题目");PageResult<SubjectInfoEs> subjectInfoEsPageResult = subjectEsService.querySubjectList(subjectInfoEs);// 打印log.info("querySubjectByKeyword:" + JSON.toJSONString(subjectInfoEsPageResult));}
}
2.新增几条记录

image-20240621131902122

2.查询

image-20240621131919068

3.结果高亮显示

image-20240621131958040

3.加上控制层的实现

1.DTO和BO都加上keyWord属性

image-20240621134333208

image-20240621134345542

2.SubjectController.java
/*** 全文检索* @param subjectInfoDTO* @return*/
@PostMapping("/getSubjectPageBySearch")
public Result<SubjectInfoEs> getSubjectPageBySearch(@RequestBody SubjectInfoDTO subjectInfoDTO) {try {// 打印日志if (log.isInfoEnabled()) {log.info("SubjectController getSubjectPageBySearch SubjectInfoDTO, subjectInfoDTO:{}", JSON.toJSONString(subjectInfoDTO));}// 参数校验Preconditions.checkArgument(StringUtils.isNotBlank(subjectInfoDTO.getKeyWord()), "关键字不能为空");// DTO转BOSubjectInfoBO subjectInfoBO = SubjectInfoDTOConverter.INSTANCE.convertDTO2BO(subjectInfoDTO);// 设置分页参数subjectInfoBO.setPageNo(subjectInfoDTO.getPageNo());subjectInfoBO.setPageSize(subjectInfoDTO.getPageSize());// 全文检索PageResult<SubjectInfoEs> boPageResult = subjectInfoDomainService.getSubjectPageBySearch(subjectInfoBO);return Result.ok(boPageResult);} catch (Exception e) {log.error("SubjectController getSubjectPageBySearch error, subjectInfoDTO:{}", e.getMessage(), e);return Result.fail("全文检索失败");}
}
3.sun-club-domain
1.SubjectInfoDomainService.java
/*** 全文检索* @param subjectInfoBO* @return*/
PageResult<SubjectInfoEs> getSubjectPageBySearch(SubjectInfoBO subjectInfoBO);
2.SubjectInfoDomainServiceImpl.java
@Override
public PageResult<SubjectInfoEs> getSubjectPageBySearch(SubjectInfoBO subjectInfoBO) {// 将bo转换为entitySubjectInfoEs subjectInfoEs = new SubjectInfoEs();subjectInfoEs.setKeyWord(subjectInfoBO.getKeyWord());subjectInfoEs.setPageNo(subjectInfoBO.getPageNo());subjectInfoEs.setPageSize(subjectInfoBO.getPageSize());// 全文检索PageResult<SubjectInfoEs> subjectInfoEsPageResult = subjectEsService.querySubjectList(subjectInfoEs);return subjectInfoEsPageResult;
}
4.测试
1.es报错,requires query value

image-20240621134034359

2.发现转换器没有将keyWord转换,所以clean-package一下maven即可

image-20240621134110243

image-20240621134223762

3.重新测试

image-20240621134708128

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/396946.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

大数据-74 Kafka 高级特性 稳定性 - 控制器、可靠性 副本复制、失效副本、副本滞后 多图一篇详解

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

【Linux】Linux环境基础开发工具使用之软件包管理(yum)与 Linux编辑器(vim)

目录 一、Linux 软件包管理器 yum1.1 什么是软件包1.2 关于 rzsz1.3 查看软件包1.4 如何安装软件1.5 如何卸载软件1.6 如何更新软件包1.7 yum源更新 二、 Linux编辑器-vim使用2.1 vim的基本概念2.2 vim的基本操作2.3 vim命令模式命令集2.3.1 从命令模式切换为插入模式2.3.2 从插…

03创建型设计模式——抽象工厂模式

一、抽象工厂模式简介 抽象工厂模式是所有形态的工厂模式中最为抽象和具有一般性的。抽象工厂模式可以向客户端提供一个接口&#xff0c;使得客户端在不必指定产品的具体类型的情况下&#xff0c;能够创建多个产品族的产品对象。例如现实生活中&#xff0c;水果的种类繁多&…

Vue3+Ts项目中经常遇到导入组件,vscode报无法找到模块xxx,xxx隐式拥有 “any“ 类型解决办法~

1、报错截图&#xff1a; 2、解决办法&#xff1a;在确保路径正确的情况下&#xff0c;你会在 src 目录下找到一个名为 env.d.ts 的文件&#xff08;或者类似的名称&#xff09;。在这个文件中&#xff0c;你可以声明 .vue 文件的模块类型。例如&#xff1a;(这告诉 TypeScript…

系统内存管理:虚拟内存、内存分段与分页、页表缓存TLB以及Linux内存管理

虚拟内存 虚拟内存是一种操作系统提供的机制&#xff0c;用于将每个进程分配的独立的虚拟地址空间映射到实际的物理内存地址空间上。通过使用虚拟内存&#xff0c;操作系统可以有效地解决多个应用程序直接操作物理内存可能引发的冲突问题。 在使用虚拟内存的情况下&#xff0…

IDEA打开持久层的代码很卡,关掉mybatis-plus的插件

不知道大家有没有遇到过打开 mapper 层的页面&#xff0c;然后要切换另外 java 文件的时候很卡&#xff0c;我遇到过卡了好几分钟的&#xff0c;那种继承了 mybatis-plus 的 mapper java文件或者 xml 文件都会&#xff0c;我后来把 mybatis 的插件关掉了&#xff0c;就不会了

LVS的12种调度算法详解

1.lvs调度算法类型 1.1静态方法 仅根据算法本身进行调度&#xff0c;不考虑RS的负载情况 1.2动态方法 主要根据每RS当前的负载状态及调度算法进行调度Overheadvalue较小的RS将被调度 1.1lvs静态调度算法 1.1.1RR&#xff08;轮询算法&#xff09;&#xff1a; roundrobin 轮…

Haproxy状态页

HAProxy 的状态页是一个非常有用的监控和诊断工具&#xff0c;它提供了关于 HAProxy 服务器运行状态的详细信息&#xff0c;通过web界面&#xff0c;显示当前HAProxy的运行状态。 状态页通常包含以下关键信息&#xff1a; 前端&#xff08;Frontend&#xff09;和后端&#x…

从TiDB迁移到OceanBase的实践分享

本文来自OceanBase热心用户的分享 近期&#xff0c;我们计划将业务数据库从TiDB迁移到OceanBase&#xff0c;但面临的一个主要挑战是如何更平滑的完成这一迁移过程。经过研究&#xff0c;了解到OceanBase提供的OMS数据迁移工具能够支持从TiDB到OceanBase的迁移&#xff0c;并且…

js构造函数的prototype赋值总结

我们知道通过构造函数的prototype,可以生成让所有实例对象访问的通用属性和方法,下面通过代码来解释这个过程 function Person(name){this.name name; }Person.prototype.sex man我们定义了一个构造函数Person,然后给它的prototype添加了一个sex的属性,下面我们来看看Person…

OSPF进阶

一、LSA详解 Type&#xff1a;LSA的类型&#xff08;1、2、3、4、5、7类&#xff09; link-state-ID&#xff1a;链路状态表示符 ADV router&#xff1a;产生该LSA的路由器 age&#xff1a;老化时间 Metric&#xff1a;开销值&#xff0c;一般都为ADV router到达该路由的开…

人工智能,代跑通,预测模型,模型优化

人工智能&#xff0c;代跑通&#xff0c;预测模型&#xff0c;模型优化&#xff0c;增加模块&#xff0c;文章复现&#xff0c;python代做&#xff0c;预测&#xff0c;微调&#xff0c;融合&#xff0c;深度学习&#xff0c;机器学习程序代写&#xff0c;环境调试&#xff0c;…

STM32-门电路-储存器-寄存器-STM32f1-MCU-GPIO-总线-keil5-点led-寄存器编程

1、门电路 门电路组成简单加法器&#xff1a; 二进制对电路的影响&#xff1a; 0和1代表无和有&#xff1b; 以下图例&#xff0c;演示与门&#xff1a;左1右1输出1&#xff1b; 电平标准&#xff1a;使用不同的电压表示数字0和1&#xff1b; 高电平&#xff1a;1&#xff1…

攻防世界-web-ctf-upload

题目场景 查看源码 毫无有效的数据 官方WriteUp 本题需要利用文件上传漏洞点&#xff0c;通过绕过服务器的安全防护&#xff0c;达到getshell的目的 本题的主要考点为利用fastcgi的.user.ini特性进行任意命令执行 这里需要绕过的点如下 检查文件内容是否有php字符串 检查…

haproxy七层代理

目录 一、haproxy简介 二、haproxy实验 1.环境部署 2.haproxy的基本部署方法及负载均衡的实现 2.1安装软件 2.2haproxy的基本配置 3.haproxy的全局配置参数及日志分离 3.1多线程设定 3.2自定义日志 4.haproxy-proxies中的常用配置参数 4.1设置backup --- sorryserver…

卷积神经网络(李宏毅老师系列)

自学参考&#xff1a; 一文搞懂卷积神经网络&#xff08;CNN&#xff09;的原理 视频课 课件资料 笔记 一、引入 cnn设计灵感来自于生物学中的视觉系统&#xff0c;旨在模拟人类视觉处理的方式。常用场景&#xff1a;image classification 基本步骤&#xff1a; 把所有图片都先…

数据结构--第六天

--树 -树的基本概念 树结构通常用来储存逻辑关系为“一对多”的数据&#xff0c;例如&#xff1a; 上图的这些元素具有的就是 "一对多" 的逻辑关系&#xff0c;例如元素A同时和B、C、D有关系&#xff0c;元素D同时和A、H、I、J有关系等。 观察这些元素之间的逻辑关…

模拟经营之神:《北境之地》安卓手机游戏,免费分享

《北境之地》&#xff08;Northgard&#xff09;是一款以北欧神话为背景的即时战略游戏&#xff0c;由Shiro Games开发。玩家在游戏中扮演维京部落的领袖&#xff0c;目标是探索新大陆、建立据点、管理资源&#xff0c;并在严酷的冬季和敌人的威胁下生存下来 。 游戏特色包括&a…

gin路由

1主文件 package main import ("github.com/gin-gonic/gin""godade/user""net/http" ) func main() {router : gin.Default()router.GET("/", func(c *gin.Context) {c.String(http.StatusOK, "Hello World")})v1 : router…

如何避免项目发布后用户从浏览器WebPack中看到源码

打包前在config->index.js中设置productionSourceMap为false productionSourceMap: false,