我希望filter
输出RDD的字段' status'不等于' OK'。我从HDFS上的一组CSV文件创建我的RDD,然后在尝试map
之前使用filter
获取我想要的结构:
import csv, StringIO
files = "/hdfs_path/*.csv"
fields = ["time", "status"]
dial = "excel"
default = {'status': 'OK', 'time': '2014-01-01 00:00:00'}
def loadRecord(line, fieldnames, dialect):
input = StringIO.StringIO(line)
reader = csv.DictReader(input, fieldnames = fieldnames, dialect = dialect)
try:
line = reader.next()
if line is None:
return default
else:
return line
except:
return default
harmonics = sc.textFile(files) \
.map(lambda x: loadRecord(x, fields, dial)) \
.filter(lambda x: "OK" not in x['status'])
我可以对此RDD做其他事情 - 例如另一个map
到get
只有某些字段等。但是,当我使用filter
运行我的代码时,其中一个任务总是失败,我的filter
lambda中出现异常功能:
'NoneType object is not iterable'
我认为这意味着filter
lambda正在收到None
,因此我将代码添加到loadRecord
以避免返回None
。但是,我仍然得到同样的错误。它确实适用于小样本数据集,但我的实际数据足够大,以至于我不确定如何检测它的哪个部分可能导致问题。
任何意见都赞赏!
答案 0 :(得分:3)
首先,使用map(lambda x: loadRecord(x, fields, dial))
重新定位map(lambda x: (x, loadRecord(x, fields, dial)))
- 这样就可以保存原始记录和已解析的记录。
其次,用filter()
替换flatMap(test_function)
调用并定义test_function
测试输入的方式,如果第二个传递的参数是None(解析记录),它将返回第一个
这样你就会得到导致问题的输入行,并在本地测试你的脚本。一般情况下,我会添加一行global default
作为loadRecord
函数的第一行
答案 1 :(得分:0)
以0x0FFF的答案为基础,我能够运行我的代码。我还没有看到违规文件的违规行,但我比我更接近。这就是我所做的,从我的问题中的代码开始:
def checkNone(x):
try:
return "OK" not in x['status']
except:
return True
harmonics = sc.textFile(files) \
.map(lambda x: loadRecord(x, fields, dial)) \
.filter(lambda x: checkNone(x))