繁体   English   中英

Spark:在RDD map()中使用迭代器Lambda函数

[英]Spark: Using iterator lambda function in RDD map()

我在HDFS上有简单的数据集,正在将其加载到Spark中。 看起来像这样:

1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
...

基本上是一个矩阵 我正在尝试实现一些需要对矩阵行进行分组的事情,因此,我试图为每一行添加一个唯一键,如下所示:

(1, [1 1 1 1 1 ... ])
(2, [1 1 1 1 1 ... ])
(3, [1 1 1 1 1 ... ])
...

我尝试了一些天真的尝试:设置全局变量并编写一个lambda函数以遍历全局变量:

# initialize global index
global global_index
global_index = 0

# function to generate keys
def generateKeys(x):
    global_index+=1
    return (global_index,x)

# read in data and operate on it
data = sc.textFile("/data.txt")

...some preprocessing...

data.map(generateKeys)

而且它似乎不认识全局变量的存在。

有没有想到的简单方法可以做到这一点?

谢谢杰克

>>> lsts = [
...     [1, 1, 1, 1, 1, 1],
...     [1, 1, 1, 1, 1, 1],
...     [1, 1, 1, 1, 1, 1],
...     [1, 1, 1, 1, 1, 1],
...     [1, 1, 1, 1, 1, 1],
...     [1, 1, 1, 1, 1, 1],
...     [1, 1, 1, 1, 1, 2],
...     [1, 1, 1, 2, 1, 2]
...     ]
...
>>> list(enumerate(lsts))
[(0, [1, 1, 1, 1, 1, 1]),
 (1, [1, 1, 1, 1, 1, 1]),
 (2, [1, 1, 1, 1, 1, 1]),
 (3, [1, 1, 1, 1, 1, 1]),
 (4, [1, 1, 1, 1, 1, 1]),
 (5, [1, 1, 1, 1, 1, 1]),
 (6, [1, 1, 1, 1, 1, 2]),
 (7, [1, 1, 1, 2, 1, 2])]

enumerate为iterable中的每个项目生成唯一索引,并生成具有值的元组(index, original_item)

如果要从0以外的数字开始编号,请将起始值传递为第二个参数进行enumerate

>>> list(enumerate(lsts, 1))
[(1, [1, 1, 1, 1, 1, 1]),
 (2, [1, 1, 1, 1, 1, 1]),
 (3, [1, 1, 1, 1, 1, 1]),
 (4, [1, 1, 1, 1, 1, 1]),
 (5, [1, 1, 1, 1, 1, 1]),
 (6, [1, 1, 1, 1, 1, 1]),
 (7, [1, 1, 1, 1, 1, 2]),
 (8, [1, 1, 1, 2, 1, 2])]

请注意,该list用于从enumerate获取实数值,该enumerate是迭代器而非函数,返回列表。

备选:全球可用的ID分配器

enumerate易于使用,但是如果您需要在不同的代码段中添加id,它将变得困难或不可能。 对于这种情况,可以使用全球可用的生成器(如OP中的起草器)。

itertools提供count可以服务于我们的需要:

>>> from itertools import count
>>> idgen = count()

现在,我们已经有了(全球可用的) idgen生成器,可以生成唯一的id。

我们可以通过函数prid (打印ID)对其进行测试:

>>> def prid():
...     id = idgen.next()
...     print id
...
>>> prid()
0
>>> prid()
1
>>> prid()
2
>>> prid()
3

在工作时,我们可以在值列表上对其进行测试:

>>> lst = ['100', '101', '102', '103', '104', '105', '106', '107', '108', '109']

并定义实际函数,当使用值调用时将返回元组(id, value)

>>> def assignId(val):
...     return (idgen.next(), val)
...

请注意,无需将idgen声明为全局idgen ,因为我们不会更改其值( idgen仅在被调用时会更改其内部状态,但仍将保持相同的生成器)。

测试是否可行:

>>> assignId("ahahah")
(4, 'ahahah')

并尝试在列表上:

>>> map(assignId, lst)
[(5, '100'),
 (6, '101'),
 (7, '102'),
 (8, '103'),
 (9, '104'),
 (10, '105'),
 (11, '106'),
 (12, '107'),
 (13, '108'),
 (14, '109')]

enumerate解决方案的主要区别在于,我们可以在代码中的任何位置逐一分配id,而无需在enumerate所有处理中全部完成。

>>> assignId("lonely line")
(15, 'lonely line')

如果必须首先拥有索引,请尝试dataRdd.zipWithIndex并最终交换结果元组。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM