为什么Spark reduceByKey的结果不一致

时间:2016-09-06 14:10:49

标签: scala hadoop apache-spark

我正在尝试使用scala计算每行的迭代次数 以下是我的意见:

1 vikram
2 sachin
3 shobit
4 alok
5 akul
5 akul
1 vikram
1 vikram
3 shobit
10 ashu
5 akul
1 vikram
2 sachin
7 vikram

现在我按如下方式创建2个单独的RDD。

val f1 = sc.textFile("hdfs:///path to above data file")
val m1 = f1.map( s => (s.split(" ")(0),1) ) //creating a tuple (key,1)
//now if i create a RDD as
val rd1 = m1.reduceByKey((a,b) => a+b )
rd1.collect().foreach(println)
//I get a proper output i.e (it gives correct output every time)
//output: (4,1) (2,2) (7,1) (5,3) (3,2) (1,4) (10,1)

//but if i create a RDD as
val rd2 = m1.reduceByKey((a,b) => a+1 )
rd2.collect().foreach(println)
//I get a inconsistent result i.e some times i get this (WRONG)
//output: (4,1) (2,2) (7,1) (5,2) (3,2) (1,2) (10,1)
//and sometimes I get this as output (CORRECT)
//output: (4,1) (2,2) (7,1) (5,3) (3,2) (1,4) (10,1) 

我无法理解为什么会发生这种情况以及在哪里使用什么。我也尝试过将RDD创建为

val m2 = f1.map(s => (s,1))
val rd3 = m2.reduceByKey((a,b) => a+1 )
// Then also same issue occurs with a+1 but every thing works fine with a+b

2 个答案:

答案 0 :(得分:7)

reduceByKey假设传递的函数是可交换关联(因为docs明确表示)。 而且 - 您的第一个功能(a, b) => a + b ,但(a, b) => a+1 不是

<强> WHY吗 首先,reduceByKey将提供的函数应用于每个分区,然后应用于所有分区的组合结果。换句话说,b并不总是1,因此使用a+1并不是正确的。

考虑以下场景 - 输入包含4条记录,分为两个分区:

(aa, 1)
(aa, 1)

(aa, 1)
(cc, 1)
此输入上的

reduceByKey(f)可能计算如下:

val intermediate1 = f((aa, 1), (aa, 1)) 
val intermediate2 = f((aa, 1), (cc, 1))

val result = f(intermediate2, intermediate1)

现在,让我们按照f = (a, b) => a + b

进行操作
val intermediate1 = f((aa, 1), (aa, 1))       // (aa, 2)
val intermediate2 = f((aa, 1), (cc, 1))       // (aa, 1), (cc, 1)

val result = f(intermediate2, intermediate1)  // (aa, 3), (cc, 1)

使用f = (a, b) => a + 1

val intermediate1 = f((aa, 1), (bb, 1))       // (aa, 2)
val intermediate2 = f((aa, 1), (cc, 1))       // (aa, 1), (cc, 1)

// this is where it goes wrong:
val result = f(intermediate2, intermediate1)  // (aa, 2), (cc, 1)

主要的是 - 中间计算的顺序没有得到保证,并且可能在执行之间发生变化,对于后一种非交换函数的情况,这意味着结果有时是错误的。

答案 1 :(得分:2)

函数(a,b)=&gt; (a + 1)在性质上不具有联想性。 联想法则说,

f(a ,f(b , c)) = f(f(a , b), c) 

假设以下键:

a = (x, 1)
b = (x, 1)
c = (x, 1)

应用函数(a,b)=&gt; (a + 1)

f(a ,f(b , c)) = (x , 2)

但是,

f(f(a , b), c) = (x , 3)

因此,它不是关联的,不适用于reduceByKey。