在进行研究时,我发现删除Spark RDD中的所有子集有点困难。
数据结构为RDD[(key,set)]
。例如,它可能是:
RDD[ ("peter",Set(1,2,3)), ("mike",Set(1,3)), ("jack",Set(5)) ]
由于mike (Set(1,3))
的集合是彼得(Set(1,2,3))
的子集,我想删除" mike",最终会以
RDD[ ("peter",Set(1,2,3)), ("jack",Set(5)) ]
很容易在本地python中实现两个" for"循环操作。但是当我想用scala和spark扩展到云时,找到一个好的解决方案并不容易。
由于
答案 0 :(得分:1)
这可以通过使用RDD.fold
功能来实现
在这种情况下,所需的输出是超集项的“列表”(ItemList)。为此,输入也应转换为“List”(ItemList的RDD)
import org.apache.spark.rdd.RDD
// type alias for convinience
type Item = Tuple2[String, Set[Int]]
type ItemList = List[Item]
// Source RDD
val lst:RDD[Item] = sc.parallelize( List( ("peter",Set(1,2,3)), ("mike",Set(1,3)), ("jack",Set(5)) ) )
// Convert each element as a List. This is needed for using fold function on RDD
// since the data-type of the parameters are the same as output parameter
// data-type for fold function
val listOflst:RDD[ItemList] = lst.map(x => List(x))
// for each element in second ItemList
// - Check if it is not subset of any element in first ItemList and add first
// - Remove the subset of newly added elements
def combiner(first:ItemList, second:ItemList) : ItemList = {
def helper(lst: ItemList, i:Item) : ItemList = {
val isSubset: Boolean = lst.exists( x=> i._2.subsetOf(x._2))
if( isSubset) lst else i :: lst.filterNot( x => x._2.subsetOf(i._2))
}
second.foldLeft(first)(helper)
}
listOflst.fold(List())(combiner)
答案 1 :(得分:1)
我怀疑我们可以逃避将每个元素相互比较(相当于非分布式算法中的双循环)。集合之间的子集操作不是反身的,这意味着我们需要比较is "alice" subsetof "bob"
和is "bob" subsetof "alice"
。
要使用Spark API执行此操作,我们可以使用笛卡尔积将数据与自身相乘,并验证结果矩阵的每个条目:
val data = Seq(("peter",Set(1,2,3)), ("mike",Set(1,3)), ("anne", Set(7)),("jack",Set(5,4,1)), ("lizza", Set(5,1)), ("bart", Set(5,4)), ("maggie", Set(5)))
// expected result from this dataset = peter, olga, anne, jack
val userSet = sparkContext.parallelize(data)
val prod = userSet.cartesian(userSet)
val subsetMembers = prod.collect{case ((name1, set1), (name2,set2)) if (name1 != name2) && (set2.subsetOf(set1)) && (set1 -- set2).nonEmpty => (name2, set2) }
val superset = userSet.subtract(subsetMembers)
// lets see the results:
superset.collect()
// Array[(String, scala.collection.immutable.Set[Int])] = Array((olga,Set(1, 2, 3)), (peter,Set(1, 2, 3)), (anne,Set(7)), (jack,Set(5, 4, 1)))
答案 2 :(得分:-3)
您可以在地图后使用过滤器。
您可以像地图一样构建,为您要删除的内容返回一个值。首先构建一个函数:
def filter_mike(line):
if line[1] != Set(1,3):
return line
else:
return None
然后您可以像这样过滤:
your_rdd.map(filter_mike).filter(lambda x: x != None)
这将有效