Python pyspark中的reduce和count结果不同

Python pyspark中的reduce和count结果不同,python,hadoop,apache-spark,Python,Hadoop,Apache Spark,对于我的spark试用版,我下载了,并将它们合并到一个文件nytaix.csv中。然后我将其保存在hadoop fs中。我正在使用7个节点管理器的spark on纱线 我正在连接spark over Ipython笔记本电脑 下面是一个示例python脚本,用于计算nytaix.csv中的行数 nytaxi=sc.textFile("hdfs://bigdata6:8020/user/baris/nytaxi/nytaxi.csv") filtered=nytaxi.filter(lambda

对于我的spark试用版,我下载了,并将它们合并到一个文件nytaix.csv中。然后我将其保存在hadoop fs中。我正在使用7个节点管理器的spark on纱线

我正在连接spark over Ipython笔记本电脑

下面是一个示例python脚本,用于计算nytaix.csv中的行数

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()
返回73491693。 但是,当我尝试用下面的代码计算行数时,它返回一个大约803000的值

def plusOne (sum, v):
    #print sum, v
    return sum + 1;
splits.reduce(plusOne)
我想知道为什么结果不同。 谢谢

csv中的示例行:
u'740BD5BE61840BE4FE3905CC3EBE37E,E48B185060FB0FF49BE6DA43E69E624B,CMT,1,N,2013-10-01 12:44:292013-10-01 12:53:26,1536,1.20,-73.974319,40.741859,-73.99115,40.742424'

因为我无法对我的发现发表评论,所以我将它们写在这里

我可以用一个更简单的例子来重现你的问题

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
9999
2502
9999
9999
对于
xrangeRDD=sc.parallelize(数据,4)

输出

9999
1256
9999
2502
9999
9999
对于
xrangeRDD=sc.parallelize(数据,1)

输出

9999
1256
9999
2502
9999
9999
因为我只是改变了分区的数量,也就是改变了reduce的输出,所以我认为reduce只提供了一个分区的输出,正如这里的模式所建议的那样


我还在学习spark是如何工作的。因此,我无法完全理解为什么会发生这种情况。我希望通过这些额外的细节,有人能够解释这背后的原因

这不是完整的答案

因为我无法对我的发现发表评论,所以我将它们写在这里

我可以用一个更简单的例子来重现你的问题

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
9999
2502
9999
9999
对于
xrangeRDD=sc.parallelize(数据,4)

输出

9999
1256
9999
2502
9999
9999
对于
xrangeRDD=sc.parallelize(数据,1)

输出

9999
1256
9999
2502
9999
9999
因为我只是改变了分区的数量,也就是改变了reduce的输出,所以我认为reduce只提供了一个分区的输出,正如这里的模式所建议的那样

我还在学习spark是如何工作的。因此,我无法完全理解为什么会发生这种情况。我希望通过这些额外的细节,有人能够解释这背后的原因

的文档说明:

使用指定的交换和关联二进制运算符减少此RDD的元素

def plusOne(sum,v):返回sum+1
不可交换。它完全忽略其中一个参数。因此,您看到的是未定义的行为。(我建议您考虑一下为什么函数必须是可交换的。如果您理解这一点,那么您对Spark的理解会更好一些!)

解决方案是使用
RDD.count()
。但如果您坚持使用
reduce()
,您会这样做:

def count(rdd):
  return rdd.map(lambda x: 1).reduce(lambda a, b: a + b)
文件说明:

使用指定的交换和关联二进制运算符减少此RDD的元素

def plusOne(sum,v):返回sum+1
不可交换。它完全忽略其中一个参数。因此,您看到的是未定义的行为。(我建议您考虑一下为什么函数必须是可交换的。如果您理解这一点,那么您对Spark的理解会更好一些!)

解决方案是使用
RDD.count()
。但如果您坚持使用
reduce()
,您会这样做:

def count(rdd):
  return rdd.map(lambda x: 1).reduce(lambda a, b: a + b)

问题在于
reduce
中使用的操作必须是关联的和可交换的:

请注意,在每个分区上完成的
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个计数):

因此,您应该更喜欢
count
,或者按照Daniel的建议和
map
,或者您有第三个选项来进行
聚合

 rdd.aggregate(0)(_+1, _+_)

这将使用0作为计数种子,在本地将1添加到累加器中,然后在合并中将两个累加器添加到一起。

问题在于
reduce
中使用的操作必须是关联的和可交换的:

请注意,在每个分区上完成的
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个计数):

因此,您应该更喜欢
count
,或者按照Daniel的建议和
map
,或者您有第三个选项来进行
聚合

 rdd.aggregate(0)(_+1, _+_)

这将使用0作为计数的种子,在本地将1添加到累加器,然后在合并中将两个累加器添加到一起。

您能提供您正在使用的csv文件的某些部分吗?在问题文本中添加了一个示例行。据我所知,您得到的输出仅对应于一个分区,而不是整个RDD。我能够重现这个问题,如果没有分区被减少到1,那么输出count和reduce匹配。我仍在学习spark,所以不确定为什么会发生这种情况。您能提供您正在使用的csv文件的某些部分吗?在问题文本中添加了一行示例。据我所知,您得到的输出仅对应于一个分区,而不是整个RDD。我能够重现这个问题,如果没有分区被减少到1,那么输出count和reduce匹配。我还在学习spark,所以不知道为什么会发生这种情况。