无法在RDD上应用flatMap

时间:2016-07-06 16:47:18

标签: python apache-spark pyspark

在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可能无法执行。

代码有什么问题?

3 个答案:

答案 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'>