使用reducebykey时出错:int对象是unsubscriptable

时间:2018-01-16 05:48:55

标签: python apache-spark pyspark

执行以下脚本时,我收到错误“int object is unsubscriptable”

element.reduceByKey( lambda x , y : x[1]+y[1])

with element是一个键值RDD,值是一个元组。示例输入:

(A, (toto , 10))
(A, (titi , 30))
(5, (tata, 10))
(A, (toto, 10))

我理解reduceByKey函数采用(K,V)元组并对所有值应用函数以获得reduce的最终结果。 与ReduceByKey Apache中给出的示例类似。

请帮忙吗?

2 个答案:

答案 0 :(得分:2)

这是一个例子,将说明正在进行的事情。

让我们考虑一下您在列有reduce函数的列表上发送f时会发生什么:

reduce(f, [a,b,c]) = f(f(a,b),c)

如果我们以f = lambda u, v: u[1] + v[1]为例,那么上面的表达式会分解为:

reduce(f, [a,b,c]) = f(f(a,b),c) = f(a[1]+b[1],c)

但是a[1] + b[1]是一个整数,所以没有__getitem__方法,因此你的错误。

通常,更好的方法(如下所示)是使用map()首先以您希望的格式提取数据,然后应用reduceByKey()

包含数据的MCVE

element = sc.parallelize(
    [
        ('A', ('toto' , 10)),
        ('A', ('titi' , 30)),
        ('5', ('tata', 10)),
        ('A', ('toto', 10))
    ]
)

你可以几乎使用更复杂的reduce功能获得所需的输出:

def add_tuple_values(a, b):
    try:
        u = a[1]
    except:
        u = a
    try:
        v = b[1]
    except:
        v = b
    return u + v

print(element.reduceByKey(add_tuple_values).collect())

除此之外导致:

[('A', 50), ('5', ('tata', 10))]

为什么?因为密钥'5'只有一个值,所以没有什么可以减少的。

出于这些原因,最好先拨打map。要获得所需的输出,您可以这样做:

>>> print(element.map(lambda x: (x[0], x[1][1])).reduceByKey(lambda u, v: u+v).collect())
[('A', 50), ('5', 10)]

更新1

以下是另一种方法:

您可以在tuple函数中创建reduce,然后调用map以提取所需的值。 (基本上颠倒了mapreduce的顺序。)

print(
    element.reduceByKey(lambda u, v: (0,u[1]+v[1]))
        .map(lambda x: (x[0], x[1][1]))
        .collect()
)
[('A', 50), ('5', 10)]

备注

  • 如果每个密钥至少有2条记录,使用add_tuple_values()会给你正确的输出。

答案 1 :(得分:2)

另一种方法是使用Dataframe

rdd = sc.parallelize([('A', ('toto', 10)),('A', ('titi', 30)),('5', ('tata', 10)),('A', ('toto', 10))])
rdd.map(lambda (a,(b,c)): (a,b,c)).toDF(['a','b','c']).groupBy('a').agg(sum("c")).rdd.map(lambda (a,c): (a,c)).collect()

>>>[(u'5', 10), (u'A', 50)]