tko*_*wal 20 algorithm set storing-data data-structures
我有数据库,用户订阅主题.目前,SQL数据库中存储了大约20 000个主题,20万个用户和200万个订阅.由于它的大小,数据库按主题分区,因此我无法在一个数据库查询中获取信息.有几个主题有10万个订阅,一对有10万,其他有数百或更少.
当一个事件发生时,它通常匹配几个主题,所以为了通知用户,我需要执行查询,例如"给我所有用户订阅主题x,y,z并执行集合的联合",以便一个用户获得新闻即使他同时订阅了主题x和z.
限制是:
我想过为每个主题使用一组布隆过滤器,但是它们的约束是相反的:"用户要么没有订阅肯定,要么可能订阅".我需要一些类似"用户订阅肯定或可能不是"的内容.
有损哈希表可能是个好主意,但我不确定,如果它们可以像布隆过滤器那样具有内存效率,而且我担心它会永远是同一个用户,那就是缺少他主题中的内容.
你知道其他任何数据结构,这对解决这个问题有好处吗?
这可能不是您正在寻找的解决方案,但您可以利用 ElasticSearch 的术语过滤器并为每个用户提供一个如下所示的文档:
{
"id": 12345,
"topics": ["Apache", "GitHub", "Programming"]
}
Run Code Online (Sandbox Code Playgroud)
术语过滤器直接响应“哪些用户订阅了至少其中一个主题”的查询,ES 在如何缓存和重新利用过滤器方面非常聪明。
它不是概率数据结构,但可以非常有效地解决这个问题。您需要使用scan api来序列化检索可能较大的 JSON 响应。如有必要,您可以将此解决方案扩展到分布在多台计算机上的数十亿用户,并且响应时间为 10 - 100 毫秒。您还可以找到主题之间的相关性(重要术语聚合)并使用 ES 作为进一步分析的引擎。
编辑:我在 Python 中实现了搜索和扫描/滚动 API 的使用,并得到了一些有趣的结果。我对这 2000 万个用户和 2 亿个订阅数据集进行了“订阅任意三个主题的用户”查询,一般来说,搜索本身会在 4 - 8 毫秒内完成。查询返回 350.000 - 750.000 个用户。
即使使用扫描/滚动 API,从 ES 中获取用户 ID 也会出现问题。在 Core i5 上,我似乎每秒只有 8200 个用户,因此不到 50 万/分钟(带有"_source": false)。查询本身如下所示:
{
"filtered": {
"filter": {
"terms": {
"topics": [ 123, 234, 345 ],
"execution": "plain",
"_cache": false
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
在生产中,我将使用"execution": "bool"这样的方式,以便可以缓存部分查询结果并在其他查询中重新利用。我不知道获取结果的瓶颈是什么,服务器的 CPU 使用率为 50%,我在同一台机器上运行客户端的 python 脚本,利用elasticsearch.helpers.scan.