Elasticsearch高效文章搜索实践

功能

image-20250610211130171

创建索引和映射

image-20250610213446050

使用postman添加映射和查询

image-20250610213733416

查询所有的文章信息,批量导入到es索引库中

image-20250610214358841
server:port: 9999
spring:application:name: es-articledatasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/leadnews_article?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTCusername: rootpassword: root
# 设置Mapper接口所对应的XML文件位置,如果你在Mapper接口中有自定义方法,需要进行该配置
mybatis-plus:mapper-locations: classpath*:mapper/*.xml# 设置别名包扫描路径,通过该属性可以给包中的类注册别名type-aliases-package: com.heima.model.article.pojos#自定义elasticsearch连接配置
elasticsearch:host: 192.168.200.130port: 9200

导入到es索引库

/*** 注意:数据量的导入,如果数据量过大,需要分页导入** @throws Exception*/
@Test
public void init() throws Exception {// 查询所有符合条件的文章数据List<SearchArticleVo> searchArticleVos = apArticleMapper.loadArticleList();// 批量导入到es索引库BulkRequest bulkRequest = new BulkRequest("app_info_article");for (SearchArticleVo searchArticleVo : searchArticleVos) {IndexRequest indexRequest = new IndexRequest().id(searchArticleVo.getId().toString()).source(JSON.toJSONString(searchArticleVo), XContentType.JSON);// 批量添加数据bulkRequest.add(indexRequest);}restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
}

需求说明

image-20250610221421008

搜索接口定义

image-20250610222047807

UserSearchDto

image-20250610222355123

实现步骤

image-20250612193842072

image-20250612193949445

image-20250612194110538

文章搜索服务实现

/*** es文章分页检索** @param dto* @return*/@Overridepublic ResponseResult search(UserSearchDto dto) throws IOException {//1.检查参数if(dto == null || StringUtils.isBlank(dto.getSearchWords())){return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);}ApUser user = AppThreadLocalUtil.getUser();//异步调用 保存搜索记录if(user != null && dto.getFromIndex() == 0){apUserSearchService.insert(dto.getSearchWords(), user.getId());}//2.设置查询条件SearchRequest searchRequest = new SearchRequest("app_info_article");SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();//布尔查询BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();//关键字的分词之后查询QueryStringQueryBuilder queryStringQueryBuilder = QueryBuilders.queryStringQuery(dto.getSearchWords()).field("title").field("content").defaultOperator(Operator.OR);boolQueryBuilder.must(queryStringQueryBuilder);//查询小于mindate的数据RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("publishTime").lt(dto.getMinBehotTime().getTime());boolQueryBuilder.filter(rangeQueryBuilder);//分页查询searchSourceBuilder.from(0);searchSourceBuilder.size(dto.getPageSize());//按照发布时间倒序查询searchSourceBuilder.sort("publishTime", SortOrder.DESC);//设置高亮  titleHighlightBuilder highlightBuilder = new HighlightBuilder();highlightBuilder.field("title");highlightBuilder.preTags("<font style='color: red; font-size: inherit;'>");highlightBuilder.postTags("</font>");searchSourceBuilder.highlighter(highlightBuilder);searchSourceBuilder.query(boolQueryBuilder);searchRequest.source(searchSourceBuilder);SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);//3.结果封装返回List<Map> list = new ArrayList<>();SearchHit[] hits = searchResponse.getHits().getHits();for (SearchHit hit : hits) {String json = hit.getSourceAsString();Map map = JSON.parseObject(json, Map.class);//处理高亮if(hit.getHighlightFields() != null && hit.getHighlightFields().size() > 0){Text[] titles = hit.getHighlightFields().get("title").getFragments();String title = StringUtils.join(titles);//高亮标题map.put("h_title",title);}else {//原始标题map.put("h_title",map.get("title"));}list.add(map);}return ResponseResult.okResult(list);}

新增文章同步添加索引

/*** 创建文章索引** @param apArticle* @param content* @param path*/
private void createArticleEsIndex(ApArticle apArticle, String content, String path) {SearchArticleVo vo = new SearchArticleVo();BeanUtils.copyProperties(apArticle, vo);vo.setContent(content);vo.setStaticUrl(path);kafkaTemplate.send(ArticleConstants.ARTICLE_ES_SYNC_TOPIC, JSON.toJSONString(vo));
}

同步文章数据

@Component
@Slf4j
public class SyncArticleListener {@Autowiredprivate RestHighLevelClient  restHighLevelClient;/*** 同步文章数据* @param message*/@KafkaListener(topics = ArticleConstants.ARTICLE_ES_SYNC_TOPIC)public void onMessage(String message) {if (StringUtils.isNotBlank(message)) {SearchArticleVo searchArticleVo = JSON.parseObject(message, SearchArticleVo.class);IndexRequest indexRequest = new IndexRequest("app_info_article");indexRequest.id(searchArticleVo.getId().toString());indexRequest.source(message, XContentType.JSON);try {restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);} catch (IOException e) {log.error("sync es error = {}", e.getMessage(), e);}}}
}

