我希望得到一个快速的近似集合成员资格,基于应用于字符串向量的大型Spark RDD(~1B记录)的字符串值函数。基本上这个想法是减少到Bloom filter。然后可以将这个布隆过滤器广播给工人以供进一步使用。
更具体地说,我目前有
rdd: RDD[Vector[String]]
f: Vector[String] => String
val uniqueVals = rdd.map(f).distinct().collect()
val uv = sc.broadcast(uniqueVals)
但uniqueVals
太大而不实用,我想用更小(和已知)尺寸的东西代替它,即布隆过滤器。
我的问题:
是否可以缩减为Bloom过滤器,或者我必须先收集,然后在驱动程序中构建它?
是否有适合此的成熟Scala / Java Bloom过滤器实现?
答案 0 :(得分:10)
是的,Bloom过滤器可以减少,因为它们有一些不错的属性(它们是monoids)。这意味着您可以并行执行所有聚合操作,只对数据进行一次有效传递,为每个分区构建BloomFilter,然后将这些BloomFilter一起减少,以获得可以查询contains
的单个BloomFilter。 / p>
Scala中至少有两个BloomFilter实现,它们似乎都是成熟的项目(实际上并没有在生产中使用它们)。第一个是Breeze,第二个是Twitter's Algebird。两者都包含不同草图的实现以及更多。
这是一个如何使用Breeze执行此操作的示例:
import breeze.util.BloomFilter
val nums = List(1 to 20: _*).map(_.toString)
val rdd = sc.parallelize(nums, 5)
val bf = rdd.mapPartitions { iter =>
val bf = BloomFilter.optimallySized[String](10000, 0.001)
iter.foreach(i => bf += i)
Iterator(bf)
}.reduce(_ | _)
println(bf.contains("5")) // true
println(bf.contains("31")) // false