热门搜索分析:
首先说下,我能想到的:
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