通过spark(python)中的MapReduce了解组

通过spark(python)中的MapReduce了解组,python,apache-spark,mapreduce,pyspark,rdd,Python,Apache Spark,Mapreduce,Pyspark,Rdd,我正在尝试一个小程序,其中我正在考虑一个员工数据集,并试图计算分布在各个部门的工资总额。我有一个可复制的例子 emp_list=[(u'ACC', [u'101', u'a', u'ACC', u'1000']), (u'SALES', [u'102', u'b', u'SALES', u'2000']), (u'IT', [u'103', u'c', u'IT', u'3000']), (u'ACC', [u'104', u'd', u'ACC', u'4000']), (u'ACC

我正在尝试一个小程序,其中我正在考虑一个员工数据集,并试图计算分布在各个部门的工资总额。我有一个可复制的例子

 emp_list=[(u'ACC', [u'101', u'a', u'ACC', u'1000']),
 (u'SALES', [u'102', u'b', u'SALES', u'2000']),
 (u'IT', [u'103', u'c', u'IT', u'3000']),
 (u'ACC', [u'104', u'd', u'ACC', u'4000']),
 (u'ACC', [u'105', u'e', u'ACC', u'5000']),
 (u'HR', [u'106', u'f', u'HR', u'6000']),
 (u'ACC', [u'107', u'g', u'ACC', u'7000']),
 (u'FIN', [u'108', u'h', u'FIN', u'8000']),
 (u'ACC', [u'109', u'k', u'ACC', u'9000']),
 (u'HR', [u'1010', u'l', u'HR', u'10000']),
 (u'ACC', [u'1011', u'm', u'ACC', u'11000']),
 (u'ACC', [u'1012', u'n', u'ACC', u'12000']),
 (u'FIN', [u'1013', u'o', u'FIN', u'13000']),
 (u'IT', [u'1014', u'p', u'IT', u'14000'])]

emp=sc.parallelize(emp_list)

emp.reduceByKey(lambda x,y : x[3]+y[3]).take(10)
我得到的结果是:

[(u'ACC', u'00'),
 (u'HR', u'600010000'),
 (u'FIN', u'800013000'),
 (u'SALES', [u'102', u'b', u'SALES', u'2000']),
 (u'IT', u'300014000')]

谁能解释一下为什么我在
ACC
SALES
部门得到奇怪的值。我还想看看这两个人的合并工资。

也许这样可以:

emp.map(lambda k, v: (k, v[3])).reduceByKey(lambda x,y : x+y).take(10)

虽然我没有一个Spark实例来尝试它

但您会得到奇怪的值,因为函数的逻辑无效。如果使用Scala而不是Python,这甚至不会编译。应用
reduceByKey
LHS和RHS时,返回类型应为相同类型:

reduceByKey(func: (V, V) ⇒ V): RDD[(K, V)]
func
应该是关联的

在您的情况下,类型不匹配(输入是列表,返回类型是字符串),函数不关联。要理解正在发生的事情,可以考虑两种不同的情况:

  • 每个键只有一个值。由于未应用
    func
    ,因此将此值作为输出。因此
    (u'SALES',[u'102',u'b',u'SALES',u'2000'])

  • 每个键有多个值。让我们以
    ACC
    中的值子集为例,假设操作顺序定义如下

    (
      # 1st partition
      ([u'101', u'a', u'ACC', u'1000'], [u'104', u'd', u'ACC', u'4000']),
      # 2nd partition
      ([u'105', u'e', u'ACC', u'5000'], [u'107', u'g', u'ACC', u'7000'])
    )
    
    首次应用
    func
    后,我们得到:

    (
       u'10004000',
       ([u'105', u'e', u'ACC', u'5000'], [u'107', u'g', u'ACC', u'7000'])
    )
    
    在第二次应用
    func
    之后,我们得到

    (
       u'10004000',
       u'50007000'
    )
    
    最后

    u'00'
    
    实际上,括号可能因配置而异,因此您可以获得不同的输出

  • 要获得正确的结果,您应该使用@Alex或
    map
    建议的
    aggregateByKey
    /
    combineByKey
    map
    reduce,然后使用
    groupByKey
    mapValues
    。最后一种方法应该是这里最有效的方法,因为它不需要中间对象:

    emp.mapValues(lambda x: x[3]).groupByKey().mapValues(lambda xs: "".join(xs))
    
    使用
    aggregateByKey
    作为参考:

    from operator import add
    
    rdd.aggregateByKey("", lambda acc, x: acc + x[3], add)
    

    您需要记住,当您进行缩减时,缩减的元素需要在reduce第一次看到它们时保持相同的结构,其他时间也一样。下面是在您的示例中实现此目的的方法:

    emp_list=[(u'ACC', [u'101', u'a', u'ACC', u'1000']),
     (u'SALES', [u'102', u'b', u'SALES', u'2000']),
     (u'IT', [u'103', u'c', u'IT', u'3000']),
     (u'ACC', [u'104', u'd', u'ACC', u'4000']),
     (u'ACC', [u'105', u'e', u'ACC', u'5000']),
     (u'HR', [u'106', u'f', u'HR', u'6000']),
     (u'ACC', [u'107', u'g', u'ACC', u'7000']),
     (u'FIN', [u'108', u'h', u'FIN', u'8000']),
     (u'ACC', [u'109', u'k', u'ACC', u'9000']),
     (u'HR', [u'1010', u'l', u'HR', u'10000']),
     (u'ACC', [u'1011', u'm', u'ACC', u'11000']),
     (u'ACC', [u'1012', u'n', u'ACC', u'12000']),
     (u'FIN', [u'1013', u'o', u'FIN', u'13000']),
     (u'IT', [u'1014', u'p', u'IT', u'14000'])]
    
    emp=sc.parallelize(emp_list)
    print emp.reduceByKey(lambda x,y : (1,1,1,x[3] + y[3]))\
    .map(lambda x: (x[0], x[1][3])).collect()
    >> [(u'ACC', u'100040005000700090001100012000'), (u'HR', u'600010000'),\
     (u'FIN', u'800013000'), (u'SALES', u'2000'), (u'IT', u'300014000')]
    

    我想要合并的工资,因为这意味着工资可以聚合,并且可以通过将字符串转换为float/int求和。只有一条线索:如果我有两条来自
    SALES
    的记录,我会得到合并的结果。但我想要的是,如果一个键只有一条记录,例如,
    SALES
    ,我应该只获取与之关联的值。i、 e.
    2000
    而不是整个记录。谢谢你的建议。你救了我!!:)您还可以让我参考一些文档,在这些文档中我可以看到各种RDD方法的各种lambda原型。与reduceByKey方法类似,lambda应该类似于
    func:(V,V)⇒ V
    。在pyspark文档中,它们引用lambda就像
    func
    一样,没有任何规范。我的lambda函数输入x和y是字符串列表,我尝试像这样从lambda函数返回字符串列表<代码>emp.reduceByKey(lambda x,y:[x[3]+y[3]])。取(10),它就不起作用了。如果您对此有任何意见,我将不胜感激。我已编辑了答案,以解释如何获得您看到的结果。谢谢!!这只需稍微修改
    emp.map(lambda v:(v[0],v[1][3])。reduceByKey(lambda x,y:x+y)。取(10)
    但缺点是我们丢失了其他字段。是的,虽然方法很简单,但这是可行的。这种方法只适用于处理只有一条记录的键。例如,此处的
    销售