如何有效删除spark RDD中的子集

时间:2016-11-08 16:15:09

标签: scala apache-spark subset rdd

在进行研究时,我发现删除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扩展到云时,找到一个好的解决方案并不容易。

由于

3 个答案:

答案 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)

这将有效