在Pyspark中编写的自定义UDF,输出为“java.lang.Object”

时间:2017-03-29 05:28:16

标签: pyspark udf

我写了一个自定义变换器类POSWordTagger。我的转换方法代码是,

  def _transform(self, dataset):

    def f(s):
        tokens = nltk.tokenize.wordpunct_tokenize(s)
        pos_tags = nltk.pos_tag(tokens)
        return pos_tags

    t = ArrayType(StringType())
    out_col = self.getOutputCol()
    in_col = dataset[self.getInputCol()]
    return dataset.withColumn(out_col, udf(f, t)(in_col))

我按如下方式调用我的Transformer类,

    sc = SparkContext(conf=conf)
    sqlContext = SQLContext(sc)

    sentenceDataFrame = sqlContext.createDataFrame([
      (0, "Hi I heard about Spark"),
      (0, "I wish Java could use case classes"),
      (1, "Logistic regression models are neat")
      ], ["label", "sentence"])

    pos_tagger = POSWordTagger(inputCol="sentence", outputCol="pos")

    pos_output=pos_tagger.transform(sentenceDataFrame)
    pos_output.select("pos").show()

我得到输出为

    +--------------------+
    |                 pos|
    +--------------------+
    |[[Ljava.lang.Obje...|
    |[[Ljava.lang.Obje...|
    |[[Ljava.lang.Obje...|
    +-------------------

即使我将模式作为ArrayType(StringType())传递,我也将Object引用作为输出。但是如果我只返回“标记”作为输出而不是我的_transform()方法中的“pos_tags”,我正确地获取输出,即标记列表。任何人都可以让我知道我错过了什么或做错了什么?任何帮助表示赞赏。我的环境是Spark 1.6和Python 2.7。

1 个答案:

答案 0 :(得分:1)

请看下面的示例,pos_tag返回list(tuple(string))

>>> text = word_tokenize("And now for something completely different")
>>> nltk.pos_tag(text)


[('And', 'CC'), ('now', 'RB'), ('for', 'IN'), ('something', 'NN'),
('completely', 'RB'), ('different', 'JJ')]

您的代码中的问题在ArrayType(StringType())处查找,因此它应该是ArrayType(ArrayType(StringType()))

######回答评论
import pyspark.sql.types as T 
import pyspark.sql.functions as F 
def flattenArray(obj):
    return reduce(lambda x,y:x+y, obj)

pos_output.select(F.udf(flattenArray, T.ArrayType(T.StringType()))("pos").alias("pos")).show(truncate = False)