我有一个成员列表,它们有许多属性,其中两个是名称和ID。我希望得到一个RDD中的元组列表。元组将包含ID
作为第一个元素,以及与ID关联的unique
个名称的计数作为第二个元素。
e.g。比如:ID, <# of unique names associated with ID>
。
这里是我为完成此任务而编写的代码:
IDnametuple = members.map(lambda a: (a.ID, a.name)) # extract only ID and name
idnamelist = IDnametuple.groupByKey() # group the IDs together
idnameunique_count = (idnamelist
# set(tup[1]) should extract unique elements,
# and len should tell the number of them
.map(lambda tup: (tup[0], len(set(tup[1])))))
它非常慢,并且比为每个成员计算唯一属性的类似操作慢得多。
有更快的方法吗?我尝试使用尽可能多的内置插件,这是加速操作的正确方法,来自我所听到的内容。
答案 0 :(得分:3)
没有任何细节,我们只能猜测,但显而易见的选择是groupByKey
。如果每个id与大量名称相关联,则由于广泛的改组,它可能相当昂贵。最简单的改进是aggregateByKey
或combineByKey
:
create_combiner = set
def merge_value(acc, x):
acc.add(x)
return acc
def merge_combiners(acc1, acc2):
acc1.update(acc2)
return acc1
id_name_unique_count = (id_name_tuple # Keep consistent naming convention
.combineByKey(create_combiner, merge_value, merge_combiners)
.mapValues(len))
如果预期的唯一值数量很大,您可能更愿意替换近似的精确方法。一种可能的方法是使用Bloom过滤器来跟踪唯一值而不是set
。
有关groupByKey
与aggregateByKey
(reduceByKey
,combineByKey
)的其他信息,请参阅:
答案 1 :(得分:1)
这基本上是https://spark.apache.org/docs/latest/programming-guide.html#working-with-key-value-pairs的单词计数示例,但计算不同的键值对:
from operator import add
IDnametuple = sc.parallelize([(0, "a"),(0, "a"),(0, "b"),(1, "a"),(1, "b"),(1, "c"),(2, "z")])
idnameunique_count = (IDnametuple.distinct()
.map(lambda idName : (idName[0], 1))
.reduceByKey(add))
因此idnameunique_count.collect()
会返回[(0, 2), (1, 3), (2, 1)]
,其中(0, "a")
只计算一次。正如@ zero323所提到的,这里的关键是将groupByKey
替换为reduceByKey
,以避免创建名称的中间列表。您只需要名称计数,这是一个小得多的对象,可能是一个巨大的列表。此外,您的版本使用set()
在闭包代码中按顺序消除重复项,而distinct
则作为分布式并行RDD转换执行。