【问题标题】:Best solution for finding 1 x 1 million set intersection? Redis, Mongo, other寻找 1 x 100 万个交叉点的最佳解决方案? Redis、Mongo、其他
【发布时间】:2012-06-21 03:49:56
【问题描述】:

大家好,提前致谢。 我是 NoSQL 游戏的新手,但我目前的工作地点要求我对一些大数据进行设置比较。

我们的系统有客户标签集和目标标签集。 标签是一个 8 位数字。
一个客户标签集最多可以有 300 个标签,但平均有 100 个标签
一个目标标签集最多可能有 300 个标签,但平均有 40 个标签。

预计算不是一种选择,因为我们正在为 10 亿用户的潜在客户群进行拍摄。

(这些标签是分层的,所以有一个标签意味着你也有它的父标签和祖先标签。暂时把这些信息放在一边。)

当客户访问我们的网站时,我们需要尽快将他们的标签集与一百万个目标标签集相交。客户集必须包含要匹配的目标集的所有元素。

我一直在探索我的选择,Redis 中设置的交集似乎是理想的。然而,我在互联网上的拖钓并没有透露需要多少内存才能容纳一百万个标签集。我意识到交叉路口会很快,但这是 Redis 的可行解决方案。

我意识到这是蛮力和低效的。我还想用这个问题来获得有关过去处理此类问题的方法的建议。如前所述,标签存储在树中。我也开始将 Mongodb 视为一种可能的解决方案。

再次感谢

【问题讨论】:

  • 这是典型的存储/内存使用与处理时间的两难选择,不是吗?您可以计算标签更新的结果标签集、存储它并更快地提供它,或者在真正需要数据时进行动态计算。如果标签更新不常见,您可以考虑选择第​​一个选项,或者考虑使用集群数据库选项(例如,Clustrix)
  • 谢谢。我应该指定的。我们目前预先计算,但如果我们作为一家公司取得成功,我们可能会寻找十亿潜在客户。我将审查 Clusterix
  • Mongodb 不提供集合交集。如果你有一些 RAM(比如 100+ GB),你可以在 redis 中存储相当多的键 :)
  • 正如其他人所提到的,MongoDB 在快速交叉方面没有什么特别之处。 Redis 有很好的集合支持,但是对于快速交叉点没有什么特别的,例如 bitset 交叉点等。例如,查看 Lucene/Solr 的快速实现(您可以将其用作参考)。内存方面:1 百万标签是 1 百万比特,+ 一次包含 1 百万标签的哈希图。所以这应该是可行的:)。 +
  • Redis 具有高效的 intset 数据结构,多个集合的智能交集算法,如果需要可以使用 BITOP 命令操作位集 (redis.io/commands/bitop)

标签: mongodb redis bigdata nosql


【解决方案1】:

这是一个有趣的问题,我认为 Redis 可以在这里提供帮助。

Redis 可以使用优化的“intset”格式存储整数集。请参阅http://redis.io/topics/memory-optimization 了解更多信息。

我相信这里正确的数据结构是目标标签集的集合,加上将标签映射到目标标签集的反向索引。

存储两个目标标签集:

 0 -> [ 1 2 3 4 5 6 7 8 ]
 1 -> [ 6 7 8 9 10 ]

我会使用:

 # Targeted tag sets
 sadd tgt:0 1 2 3 4 5 6 7 8
 sadd tgt:1 2 6 7 8 9 10
 # Reverse index
 sadd tag:0 0
 sadd tag:1 0
 sadd tag:2 0 1
 sadd tag:3 0
 sadd tag:4 0
 sadd tag:5 0
 sadd tag:6 0 1
 sadd tag:7 0 1
 sadd tag:8 0 1
 sadd tag:9 1
 sadd tag:10 1

当从系统中添加/删除目标标签集时,这个反向索引很容易维护。

全局内存消耗取决于多个目标标签集共有的标签数量。在 Redis 中存储伪数据并模拟内存消耗非常容易。我已经使用simple node.js script 完成了它。

对于 100 万个目标标签集(标签为 8 位数字,每组 40 个标签),当目标标签集共享的标签很少时,内存消耗接近 4 GB(反向索引中超过 32M 的条目),并且当标签被大量共享时大约 500 MB(反向索引中只有 100K 条目)。

使用这种数据结构,查找包含给定客户的所有标签的目标标签集非常有效。

1- Get customer tag set (suppose it is 1 2 3 4)
2- SINTER tag:1 tag:2 tag:3 tag:4
   => result is a list of targeted tag sets having all the tags of the customer

交集操作是高效的,因为 Redis 足够聪明,可以按基数对集合进行排序,并从具有最低基数的集合开始。

现在我知道您需要实施相反的操作(即找到目标标签集,其所有标签都在客户标签集中)。反向索引仍然可以提供帮助。

这里是一个丑陋的伪代码示例:

1- Get customer tag set (suppose it is 1 2 3 4)
2- SUNIONSTORE tmp tag:1 tag:2 tag:3 tag:4
   => result is a list of targeted tag sets having at least one tag in common with the customer
3- For t in tmp (iterating on the selected targeted tag sets)
      n = SCARD tgt:t (cardinality of the targeted tag sets)
      intersect = SINTER customer tgt:t
      if n == len(intersect), this targeted tag set matches

因此,您无需针对 1M 目标标签集测试客户标签集。您可以依靠反向索引将搜索范围限制在可接受的范围内。

【讨论】:

  • 顺便说一句,我从来没有评论过。很棒的答案。非常感谢。我已经成功使用了一个月了。
  • 我对它的性能感兴趣。这是实时的吗?
  • 很棒的答案!也许你也知道如何帮助这个? :) stackoverflow.com/questions/37986935/…
【解决方案2】:

这可能会有所帮助:

案例研究:在非常大的集合上使用 Redis 相交(120M+ 和 120M+)

http://redis4you.com/articles.php?id=016&name=Case+Study%3A+Using+Redis+intersect+on+very+large+sets

【讨论】:

【解决方案3】:

最初提供的答案对我有所帮助。然而,随着我们客户群的增长,我偶然发现了一项很棒的技术,它涉及使用 redis 字符串位和位运算符来非常快速地对数亿用户执行分析。

查看这篇文章。 Redis 的创建者 Antirez 也经常引用这一点。

http://blog.getspool.com/2011/11/29/fast-easy-realtime-metrics-using-redis-bitmaps/

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-11-11
    • 1970-01-01
    • 2012-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多