背景
在我的网站中,用户正在创建自己的社交网络。这会导致通知飞到网络中的相关节点。例如。朋友请求,喜欢,评论,都为网络中的相关节点生成通知。
为了保持一切透明,用户可以在单独的网址中将其相关通知视为列表。此列表由名为ss:<user_id>
的redis支持的有序集提供支持。有序集包含hash ids
,以及自纪元以来的时间(作为score
)。例如:
hash_id | updated_at
np:1:0:544 | 1482234321.48124
np:1:2:454 | 1482235629.73111
np:1:1:701 | 1482237000.59143
此外,每个通知都是看到或看不见。此seen
状态存储在密钥s
的相关哈希中。例如。哈希s
中的np:1:0:544
键为False
;告诉我们这是一个看不见的通知。很简单。
挑战:
挑战在于计算超出预定义纪元时间的所有看不见的通知。此时间存储在名为cut-off
的单独计数器中。
我现在在做什么:
1)获取ss:<user_id>
的所有hash_ids,得分高于cut-off
。例如。 ZRANGEBYSCORE ss:<user_id> (cut-off +inf
(用redis的说法)。
2)遍历每个hash_id,检查它的s
密钥(即seen
密钥)。如果s
为False
,请递增计数器。例如。为每个哈希对象执行HGET hash_name s
。如果返回值为False
,则incr
为单独的redis计数器。
步骤1的时间复杂度为O(log(N)+M)
。第2步的结果是O(M)
。它最多可以是O(N)
我需要改进的地方:
我能以更短的时间复杂度(例如O(log(N)
)做到这一点吗?例如。通过使用复合索引和词典排序?
表现至关重要;这个计算每天在我的网站上发生约200万次(并且扩大规模),所以我正在寻找提高可扩展性的方法。
注意:我当然可以采取其他措施来减轻这种算法的负担(例如降低其发生率,改善基础设施等),但这些是不同的考虑因素。
答案 0 :(得分:0)
我改变了方法。
排序集的score
(即updated_at
)现在为time.time()+SEEN[status]
SEEN={True:2000000000,False:4000000000}
。这会自动按看到和看不见对键进行排序,同时保留时间信息(由score-SEEN[status]
获得)。
总的来说,这种方法使我能够从计算中删除第2步。时间复杂度降至O(log(N))。最重要的是,指数的智能制定可以真正推动绩效。对于任何有兴趣的人,here's an informative read关于复杂索引如何能够完成各种事情。