热门搜索分析

8 篇文章 0 订阅
热门搜索分析:
	首先说下,我能想到的:

		1.一般是 mysql 存储

			1>创建数据表
				hot_keywords - 热门关键字表
					id
					identifier - 标识类型:fulltime - 全职 | parttime - 兼职 ...
					keyword - 关键字
					count - 统计次数
					created_at 
					updated_at

			2>每次用户搜索一次,首先查询数据库中,有无对应的关键字
				不存在 - 新建&次数+1,
				存在 - 次数+1

			3>页面展示热门关键字
				查询 hot_keywords,count 倒序,列出指定条数即可

		2.我们都知道优化,纯 mysql 方式,是不是有点不够优化,就想到能否借助缓存,一般就是 redis 了。

			点击热门标签,进行搜索,或者通过搜索框,进行搜索。这种频率是否会很高,不断的更新表,会不会影响性能。所以,考虑是不是可以借助 redis,来稍微延迟下更新到 mysql。(我从来没有做过此方面测试,包括所有自以为的或者听网上别人说的优化,所以这只是我自己这么想的,没有更高级的思维!适合新手)

			我们这里强调下:
				我们这里的方案,主要还是以 mysql 来存储,只是不那么频繁更新 mysql,而是通过 redis 来存储,10分钟(或其他时间)来执行一次
				10分钟执行一次,就需要使用 '计划任务'。

			1>上面的 hot_keywords 仍旧需要创建

			2>redis 这块考虑怎么设计
				我们需要记录的内容很简单,就是 10 分钟有效期内的:
					identifier - keyword - count
				哪个类别下,关键字的次数

				对于每个类别,我们可以单独命名为一个 key,例如:hot_keywords_fulltime | hot_keywords_parttime
				该 key 下,我们存储 keyword - count 的映射表,最适合我们的数据结构是:hash

				我们可以存储:
					HINCRBY hot_keywords_fulltime keyword 1

			3>redis 这里的逻辑实现
				10分钟内,只要有用户搜索,redis 执行上述命令即可。我们根据业务,可能有多个 identifier 的 hash
					HINCRBY hot_keywords_fulltime keyword1 1
					HINCRBY hot_keywords_fulltime keyword2 1
					...

					HINCRBY hot_keywords_parttime keyword1 1
					HINCRBY hot_keywords_parttime keyword2 1
					...


				到达10分钟,我们执行任务计划。
					1.获取所有的 hash,使用 HGETALL 获取所有的元素(这里以 PHP 为例,得到一个数组)
						$redis_hot_keywords = [
							'keyword1' => 2,
							'keyword2' => 1,
							'keyword3' => 3,
						];

					2.获取所有的 keyword
						$all_keywords = array_keys($redis_hot_keywords);
						$sql = 'select keyword from hot_keywords where keyword in (' . trim(join(',', $all_keywords), ',') . ')';
						获取已经存在在数据库中的所有的 keyword,$exists_keywords = [];

						// 拼接
						$batch_execute_sql = '';
						foreach($redis_hot_keywords as $keyword => $count){
							if(in_array($keyword, $exists_keywords)){
								$batch_execute_sql .= "update hot_keywords set count = count + {$count} where identifier = '{$identifer}'' and keyword = '{$keyword}';";
							}else{
								$batch_execute_sql .= "insert info hot_keywords (identifier, keyword, count) values('{$identifier}', '{$keyword}', 1);";
							}
						}
						执行 $batch_execute_sql;

					3.直接删除 redis 中相关的 key
						DEL hot_keywords_fulltime, hot_keywords_parttime, ...

		/*
			对于,方法1和2,我们只考虑的是 "插入",对于 "查询",我们是不是应该也可以优化。
			另外,当我不断更新表,每次访问页面,都会展示 "查询" 结果,每次都去查询数据库,是不是也有点不优化。
			主要是这个数据,不是核心的,有些延迟、误差都没大的关系。
			所以,考虑,再添加额外的查询的缓存:
				hot_keywords_show - 最终展示的 keyword 列表(可以设置10分钟更新一次)

			对于方法1:
				添加个任务计划,10分钟执行一次,mysql 获取最多次数的keyword,然后插入到 redis 中

			对于方法2:
				我们已经有10分钟,执行批量插入的任务计划了,待插入结束后,执行一次 redis 缓存更新即可。

			另外,对于数据不足,或者还没有 keyword 数据,我们应该默认的 keyword 列表。这应该是 10分钟计划任务时,进行判断。

				1>默认关键字,假设8个:
					keyword1, keyword2, ...
				2>查询数据库,发现就3个关键字,或者发现,关键字搜索的次数,才1、2次,这种随机性太高,我觉得不适合作为通用的 keyword,所以,还得设置个标准,达到 100次,或50次以上,才能作为 keyword。查询 count >= 50 的 keyword ,不断的替换了 默认关键字
				3>插入到 hot_keywords_show 中,数据结构随便定义,简单的话,直接使用 string。8个 keyword,用 ',' 分割即可
		 */


		3.不使用 mysql,完全使用 redis
			因为要进行排序,为了方便,我们直接使用 'zset' 数据类型(使用 list 应该也可以,自己维护一个有序的列表,只是猜想)

				ZINCRTY hot_keywords_fulltime 1 keyword1
				ZINCRTY hot_keywords_fulltime 1 keyword2
				...

				ZINCRTY hot_keywords_parttime 1 keyword1
				ZINCRTY hot_keywords_parttime 1 keyword2
				...

			获取关键字时,我们可以使用:
				ZREVRANGE hot_keywords_fulltime 0 8			// 按 count 倒序,获取前8个 keyword


	请教了个大神,人家简单给了个思路,直接就是从 "性能"、"算法" 出发的,下面简述下大神的思路:

		/*
			问题是这样,你每个用户来访问的时候。你都需要把 redis 里面的所有数据取出来,然后做排序。。。如果量大的话。。。你的性能会有问题

			如果你了解过算法的话。。。你应该明白 排序是一个比较复杂的计算

			所以不是你用户量的问题,而是搜索量的问题,所以不要排序(我说了句,用户量比较少)

			建议不要使用redis 的 zset 进行排序

			比如说你有
				标签 1 --- 搜索次数 7
				标签 2 --- 搜索次数 6
				标签 3 --- 搜索次数 5

				现在我们只要两个热门搜索,那当前的搜索阈值是 6

			你现在需要更新维护的就是 索引阈值 以及 热门搜索数量

			把排序的复杂度降低

			这样对于 空间 和 时间 都是最节省的

			你可以先抛开 redis

			你会更明白

			就是简单的数据结构

			比如说你只需要 10 个热门搜索,你有一堆数据

			你的原始数据应该是个数组:[]
			然后你有一个变量来存目前的阈值 var
			最后你需要维护一个 10 个的热门搜索,这个也是一个数组:[]

			这个还可以优化的,不过留给你自己去想了。你可以把这个 10 个热门搜索的数组变成一个 hash map {}

			我只是帮你 预见一些问题。。。然后在工程复杂度增加不到的情况下 可以尽量避免掉
		*/

	大家可能不太理解说的啥,没有我问的上下文。简单说下,大神的思路:
		尽量少用排序,不管是 mysql,还是 redis,排序是一个及其耗费性能的操作
		对于我们只需 "热门标签",这个其实,就顶多几个最热的标签,而不是 "排行榜",非得全部进行排序。
		我们仅仅只需要维护一个 10 个左右的热门标签数组,参与排序的元素就这么 10 个左右,性能会大大提升!

		分析后,该功能的实现,必须具备2个因素:
			1.记录阈值,可以理解为,成为热门标签,最少的点击次数
			2.热门标签的点击次数,要>=阈值,这个对于我们的数据库,至少具有筛选功能。

		实现难度:	
			1.筛选功能的话,感觉 redis 并没有适合的数据类型,没看到提供的方法。mysql 只需要一个 where 语句,就可以筛选出来!
			2.这个 "阈值",这个思考了下,可能可以通过程序逻辑,可以实现,但是估计异常复杂...,我感觉还不如直接排序简单...

		这里,我就不再继续研究了,完全没看过算法,水平有限,另外平台用户量也很小,还不是特别注重性能的阶段...

此外,对于热门关键字,我们还需要考虑:
	关键字的要求,哪些搜索,可以作为关键字!
	过长、过短,是不是词,等等,就是关键字的要求。
	以及和时间相关联上,可能是最近 3 天或最近 7 天的热门关键字等等(这就需要添加时间了关联了,主要是 redis,我们可以将之前的 key 稍微改造:2017_07_23:hot_keywords_fulltime)

参考下面这篇文章,提到的:
	http://qb.doudang.com/www/doc/view/?doc_id=2371

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值