核心需求

一个项目中,遇到了搜索热词统计的需求,我使用了 Redis 的五大数据类型之一 Sorted Set 实现。目前有两项数据需要统计:“当日搜索热词 top10”和“当周搜索热词 top10”。

关于这两项数据的统计方法,目前想到了两种实现方法:

  1. 两个 Redis 的 Sorted Set 实现,一个 Sorted Set A 统计当天,0 点 top10 记录进 MySQL,Sorted Set 清零。一个 Sorted Set B 统计当周,每周日 top10 记录进 MySQL,Sorted Set B 清零。
  2. 只使用用一个 Sorted Set 记录当天搜索热词,0 点 top10 记录进 MySQL,Sorted Set 清零。到周日时,会有 7 * 10 行记录。把这 7 * 10 行遍历,每次便利都记录进 Sorted Set,全部遍历结束后,再从 Sorted Set 中取出 top10 记录进 MySQL 的周热词统计表中。

Sorted Set 是 Redis 的数据结构,方法 1 会占用两份内存,一份当天的,一份当周的。方法 2 会提高系统的复杂度,并且在统计周表时,可能会出现短时间内大量的计算(当然可以使用定时任务,把周表的统计放到凌晨进行)。

最后选择了方案1,分开维护清晰明了。

至于内存占用问题,1MB = 1048576 字节,按两个字节存一个字算,理论上1MB 能存 1048576/2/8 = 65,536 个不重复的搜索关键词(当然使用Sorted Set肯定比纯字更多占用一些空间)。多投入一些内存,能存下的数量还是很大的,通常可以撑到每周结束清理内存。一般的 CRUD 项目不用怎么考虑内存占用。

问题中涉及的相关知识

一个项目中,遇到了搜索热词统计的需求。我使用了 Redis 的五大数据类型之一 Sorted Set 实现。

Redis 有序集合(sorted set)
Redis 有序集合和集合一样也是 string 类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个 double 类型的分数。Redis 正是通过分数来为集合中的成员进行从小到大的排序。
有序集合的成员是唯一的,但分数(score)却可以重复。
集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。 集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储 40 多亿个成员)。
定义出自:菜鸟教程

如上图,Redis 的 Sorted Set 自带排序功能。

操作方法也比较简单,在本项目中,核心是两个方法:

zincrby,对于一个 Sorted Set,存在的就把分数加 x (x 可自行设定),不存在就创建一个分数为 1 的成员。

zrevrange,查询Sorted Set中指定范围的值。返回的有序集合中,score 大的在前面。此方法无需担心用于指定范围的start和end出现越界报错问题。

在StringRedisTemplate中,Sorted Set被称为ZSet。更多redis (java客户端) 的Soeted Set使用方法请见:Redis之ZSet数据结构使用姿势

代码

service示例代码:

@Service("redisService")
public class RedisServiceImpl implements RedisService {@Autowiredprivate StringRedisTemplate redisTemplate;/*** 使用Sorted Set记录keyword* zincrby命令,对于一个Sorted Set,存在的就把分数加x(x可自行设定),不存在就创建一个分数为1的成员** @param keyword 搜索关键词*/@Overridepublic void searchZincrby(String keyword) {// 名为sortedSetName的Sorted Set不用预先创建,不存在会自动创建,存在则向里添加数据String sortedSetName = "searchHotWord";// x 的含义请见本方法的注释double x = 1.0;redisTemplate.opsForZSet().incrementScore(sortedSetName, keyword, x);}/*** zrevrange命令, 查询Sorted Set中指定范围的值* 返回的有序集合中,score大的在前面* zrevrange方法无需担心用于指定范围的start和end出现越界报错问题** @param start 查询范围开始位置* @param end 查询范围结束位置* @return*/@Overridepublic Set<ZSetOperations.TypedTuple<String>> queryTopSearchHotWord(Integer start, Integer end) {String sortedSetName = "searchHotWord";Set<ZSetOperations.TypedTuple<String>> resultSet =  redisTemplate.opsForZSet().reverseRangeWithScores(sortedSetName, start, end);return resultSet;}/*** 删除指定的key** @param keyName keyName*/@Overridepublic void deleteKey(String keyName) {redisTemplate.delete(keyName);}}

controller示例代码

@RestController
@RequestMapping("/redis")
public class RedisController {@Autowiredprivate RedisService redisService;/*** 测试redis记录keyword** @param keyword 搜索关键词* @return*/@GetMapping("/test_search")public ResultVO testSearch(@RequestParam("keyword") String keyword) {redisService.searchZincrby(keyword);// ResultVO和ResultVOUtil是自定义的class,为了方便展示结果,阅读时忽略即可return ResultVOUtil.success(1, "test-return");}/*** 测试redis查询指定范围的热词** @param start 查询范围开始位置* @param end 查询范围结束位置* @return*/@GetMapping("/test_query_top_search_hot_word")public ResultVO testQueryTopSearchHotWord(@RequestParam("start") Integer start,@RequestParam("end") Integer end) {Set<ZSetOperations.TypedTuple<String>> resultSet =  redisService.queryTopSearchHotWord(start, end);// ResultVO和ResultVOUtil是自定义的class,为了方便展示结果,阅读时忽略即可return ResultVOUtil.success(1, "success", resultSet);}/*** 删除指定的key** @param keyName keyName* @return*/@PostMapping("/delete_key")public ResultVO deleteKey(@RequestParam("keyName") String keyName) {redisService.deleteKey(keyName);// ResultVO和ResultVOUtil是自定义的class,为了方便展示结果,阅读时忽略即可return ResultVOUtil.success(1, "test-return");}}

测试代码的运行效果

模拟搜索一些keyword:

使用rdm查看reids的存储情况,搜索热词已经存在redis一个名为searchHotWord的Sorted Set中:

查询结果:

One more thing

zrevrange方法无需担心用于指定范围的 startend 出现越界报错问题。

测试用的Sorted Set总共有8个数据,故意指定 startend 在此长度范围之外:

经测试,在保证 startend 均 >=0 的前提下,startend 均无越界报错问题。

redis 实现搜索热词统计相关推荐

