在PySpark中,对于RDD的每个元素,我正在尝试获取Row
个元素的数组。然后我想将结果转换为DataFrame。
我有以下代码:
simulation = housesDF.flatMap(lambda house: goThroughAB(jobId, house))
print simulation.toDF().show()
在其中,我正在调用这些辅助方法:
def simulate(jobId, house, a, b):
return Row(jobId=jobId, house=house, a=a, b=b, myVl=[i for i in range(10)])
def goThroughAB(jobId, house):
print "in goThroughAB"
results = []
for a in as:
for b in bs:
results += simulate(jobId, house, a, b)
print type(results)
return results
奇怪的是,print "in goThroughAB"
没有任何效果,因为屏幕上没有输出。
但是,我收到此错误:
---> 23 print simulation.toDF().show()
24
25 dfRow = sqlContext.createDataFrame(simulationResults)
/databricks/spark/python/pyspark/sql/context.py in toDF(self, schema, sampleRatio)
62 [Row(name=u'Alice', age=1)]
63 """
---> 64 return sqlContext.createDataFrame(self, schema, sampleRatio)
65
66 RDD.toDF = toDF
/databricks/spark/python/pyspark/sql/context.py in createDataFrame(self, data, schema, samplingRatio)
421
422 if isinstance(data, RDD):
--> 423 rdd, schema = self._createFromRDD(data, schema, samplingRatio)
424 else:
425 rdd, schema = self._createFromLocal(data, schema)
/databricks/spark/python/pyspark/sql/context.py in _createFromRDD(self, rdd, schema, samplingRatio)
308 """
309 if schema is None or isinstance(schema, (list, tuple)):
--> 310 struct = self._inferSchema(rdd, samplingRatio)
311 converter = _create_converter(struct)
312 rdd = rdd.map(converter)
/databricks/spark/python/pyspark/sql/context.py in _inferSchema(self, rdd, samplingRatio)
261
262 if samplingRatio is None:
--> 263 schema = _infer_schema(first)
264 if _has_nulltype(schema):
265 for row in rdd.take(100)[1:]:
/databricks/spark/python/pyspark/sql/types.py in _infer_schema(row)
829
830 else:
--> 831 raise TypeError("Can not infer schema for type: %s" % type(row))
832
833 fields = [StructField(k, _infer_type(v), True) for k, v in items]
TypeError: Can not infer schema for type: <type 'str'>
在这一行:
print simulation.toDF().show()
因此看起来goThroughAB
未执行,这意味着flatMap
可能无法执行。
代码有什么问题?
答案 0 :(得分:0)
首先,您不是在驱动程序上打印,而是在Spark执行程序上打印。如您所知,执行程序是并行执行Spark任务的远程进程。他们会在自己的控制台上打印该行。您不知道哪个执行程序运行某个分区,您不应该依赖分布式环境中的print语句。
然后问题是,当您想要创建DataFrame时,Spark需要知道该表的架构。如果您没有指定它,它将使用采样率并检查某些行以确定其类型。如果未指定采样率,则仅检查第一行。这种情况发生在您的情况下,您可能有一个无法确定类型的字段(可能为空)。
要解决此问题,您应该将架构添加到toDF()方法或指定非零采样率。可以提前创建模式,如下所示:
schema = StructType([StructField("int_field", IntegerType()),
StructField("string_field", StringType())])
答案 1 :(得分:0)
此代码不正确。 results += simulate(jobId, house, a, b)
将尝试连接行和失败。如果您没有看到TypeError
未找到,而您的代码在其他地方失败,可能是在您创建housesDF
时。
答案 2 :(得分:-1)
正如其他人所指出的,关键问题是results += simulate(jobId, house, a, b)
,当simulation
返回Row对象时,它不会起作用。您可以尝试将results
设为list
,然后使用list.append
。但为什么不yield
?
def goThroughAB(jobId, house):
print "in goThroughAB"
results = []
for a in as:
for b in bs:
yield simulate(jobId, house, a, b)
当您+
两个Row对象时发生了什么?
In[9]:
from pyspark.sql.types import Row
Row(a='a', b=1) + Row(a='b', b=2)
Out[9]:
('a', 1, 'b', 2)
然后toDF
对第一个元素进行了抽样,发现它是str
(你的jobId),因此抱怨
TypeError: Can not infer schema for type: <type 'str'>