2016-12-21 54 views
0

我有一個非常簡單的代碼:RDD創建和變量綁定

def fun(x, n): 
    return (x, n) 

rdds = [] 
for i in range(2): 
    rdd = sc.parallelize(range(5*i, 5*(i+1))) 
    rdd = rdd.map(lambda x: fun(x, i)) 
    rdds.append(rdd) 

a = sc.union(rdds) 
print a.collect() 

我所預料的輸出爲以下幾點:

[(0, 0), (1, 0), (2, 0), (3, 0), (4, 0), (5, 1), (6, 1), (7, 1), (8, 1), (9, 1)] 

但是,輸出如下:

[(0, 1), (1, 1), (2, 1), (3, 1), (4, 1), (5, 1), (6, 1), (7, 1), (8, 1), (9, 1)] 

這令人困惑,至少可以說。

看來,由於RDDS,正被用於創建RDDS的i值的惰性計算是一個當collect()把它叫做熊,這是1(從for循環的最後運行)。

現在,元組的兩個元素都來自i

但似乎,對於元組的第一個元素,i熊值0和1倍,而對於元組i的第二個元素承載值2

有人能請解釋一下發生了什麼?

感謝。

回答

2

只是改變

rdd = rdd.map(lambda x: fun(x, i)) 

rdd = rdd.map(lambda x, i=i: (x, i)) 

那只是關於Python,看看這個

https://docs.python.org/2.7/tutorial/controlflow.html#default-argument-values

+0

因此'i = i'將'i'推入到lambda函數的範圍中,當它被調用時,lambda函數的本地值將首先被訪問。 – MYGz

+0

@MohammadYusufGhazi是的。缺省值在定義範圍內的函數定義處計算 –

+0

由range(2)創建的'list'中的'0'和'1'整數對象的id被分配給lambda函數參數。該列表不會被垃圾回收,因爲其中的項目仍然被其他一些變量指向? – MYGz

0

sc.parallelize()是一個即時執行的動作。因此將使用i的兩個值,即01

但在rdd.map()的情況下,當您稍後致電collect()時,將只使用最後一個值i

rdd = sc.parallelize(range(5*i, 5*(i+1))) 
rdd = rdd.map(lambda x: fun(x, i)) 

這裏rdd.map不會變換RDD,它將只創建DAG(有向無環圖),即lambda函數將不會被施加到RDD的元件。

當您調用collect()時,lambda函數將被調用,但到那時i的值爲1.如果您在調用collect之前重新分配i=10,那麼將使用該值i

+0

如果是這樣的話,那麼爲什麼是價值0和1用於元組的第一個元素,而在我的例子中只有1用於第二個元素?謝謝。 – abhinavkulkarni

+1

@abhinavkulkarni因爲sc.parallelize()是一個即時執行的動作,而rdd.map()是一個轉換。如果你收集循環內的rdd然後追加到列表中,你將得到你想要的結果。 – MYGz

+0

@abhinavkulkarni你把zhangtong的解決方案放在lambda函數的範圍裏,把'i'的值壓下去。所以當lambda函數被調用時,它將首先使用它的本地值'i',然後爬上外部範圍,其中'i'的值已經改變。 – MYGz