Java和Redis实现一个简单的热搜功能
1. 前言
我们有一个简单的需求:
- 搜索栏展示当前登陆的个人用户的搜索历史记录,删除个人历史记录。
- 用户在搜索栏输入某字符,则将该字符记录下来 以zset格式存储的redis中,记录该字符被搜索的个数以及当前的时间戳 (用了DFA算法)。
- 每当用户查询了已在redis存在了的字符时,则直接累加个数, 用来获取平台上最热查询的十条数据。(可以自己写接口或者直接在redis中添加一些预备好的关键词)。
- 做不雅文字的过滤功能。

2. 实现
2.1 引入依赖
<dependencies> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>3.7.0</version> <!-- 使用你需要的版本 --> </dependency>
</dependencies>
2.2 实现代码
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Tuple;import java.util.Set;
import java.util.HashSet;
import java.util.List;
import java.util.ArrayList;
import java.util.stream.Collectors;
import java.util.stream.IntStream;public class HotSearch {private static final String REDIS_HOST = "localhost";private static final int REDIS_PORT = 6379;private static final String HISTORY_SET = "history";private static final String ZSET_PREFIX = "zset:";private static final int TOP_TEN = 10;private static final String BAD_WORDS = "bad"; // 替换为需要过滤的关键词 private static final String FILTERED_WORD = "***"; // 替换为过滤后的关键词 private static final int BAD_WORD_THRESHOLD = 100; // 替换为过滤的阈值,超过则认为是不雅文字 private static final List<String> BAD_WORD_LIST = IntStream.range(0, BAD_WORDS.length()).mapToObj(i -> BAD_WORDS.substring(i, i + 1)).collect(Collectors.toList()); // 将BAD_WORDS转为List,方便后续操作 public static void main(String[] args) {Jedis jedis = new Jedis(REDIS_HOST, REDIS_PORT);String userId = "user1"; // 当前登陆的个人用户ID,需要根据实际情况获取 String searchWord = "test"; // 需要搜索的字符 hotSearch(jedis, userId, searchWord);}public static void hotSearch(Jedis jedis, String userId, String searchWord) {// 获取当前用户的搜索历史记录 Set<String> history = jedis.smembers(HISTORY_SET + ":" + userId);if (history == null) history = new HashSet<>();history.add(searchWord); // 将新搜索词加入历史记录 jedis.sadd(HISTORY_SET + ":" + userId, history); // 将历史记录存入redis中 history.remove(searchWord); // 去掉新搜索词,只保留旧的历史记录 // 将搜索词加入zset中,记录该字符被搜索的个数以及当前的时间戳 jedis.zadd(ZSET_PREFIX + userId, getScore(searchWord), searchWord);System.out.println("Added " + searchWord + " to hot search with score " + getScore(searchWord));// 过滤不雅文字,如果是不雅文字则替换为***,并累加不雅文字的搜索次数 if (BAD_WORD_LIST.contains(searchWord)) {if (jedis.zscore(ZSET_PREFIX + userId, FILTERED_WORD) == null) { // 如果该词在zset中不存在,则加入并设置得分 jedis.zadd(ZSET_PREFIX + userId, BAD_WORD_THRESHOLD, FILTERED_WORD); // 设置得分为BAD_WORD_THRESHOLD,表示这是一个不雅文字 jedis.incrBy(HISTORY_SET + ":bad", 1); // 累加不雅文字的搜索次数,存储在bad历史的集合中,方便后续统计和过滤处理 } else { // 如果该词在zset中已存在,则只累加搜索次数,并更新得分(得分+1) jedis.zincrby(ZSET_PREFIX + userId, 1, FILTERED_WORD); // 得分为当前得分+1,表示这是一个不雅文字的再次搜索 jedis.incrBy(HISTORY_SET + ":bad", 1); // 累加不雅文字的搜索次数,存储在bad历史的集合中,方便后续统计和过滤处理 }System.out.println("The word " + searchWord + " is filtered and replaced with " + FILTERED_WORD); // 输出过滤后的结果 } else { // 如果不是不雅文字,则正常加入热搜列表并设置得分 jedis.zadd(ZSET_PREFIX + userId, getScore(searchWord), searchWord); // 正常加入热搜列表并设置得分 System.out.println("Added normal word " + searchWord + " to hot search with score " + getScore(searchWord)); // 输出正常加入热搜列表的结果}// 获取平台上最热搜索的十条数据 Set<Tuple> hotData = jedis.zrevrangeWithScores(ZSET_PREFIX + userId, 0, TOP_TEN - 1);List<String> hotWords = hotData.stream().map(Tuple::getElement).collect(Collectors.toList());List<Integer> hotScores = hotData.stream().map(Tuple::getScore).collect(Collectors.toList());System.out.println("Top " + TOP_TEN + " hot searches are: " + hotWords + " with scores: " + hotScores);}// 用于计算得分的方法,这里采用了最简单的得分方式,只考虑了搜索频率和时间戳,实际情况可能需要更复杂的算法 private static int getScore(String word) {return 1;}
}
2.3 实现原理
- 搜索历史记录:
- 我们使用Redis的set数据结构来存储用户的搜索历史。每个用户都有自己的历史记录集合,通过
HISTORY_SET + ":" + userId来区分不同用户的搜索历史。 jedis.sadd方法用于添加新搜索词到历史记录集合中。- 删除操作没有直接在代码中体现,但可以通过
jedis.srem方法从集合中移除某个元素来实现。
- 我们使用Redis的set数据结构来存储用户的搜索历史。每个用户都有自己的历史记录集合,通过
- 更新热搜列表:
- 我们使用Redis的有序集合(zset)来存储热搜数据。每个用户都有自己的有序集合,通过
ZSET_PREFIX + userId来区分不同用户的热搜数据。 - 每个搜索词都与一个得分相关联,该得分由函数
getScore计算得出。新搜索词得分为1,旧搜索词得分为0。这个得分代表了搜索的频率和时间戳。 jedis.zadd方法用于向有序集合中添加新元素,并设置其得分。
- 我们使用Redis的有序集合(zset)来存储热搜数据。每个用户都有自己的有序集合,通过
- 获取平台上最热查询的十条数据:
- 我们使用
jedis.zrevrangeWithScores方法获取有序集合中的前十个元素(得分最高的十个搜索词)。 - 返回的结果是一个包含元素和得分的集合,我们通过流处理将其转换为列表。
- 我们使用
- 不雅文字过滤:
- 这部分功能在代码中有直接实现,其原理是当用户输入搜索词时,系统会检查该词是否在预定义的
BAD_WORDS列表中。 - 如果在列表中,并且该词的搜索频率超过
BAD_WORD_THRESHOLD,则认为这是一个不雅文字,将其替换为FILTERED_WORD。 - 注意:在实际应用中,可能需要更复杂的不雅文字过滤算法和策略,而不仅仅是基于频率的检查。
- 这部分功能在代码中有直接实现,其原理是当用户输入搜索词时,系统会检查该词是否在预定义的
3. 注意事项
- 安全性:
- 确保Redis服务器的安全性。这包括使用强密码、配置防火墙规则、使用SSL连接等。不要将敏感数据暴露给不必要的用户或应用程序。
- 在存储和传输用户搜索数据时,考虑到数据的机密性和隐私保护。根据当地的隐私法律和政策,可能需要采取额外的措施来保护用户数据。
- 性能监控和调优:
- 监控Redis的性能指标,如内存使用情况、连接数、查询速度等。根据实际负载情况,可能需要调整Redis的配置参数或增加硬件资源。
- 定期检查代码的性能,确保在大量请求下能够保持稳定的性能。对于瓶颈部分,可能需要优化算法或调整数据结构。
- 异常处理:
- 添加适当的异常处理逻辑,以处理Redis连接失败、查询错误等情况。确保应用程序能够优雅地处理这些异常,并为用户提供适当的错误消息。
- 对于可能出现的Redis故障或维护时段,考虑实现一种回退机制或通知系统,以便及时通知相关人员并采取措施。
- 数据一致性和备份:
- 确保Redis中的数据与应用程序中的其他数据源保持一致。在写入数据时,要确保幂等性以避免数据冲突。
- 定期备份Redis中的数据,以防数据丢失。考虑使用快照或追加日志的方式来备份数据。
- 扩展性和高可用性:
- 如果应用程序需要处理大量的搜索请求,考虑使用Redis集群来分担负载和提高可用性。确保集群配置正确,并能够自动处理节点故障转移。
- 在设计系统时,考虑到未来的扩展需求。使用可扩展的数据结构或算法,以便在需要时轻松地增加功能和优化性能。
- 日志和监控:
- 配置适当的日志记录系统,记录Redis的操作和关键事件。这有助于故障排查和性能分析。
- 使用监控工具来实时跟踪Redis的性能指标和应用程序的健康状况。这样可以在问题发生时迅速采取行动。
- 测试和验证:
- 在将代码部署到生产环境之前,进行充分的测试和验证。确保代码的功能正确、性能良好,并且没有安全漏洞。
- 考虑使用集成测试、单元测试和负载测试来评估代码的健壮性和稳定性。确保代码能够承受实际工作负载和各种边界条件。
- 代码维护和文档:
- 为代码添加适当的注释和文档,以帮助其他开发人员理解其工作原理和维护方式。这也有助于未来的代码审查和维护工作。
- 保持代码的清洁和可维护性,遵循最佳实践和编码规范。定期重构代码以消除冗余和提高可读性。
相关文章:
Java和Redis实现一个简单的热搜功能
1. 前言 我们有一个简单的需求: 搜索栏展示当前登陆的个人用户的搜索历史记录,删除个人历史记录。用户在搜索栏输入某字符,则将该字符记录下来 以zset格式存储的redis中,记录该字符被搜索的个数以及当前的时间戳 (用…...
超越传统,想修哪里就修哪里,SUPIR如何通过文本提示实现智能图像修复
项目简介 通过参数增加使得模型不仅能够修复图像中的错误或损坏,还能根据文本提示进行智能修复。例如根据描述来改变图像中的特定细节。这样的处理方式提升了图像修复的质量和智能度,使得模型能够更准确、更灵活地恢复和改进图像。 SUPIR的主要功能图像…...
《如何画好架构图》学习笔记
看了一堂《如何画好架构图》的公开课,结合网上的资料与经验做一些思考总结。文中的例子和图片大多是从课程中摘录的。 1. 4R架构定义 4R架构定义其实是软件架构定义经过归纳提炼后的简称。 软件架构定义:软件架构是指软件系统的顶层(Rank&am…...
redis整合
一.redis的发布订阅 什么 是发布和订阅 Redis 发布订阅 (pub/sub) 是一种消息通信模式:发送者 (pub) 发送消息,订阅者 (sub) 接收消息。 Redis 客户端可以订阅任意数量的频道。 1、Redis的发布和订阅 客户端订阅频道发布的消息 频道发布消息 订阅者就可以…...
开循环低温样品架节约液氦操作技巧
开循环低温样品架以降温快、无轰动源、重量轻、装置便利等特色遭到大多数客户的喜爱。但是制冷剂消耗量引起的运用本钱是客户在运用过程中zhong点重视的问题,特别是随着全球液氦价格继续飙升,开循环样品架的运用本钱也在逐渐添加,如何节约液氦…...
年薪30W+,待遇翻倍,我的经历值得每个测试人借鉴
从自考大专到出走公司,从半年无业露宿深圳北站,从8k…到11.5k…再到20k,我的经历值得每个测试人借鉴 或许学历并没有那么重要 12年高考之后,在朋友的介绍下(骗了过去),没有好好的读大学&#x…...
DEB方式安装elastic search7以及使用
参考:https://www.cnblogs.com/anech/p/15957607.html 1、安装elastic search7 #手动下载安装 wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.17.1-amd64.deb wget https://artifacts.elastic.co/downloads/elasticsearch/elastics…...
[Tomcat] [最全] 目录和文件详解
打开tomcat的解压之后的目录可以看到如下的目录结构: Bin bin目录主要是用来存放tomcat的命令,主要有两大类,一类是以.sh结尾的(linux命令),另一类是以.bat结尾的(windows命令)。 …...
微信小程序元素/文字在横向和纵向实现居中对齐、两端对齐、左右对齐、上下对齐
元素对齐往往是新学者的一大困惑点,在此总结常用的各种元素和文字对齐方式以供参考: 初始显示 .wxml <view style"width: 100%;height: 500rpx; background-color: lightgray;"><view style"width: 200rpx;height:100rpx;bac…...
兼容树莓派扩展模块,专注工业产品开发的瑞米派强势来袭
近日,米尔电子和瑞萨电子共同定义和开发了瑞萨第一款MPU生态开发板——瑞米派(Remi Pi)正式上市了!在各种Pi板卡琳琅满目的当下,Remi Pi是一款与众不同的开发板,他兼顾了严肃产品开发和爱好者创意实现两种需…...
云原生 - 微信小程序 COS 对象存储图片缓存强制更新解决方案
问题描述 遇到一个这样的情况:在微信小程序里图片缓存十分麻烦,网上很多说在腾讯云里的 COS 存储对象服务里设置对应的图片缓存(Header 头 Cache-Contorl),说实话真不好用,一会儿生效,一会儿没…...
设计公司设计ppt的优势—南京梵构广告
在这个时代的发展下,PPT软件越来越好用,投影仪越来越便宜,直接导致许多商界人士不再撰写文件了。他们只是在编写演示文稿,这些文稿只是些没有细节、缺乏支持的概要。许多人不喜欢撰写详尽文件所付出的脑力劳动。 视觉效果 一个好…...
gitlab设置/修改克隆clone地址端口
最近由于公司要停测试库云服务器? 什么?要停测试库服务器??? 是的! 你没听错。 真是醉了,多大的集团,为了省钱,也真是拼了, 作为开发人员,没有测试服务器,犹如断臂之人。 所以,在之前搭建环境的时候都没有写文档,今天算是弥补上,以后都可以作为参考了, …...
Jellyfin影音服务本地部署并结合内网穿透实现公网访问本地资源
文章目录 1. 前言2. Jellyfin服务网站搭建2.1. Jellyfin下载和安装2.2. Jellyfin网页测试 3.本地网页发布3.1 cpolar的安装和注册3.2 Cpolar云端设置3.3 Cpolar本地设置 4.公网访问测试5. 结语 1. 前言 随着移动智能设备的普及,各种各样的使用需求也被开发出来&…...
笨蛋学设计模式行为型模式-责任链模式【18】
行为型模式-责任链模式 8.5责任链模式:arrow_up::arrow_up::arrow_up:8.5.1概念8.5.2场景8.5.3优势 / 劣势8.5.4责任链模式可分为8.5.5责任链模式8.5.6实战8.5.6.1题目描述8.5.6.2输入描述8.5.6.3输出描述8.5.6.4代码 8.5.7总结 8.5责任链模式⬆️⬆️⬆️ 8.5.1概念 责任…...
【.NET Core】深入理解任务并行库 (TPL)
【.NET Core】深入理解任务并行库 (TPL) 文章目录 【.NET Core】深入理解任务并行库 (TPL)一、概述二、数据并行(任务并行库)三、Parallel.For 循环示例四、Parallel.ForEach 循环示例五、处理并行循环中的异常六、数据并行总结6.1 不要假定并行的速度始…...
win10安装redis并配置加自启动(采用官方推荐unix子系统)
记录,为啥有msi安装包,还这么麻烦的用linux版本redis的安装方式,是因为从github上下载别人制作的msi报毒,还不止一处,这种链接数据库的东西,用别人加工过的,都报毒了还用就是傻逼了。 所以采用…...
【大数据面试题】HBase面试题附答案
目录 1.介绍下HBase 2.HBase优缺点 3.介绍下的HBase的架构 4.HBase的读写缓存 5.在删除HBase中的一个数据的时候,它是立马就把数据删除掉了吗? 6.HBase中的二级索引 7.HBase的RegionServer宕机以后怎么恢复的? 8.HBase的一个region由哪些东西组成? 9.…...
SpringBoot中从HikariCP迁移到Oracle UCP指南
本博客文章的目标是作为从 HikariCP 和Oracle UCP(通用连接池)迁移的指南,因为它是连接到Oracle 数据库时的推荐方法。 HikariCP 简介 HikariCP是与 Spring Boot 应用程序一起使用的 JDBC 连接池。 简而言之,从 Java 开发人员的…...
第3章 接口和API设计
第15条:用前缀避免命名空间冲突 OC没有其他语言那种内置的命名空间机制。因此,我们在起名时要设法避免潜在的命名冲突,否则很容易就重名了。若是发生重名冲突,那么应用程序相应的链接过程就会出错。例如: 错误原因在…...
挑战杯推荐项目
“人工智能”创意赛 - 智能艺术创作助手:借助大模型技术,开发能根据用户输入的主题、风格等要求,生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用,帮助艺术家和创意爱好者激发创意、提高创作效率。 - 个性化梦境…...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...
iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...
【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...
centos 7 部署awstats 网站访问检测
一、基础环境准备(两种安装方式都要做) bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats࿰…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...
