我刚刚掌握Spark,我的函数需要映射到rdd
,但使用全局字典:
from pyspark import SparkContext
sc = SparkContext('local[*]', 'pyspark')
my_dict = {"a": 1, "b": 2, "c": 3, "d": 4} # at no point will be modified
my_list = ["a", "d", "c", "b"]
def my_func(letter):
return my_dict[letter]
my_list_rdd = sc.parallelize(my_list)
result = my_list_rdd.map(lambda x: my_func(x)).collect()
print result
以上给出了预期的结果;但是,我真的不确定我使用全局变量my_dict
。似乎每个分区都会创建一个字典副本。它只是感觉不对..
看起来broadcast正是我要找的。但是,当我尝试使用它时:
my_dict_bc = sc.broadcast(my_dict)
def my_func(letter):
return my_dict_bc[letter]
我收到以下错误:
TypeError: 'Broadcast' object has no attribute '__getitem__
这似乎意味着我无法播放字典。
我的问题:如果我有一个使用全局字典的函数,需要将其映射到rdd
,那么正确的方法是什么?
我的例子很简单,但实际上my_dict
和my_list
要大得多,my_func
更复杂。
答案 0 :(得分:24)
您忘记了有关Broadcast
个对象的重要信息,它们有一个名为value的属性,用于存储数据。
因此,您需要将my_func
修改为以下内容:
my_dict_bc = sc.broadcast(my_dict)
def my_func(letter):
return my_dict_bc.value[letter]
答案 1 :(得分:1)
执行此操作的正确方法取决于如何在程序的其余部分中访问只读共享变量(在您的情况下为字典)。在您描述的情况下,您不需要使用广播变量。来自the Spark programming guide section on broadcast variables:
Spark会自动广播每个阶段中任务所需的公共数据。以这种方式广播的数据以序列化形式缓存并在运行每个任务之前反序列化。这意味着显式创建广播变量仅在跨多个阶段的任务需要相同数据或以反序列化形式缓存数据时非常有用。
在您的情况下,如果仅在单个地图阶段中需要数据,则无需显式广播变量(它不是"有用")。但是,如果稍后在另一个阶段使用相同的字典,那么您可能希望使用广播来避免在每个阶段之前对字典进行序列化和反序列化。