搜索记录

需求说明

image-20250613221520518

数据存储说明

image-20250613221753764

保存搜索记录-实现思路

image-20250613230006106

image-20250613230334610

image-20250613230414766

image-20250613230621594

用户搜索服务实现

保存用户搜索历史记录

/*** 保存用户搜索历史记录** @param keyword* @param userId*/@Override@Asyncpublic void insert(String keyword, Integer userId) {//1.查询当前用户的搜索关键词Query query = Query.query(Criteria.where("userId").is(userId).and("keyword").is(keyword));ApUserSearch apUserSearch = mongoTemplate.findOne(query, ApUserSearch.class);//2.存在 更新创建时间if (apUserSearch != null) {apUserSearch.setCreatedTime(new Date());mongoTemplate.save(apUserSearch);return;}//3.不存在,判断当前历史记录总数量是否超过10apUserSearch = new ApUserSearch();apUserSearch.setUserId(userId);apUserSearch.setKeyword(keyword);apUserSearch.setCreatedTime(new Date());Query query1 = Query.query(Criteria.where("userId").is(userId));query1.with(Sort.by(Sort.Direction.DESC, "createdTime"));List<ApUserSearch> apUserSearchList = mongoTemplate.find(query1, ApUserSearch.class);if (apUserSearchList == null || apUserSearchList.size() < 10) {mongoTemplate.save(apUserSearch);} else {ApUserSearch lastUserSearch = apUserSearchList.get(apUserSearchList.size() - 1);mongoTemplate.findAndReplace(Query.query(Criteria.where("id").is(lastUserSearch.getId())), apUserSearch);}}

查询用户搜索历史记录

/*** 查询用户搜索历史记录* @return*/@Overridepublic ResponseResult findUserSearch() {// 获取当前用户ApUser user = AppThreadLocalUtil.getUser();if (user == null) {return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);}// 根据当前用户查询数据,按照时间倒序List<ApUserSearch> apUserSearches = mongoTemplate.find(Query.query(Criteria.where("userId").is(user.getId())).with(Sort.by(Sort.Direction.DESC, "createdTime")), ApUserSearch.class);return ResponseResult.okResult(apUserSearches);}

删除用户搜索历史记录

/*** 删除用户搜索历史记录* @param dto* @return*/@Overridepublic ResponseResult delUserSearch(HistorySearchDto dto) {// 检查参数if (dto.getId() == null) {return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);}// 判断是否登录ApUser user = AppThreadLocalUtil.getUser();if (user == null) {return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);}// 删除mongoTemplate.remove(Query.query(Criteria.where("userId").is(user.getId()).and("id").is(dto.getId())), ApUserSearch.class);return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);}

image-20250614173542679

image-20250614173634456

关键字联想词服务实现

image-20250614175924606

image-20250614180314561

image-20250614180446769

联想词查询

/*** 联想词查询* @param dto* @return*/@Override
public ResponseResult search(UserSearchDto dto) {// 检查参数if (StringUtils.isBlank(dto.getSearchWords())) {return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);}// 分页检查if (dto.getPageSize() > 20) {dto.setPageSize(20);}// 执行查询,模糊查询Query query = Query.query(Criteria.where("associateWords").regex(".*?\\" + dto.getSearchWords() + ".*"));query.limit(dto.getPageSize());List<ApAssociateWords> apAssociateWords = mongoTemplate.find(query, ApAssociateWords.class);return ResponseResult.okResult(apAssociateWords);
}

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

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

相关文章

React 中除了react-router还有哪些路由方案

在用React开发时&#xff0c;常用的路由是react-router &#xff0c;但除此之外&#xff0c;还有两个路由方案&#xff0c;因为他们具备 react-router 没有的特性。 1. tanstack/router 1.1. 主要特性 100% 推断的 TypeScript 支持 类型安全的导航 嵌套路由和布局路由 内置…

VINS-Fusion 简介、安装、编译、数据集/相机实测

目录 VINS-Fusion 简介 安装 VINS-Fusion 源码安装 运行数据集 双目模式 单目IMU 模式 双目IMU 模式 D455 相机实际运行 双目IMU 模式 VINS-Fusion 简介 VINS-Fusion 是继 VINS-Mono 和 VINS-Mobile&#xff08;单目视觉惯导 SLAM 方案&#xff09;后&#xff0c;香港科 技大学…

SQL Developer 表复制

SQL Developer 表复制 此方法在数据量比较大时&#xff0c;比一条一条的insert要快得多&#xff1b;具体是会覆盖掉原数据&#xff0c;还是增量的处理&#xff0c;请自行创建demo表测试一下。 注意&#xff1a;原库版本要与目标库数据库版本一致&#xff0c;否则可能会报错的。…

影视剧学经典系列-梁祝-《吕氏春秋·应同》

1、背景 07版电视剧《梁山伯与祝英台》中&#xff0c;谢道韫作为先生&#xff0c;给学生讲了其中的句子。 2、名言 君为尊&#xff0c;以白为黑&#xff0c;臣不能从&#xff1b;父虽亲&#xff0c;以黑为白&#xff0c;子不能从”出自《吕氏春秋应同》 其意为&#xff0c;…

异步爬虫---

代码结构分析 这是一个同步新闻爬虫程序&#xff0c;主要包含以下几个部分&#xff1a; 们把爬虫设计为一个类&#xff0c;类在初始化时&#xff0c;连接数据库&#xff0c;初始化logger&#xff0c;创建网址池&#xff0c;加载hubs并设置到网址池。 爬虫开始运行的入口就是r…

微服务架构中的 Kafka:异步通信与服务解耦(二)

三、Kafka 基础入门 3.1 Kafka 是什么 Kafka 最初由 LinkedIn 公司开发&#xff0c;是一个开源的分布式事件流平台&#xff0c;后成为 Apache 基金会的顶级项目 。它不仅仅是一个简单的消息队列&#xff0c;更是一个分布式流处理平台&#xff0c;具备强大的消息队列、存储系统…

Lighthouse与首屏优化

之前提到首屏优化&#xff0c;想到的就是Vue项目首页打开很慢需要优化。一般都是肉眼看看&#xff0c;对当前的加载速度并没有一个准确的衡量标准&#xff0c;也没有很清晰的解决思路。 前两天我想给自己的网站申请谷歌广告&#xff0c;听说审核对网站的性能要求很高。于是网上…

Maven 之 打包项目时没有使用本地仓库依赖问题

背景 pom 中使用了第三方jar包&#xff0c;远程仓库设置的是阿里云&#xff0c;之前运行很好&#xff0c;今天不知道怎么的&#xff0c;打包总是报错&#xff0c;阿里云仓库无法找到依赖包(本来也没有)&#xff0c;按理来说&#xff0c;编译打包时会优先选择本地仓库的包才对&a…

Mysql基础入门\期末速成

DDL 操作数据库语句 创建&删除数据库语句 创建数据库 create database 数据库名称; -- 直接创建 create database if not exists 数据库名称; -- 如果不存在&#xff0c;则创建 create database 数据库名称 default charset utf8mb4; -- 创建编译类型utf8的数据类型 cre…

SCADA|KingSCADA4.0中历史趋势控件与之前版本的差异

哈喽,你好啊,我是雷工! 最近用到KingSCADA4.0信创版本,也算尝鲜使用。 在使用的过程中发现有些功能或多或少存在一些差异, 这里将遇到的一些不同总结一下,便于后期更好的使用。 01 历史趋势控件 在KingSCADA中有一个历史趋势曲线控件KSHTrend。 该控件既可以连接King…

ubuntu 拒绝ssh连接,连不上ssh,无法远程登录: Connection failed.

目录 问题描述视窗 可视化桌面命令行 问题描述 [C:\~]$ Connecting to 192.166.8.85:22... Could not connect to 192.166.8.85 (port 22): Connection failed.Type help to learn how to use Xshell prompt. [C:\~]$ Connecting to 192.166.8.85:22... Could not connect to …

【大模型应用开发】向量数据库向量检索方法存在问题及优化

一、检索结果重复 1. 问题分析 在构建向量数据库时&#xff0c;对文档分割会存在重复块&#xff08;chunk_overlap&#xff1a;指两个块之间共享的字符数量&#xff0c;用于保持上下文的连贯性&#xff0c;避免分割丢失上下文信息&#xff09;&#xff0c;如下图所示&#xf…

MySQL常用函数详解之数值函数

MySQL常用函数详解之数值函数 一、数值函数概述1.1 数值函数的作用1.2 数值函数分类 二、算术运算函数2.1 加法运算&#xff08;&#xff09;2.2 减法运算&#xff08;-&#xff09;2.3 乘法运算&#xff08;*&#xff09;2.4 除法运算&#xff08;/ 或 DIV&#xff09;2.5 取模…

13、Redis进阶二之Redis数据安全性分析

⼀ 、Redis性能压测脚本介绍 Redis的所有数据是保存在内存当中的&#xff0c; 得益于内存⾼效的读写性能&#xff0c; Redis的性能是⾮常强悍的 。但 是&#xff0c;内存的缺点是断电即丢失&#xff0c;所以 &#xff0c;在实际项⽬中&#xff0c; Redis—旦需要保存—些重要的…

【系统分析师】2011年真题:综合知识-答案及详解

文章目录 【第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题】【…

FastAPI-MCP构建自定义MCP工具实操指南

一、简介 • FastAPI-MCP是一个基于python FastAPI框架开发的开源项目&#xff0c;可以自动识别并暴露FastAPI接口为MCP工具 • 拥有FastAPI框架的所有优点&#xff0c;如异步高并发、独立远程部署、OpenAPI文档 • 提供SSE、mcp-remote接入方式&#xff0c;支持设置授权访问…

LLMs之Memory:《LLMs Do Not Have Human-Like Working Memory》翻译与解读

LLMs之Memory&#xff1a;《LLMs Do Not Have Human-Like Working Memory》翻译与解读 导读&#xff1a;该论文通过三个精心设计的实验&#xff0c;证明了当前的大型语言模型&#xff08;LLMs&#xff09;缺乏类似人类的工作记忆。实验结果表明&#xff0c;LLMs无法在没有明确外…

Node.js验证码:从生成到验证的趣味之旅

文章目录 Node.js验证码&#xff1a;从生成到验证的趣味之旅&#x1f4dc; 引言&#xff1a;为什么需要验证码&#xff1f;1. 验证码的基本原理 &#x1f9e0;验证码工作流程示意图 2. 技术栈准备 &#x1f6e0;️3. 验证码生成详解 &#x1f3a8;3.1 生成SVG验证码3.2 转换为P…

芯科科技携最新Matter演示和参考应用精彩亮相Matter开放日和开发者大会

全面展示赋能Matter设备实现跨协议和跨海内外生态的技术能力 作为Matter标准创始厂商之一和其解决方案的领先供应商&#xff0c;Silicon Labs&#xff08;亦称“芯科科技”&#xff09;于6月12至13日参加由连接标准联盟中国成员组&#xff08;CMGC&#xff09;主办的Matter年度…

AndroidStudio下载的SDK没有tool目录,或者想要使用uiautomatorviewer工具

1.如果没有tool目录可以使用下面的地址进行下载 https://dl.google.com/android/repository/tools_r25.2.5-windows.zip 2.并且把下载的文件解压到放在AndroidStudio的目录中 3.如果使用uiautomatorviewer.bat出现下面的错误 Unable to connect to adb.Check if adb is instal…