  1. java 热词推荐搜索实现,Redis 与搜索热词推荐

    本文解决一个非常普通的需求:在用户输入搜索关键词的过程中,系统给出搜索的推荐关键词. 实现的方式还是通过 redis,这次使用它 5 种数据结构中的 zset,也就是有序集合. Redis的有序集合( ...

  2. spark 项目应用-topn搜索热词统计

    本文章通过spark读取hive数据,分析top热点搜索词 import java.util.ArrayList; import java.util.Arrays; import java.util. ...

  3. java 热词推荐搜索实现,Flink 热词统计(1): 基础功能实现

    本系列文章将从热词统计需求讲起,讲解flink在实际项目中的应用.部署.容错.项目中的代码为scala所编写,没有用 java 的原因是scala语言看起来更加简练,同时与java语言的兼容性较好,可 ...

  4. 结对第一次—原型设计(文献摘要热词统计)

    课程 软件工程1916|W(福州大学) 作业要求 结对第一次-原型设计(文献摘要热词统计) 结对学号 221600426     221600401 原型设计工具 墨刀 原型浏览 点击浏览 作业目标 ...

  5. 结对第二次—文献摘要热词统计及进阶需求

    课程链接:软件工程1916|W(福州大学) 作业要求:结对第二次-文献摘要热词统计及进阶需求 结对学号:221600205 | 221600207 作业目标1:一.基本需求:实现一个能够对文本文件中的 ...

  6. Flink学习笔记(八):flink热词统计

    我们在网页上经常可以看到比如 百度热榜,微博热搜 这样的排行数据,那么我们在进行网络搜索的时候如何统计这些数据呢? 热词统计有很多中方法,这里主要记录下flink如何进行热词统计. 一.场景 小白在网 ...

  7. kafka jar包_Windows环境下Flink消费Kafka实现热词统计

    前言碎语 昨天博主写了<windows环境下flink入门demo实例>实现了官方提供的最简单的单词计数功能,今天升级下,将数据源从socket流换成生产级的消息队列kafka来完成一样的 ...

  8. Python爬虫-某跨境电商(AM)搜索热词

    前言 本文是该专栏的第42篇,后面会持续分享python爬虫干货知识,记得关注. 关于某跨境电商(AM),本专栏前面有单独详细介绍过,获取配送地的cookie信息以及商品库存数据,感兴趣的同学可往前翻 ...

  9. 推荐系统系列 - 实例一 - 基于流行度的算法 - 搜索热词推荐

    目录 背景 基础知识 数据清洗 计算热度推荐词 查看结果 背景 在新的系统里面,早期都是没有很多数据,很难直接拿来做推荐系统,这就是有些算法存在冷启动的问题,所以在系统早期推荐都是基于热度(流行度)或 ...

最新文章

  1. Java同一个类的不同实例_如何创建2个类实例注入不同类的依赖项实现(通过guice)?...
  2. python3 telnetlib实现telnet客户端
  3. 设计模式复习-模板方法模式
  4. Java中的Iterable与Iterator详解
  5. 027_jdbc-mysql几个常用的日期类型
  6. vue 父向子组件传递数据,子组件向父组件传递数据方式
  7. 【Linux】基础每日一命之cutmvscp命令
  8. 解决VsCode中C程序无法键盘输入的问题
  9. 《黑马程序员》 block的使用(Objective - c语法)
  10. JPA还是JDBC?
  11. 工作流牛人 Jan Mendling
  12. 远场语音是什么鬼?和人工智能有什么关系?
  13. C#之四十二 C# 读写文本文件乱码解决方案
  14. 14_星仔带你学Java之Java编码规范、常用类
  15. 软件测试 查看网页打开时间,网页响应时间101(一)
  16. 中国计算机设计大赛蔡思琦,建策杯2018年江苏省大学生计算机设计大赛.PDF
  17. 高等代数 具有度量的线性空间(第10章)2 实内积空间
  18. ==与equest的区别
  19. Linux图形化磁盘管理工具gparted
  20. 计算机ipad手机组成,如何为自适应手机,计算机和iPad制作网页的摘要

热门文章

  1. 数据库设计之逻辑设计
  2. mysql事务及其实现原理--MVCC--二阶段提交
  3. 苹果无法安装计算机,“windows 无法更新计算机的启动配置。安装无法继续”这样解决...
  4. linux 中 vim/vi的常用命令
  5. Intermediate Python - Python 进阶
  6. 零基础大学生怎么样自学软件开发?
  7. python爬取大众点评网商家信息以及评价,并将数据存储到excel表中(源码及注释)
  8. CSS - 预处理器SCSS
  9. 微信小程序家政服务系统设计与实现
  10. 如何轻松彻底卸载电脑软件