对于我的火花试验,我已经下载了NY taxi csv files并将它们合并到一个文件nytaxi.csv中。然后我把它保存在hadoop fs中。我正在使用带有7个节点管理器的火花。
我正在连接Ipython笔记本电脑。
这是一个示例python脚本,用于计算nytaxi.csv中的行数。
code
返回73491693。 但是,当我尝试通过以下代码计算行数时,它返回一个大约803000的值。
nytaxi=sc.textFile("hdfs://bigdata6:8020/user/baris/nytaxi/nytaxi.csv")
filtered=nytaxi.filter(lambda x:"distance" not in x)
splits = filtered.map(lambda x: float(x.split(",")[9]))
splits.cache()
splits.count()
我想知道为什么结果会有所不同。 感谢
来自csv的示例行: u'740BD5BE61840BE4FE3905CC3EBE3E7E,E48B185060FB0FF49BE6DA43E69E624B,CMT,1,N,2013-10-01 12:44:29,2013-10-01 12:53:26,1,536,1.20,-73.974319,40.741859,-73.99115,40.742424'
答案 0 :(得分:2)
RDD.reduce()
的文档说:
使用指定的可交换和关联二元运算符减少此RDD的元素。
def plusOne(sum, v): return sum + 1
不是可交换的。它完全忽略了其中一个参数。所以你看到了未定义的行为。 (我建议考虑为什么函数必须是可交换的。如果你理解这一点,你就会更好地理解Spark!)
解决方案是使用RDD.count()
代替。但如果你坚持使用reduce()
,你就会这样做:
def count(rdd):
return rdd.map(lambda x: 1).reduce(lambda a, b: a + b)
答案 1 :(得分:2)
问题在于Daniel指出,reduce
中使用的操作必须是关联的和可交换的。 Here's the reason from the source itself:
val reducePartition: Iterator[T] => Option[T] = iter => {
if (iter.hasNext) {
Some(iter.reduceLeft(cleanF))
} else {
None
}
}
请注意,在每个分区上执行的reduce
是一个简单的委托给它的迭代器reduceLeft
。这不会导致任何问题,因为它只是价值的积累。
val mergeResult = (index: Int, taskResult: Option[T]) => {
if (taskResult.isDefined) {
jobResult = jobResult match {
case Some(value) => Some(f(value, taskResult.get))
case None => taskResult
}
}
}
但是,分区的合并是个问题。以下是您在示例中如何分解的假设(假设在4个均匀分割的分区上有40个计数):
A = 10; B = 10; C = 10; D = 10 //Local reductions. Everything ok
A added in = 10 //Still ok
B added in = f(10, 10) = 11 //Because your definition of f is (first + 1)
//This drops the second param of 10
C added in = f(11, 10) = 12 //Again, only adding 1 instead of the actual 10 count
所以,你应该更喜欢count
,或者像丹尼尔建议和map
那样做,或者你有第三个选择来做aggregate
rdd.aggregate(0)(_+1, _+_)
这将使计数为0,继续在本地向累加器添加1,然后在合并中将两个累加器一起添加。
答案 2 :(得分:1)
这不是完整的答案
由于我无法将我的发现置于评论中,所以我在这里写它们。
我能够通过一个更简单的例子重现您的问题。
data = xrange(1, 10000)
len(data) #output => 9999
xrangeRDD = sc.parallelize(data, 8)
print xrangeRDD.count()
def plusOne (v,sum):
#print sum, v
return v + 1;
a = xrangeRDD.reduce(plusOne)
print a
<强>输出强>
9999
1256
xrangeRDD = sc.parallelize(data, 4)
<强>输出强>
9999
2502
xrangeRDD = sc.parallelize(data, 1)
<强>输出强>
9999
9999
由于我只是不同数量的分区,并且改变了reduce的输出,我认为reduce只是给你一个分区的输出,如这里的模式所示。
我还在学习火花的工作原理。所以我无法在这里得到完整的逻辑,为什么会发生这种情况。我希望通过这个额外的细节,有人可能能够解释这背后的原因。