我应该比较每对套装吗?(如果我保留一个将用户 ID 映射到设置成员资格的数据结构,则没有必要。)
为了计算交集度,你仍然需要访问用户拥有的其他组,仍然是三次方。您可以有一个哈希表或其他稀疏数组来计算,但它最多仍需要为每个用户所在的每对组的每个用户增加一个增量。如果您在 G 个组中有 N 个用户,平均每个用户有 S 个用户group 和 T 每个用户所在的组数,如果你有一个用户到组的索引,你有 G G S/2 用于比较每对组和 N T T。T = G S/N,所以 N T T=G G S序号;对于 S = 20 和数百万的 N 应该有优势。不幸的是,您还需要至少 G*G 存储来存储交集计数(对于 4 位非稀疏计数器,需要 25 TB 左右),并且必须确保结构可以并行递增。
对于 1000 万个 20 个组中的 100 万个用户,一个用户在给定组中的概率非常近似为 2e-6,两个组共享用户的概率为 40e-6,因此 25TB 降为 1GB数据,因此对于普通大小的计算机上的稀疏数组来说并非不可能。
但是,将 20 个元素的集合与 15 个共同元素进行比较具有更明显的优化
- 如果对组进行了排序,则不需要工作存储,只需直接输出输入组之间的差异程度即可。
- 大多数内存访问在连续的内存区域中是线性的,结果仅取决于被比较的两组,而不是依赖于整个数据集的总和。随机访问主存比线性访问慢得多。使用总线锁随机更改主内存比在无需锁定总线的情况下访问缓存要慢几个数量级(尽管如果每个内核有几个 GB,则可以使用 user->group 方法而无需进行任何同步)。
- 只需要计算集合之间不同的5个元素;如果数据是随机的,那么大多数集合将是不相交的,因此访问的元素的平均数量较小。
- You can quickly discount certain groups by treating the difference as a distance (if A is 11 different from B, and C is 5 different from B, then C is between 6 and 16 different from A, so can be discounted without comparing A and C directly). Since most the sets are completely disjoint, this won't gain you much though.
There is also the option of a hybrid approach, using the user->group map to prune the set of group to group comparisons to be made. This has the advantage of not requiring incrementing of a shared data structure:
- for each pair of groups that a user is in, add that pair to the list to investigate.
- sort the list of pairs of groups with at least one user in common.
- the number of times each pair occurs in the list is the number of users they have in common.
Using merge sort, this is very each to parallelise into pure streaming units. You would be sorting around 20*200*10 million/2 = 20 billion group ID pairs (each group of 20 users times the number of groups each user is in/2).