Rumah > Soal Jawab > teks badan
使用数据库MySQL(innodb)
相关表设计最大数据量:5000w
假定表news,拥有以下字段:
id int auto_increment,
title varchar(2000) not null default '' comment '标题',
score int not null default 0 comment '基础分值',
visited int not null default 0 comment '展示次数',
voted int not null default 0 comment '投票数',
//hot int not null default 0 comment '热度', 不再作为独立字段,而是在select的时候来计算
created int not null default 0 comment '创建Unix时间戳',
primary key(id),
key score(score),
key visted(visited),
key voted(voted),
key created(created)
其中,hot字段的值是结合visited、voted计算并随着时间衰减的,衰减频率最短为1小时(即间隔1小时就需要根据当前时间戳与created的差值做一次衰减)。数据主要根据hot字段的值来排序展示的,因此需要保证整表hot数据的更新。
另外,我还需要记录一个hot的历史最高值。(补充)hot值有最大限制,不能超过100。
难点:如果独立一个hot字段,数据量大了之后,衰减更新的效率将非常之低并影响系统整体性能;如果另外设一个完全不包含衰减的分数值字段score,需要展示的时候实时再实时计算hot的值又怕SQL执行效率太低。
目前后者的效率肯定更高,不知道各位大神有没有做过类似的需求,有没有更好的方案,求解!
确定在visit和vote操作时更新递增的score值,然后在SELECT列表的时候实时计算经过时间衰减的hot值,对于提取的数据先通过where条件缩小范围,结果进行一定时间的cache缓存。感谢大家!
巴扎黑2017-04-17 11:18:23
这种设计有点让人迷惑,我在想为啥要设计衰减这个操作啊,如果时间因子是T
的话,完全可以设计类似的公式啊
hot = f(visited) * f(voted) * T
越新的内容T
肯定越大,所以即使他们的visited
和voted
相同,它的hot
值也会大些,如果你不希望时间因子的扰动有这么大的话也可以
hot = f(visited) * f(voted) + f(T)
这样hot值只需要一次计算就行了,不需要实时更新,因为你已经把时间因子设计到它里面了
怪我咯2017-04-17 11:18:23
我会展示的时候再实时计算hot的值,这样不受一小时的粒度限制,排序可以更实时地变化。
如果效率太低,我就把最终考虑所有因素后生成的结果缓存起来。
另:有种暗暗的感觉,题主一定是深受《基于用户投票的排名算法》系列文章毒害颇深。
黄舟2017-04-17 11:18:23
很奇怪的做法,这个hot就不应该和原始数据放到一起,笨一点就用一个专用slave表每小时sql排序一次,彻底一点就单写一个模块去随时更新每个条目的hot值,存到另外一个地方供读取用。