Spark Dataframe验证镶木地板写入(scala)的列名称

时间:2016-07-04 19:26:55

标签: apache-spark apache-spark-sql spark-streaming spark-dataframe parquet

我正在使用从JSON事件流转换而来的Dataframes处理事件,这些事件最终会像Parquet格式一样被写出来。

但是,一些JSON事件在键中包含空格,我想在将它转换为Parquet之前从数据框中记录和删除这些事件,因为,; {}()\ n \ t =被认为是特殊的Parquet架构(CatalystSchemaConverter)中的字符在 [1] 中列出,因此不应在列名中使用。

如何在Dataframe上对列名进行此类验证,并完全删除此类事件,而不会错误输出Spark Streaming作业。

[1]  Spark的CatalystSchemaConverter

def checkFieldName(name: String): Unit = {
    // ,;{}()\n\t= and space are special characters in Parquet schema
    checkConversionRequirement(
      !name.matches(".*[ ,;{}()\n\t=].*"),
      s"""Attribute name "$name" contains invalid character(s) among " ,;{}()\\n\\t=".
         |Please use alias to rename it.
       """.stripMargin.split("\n").mkString(" ").trim)
  }

6 个答案:

答案 0 :(得分:2)

对于遇到此错误的pyspark用户,您可以使用此功能对列名进行规范化,然后再写入镶木地板文件:

import re

# invalid characters in parquet column names are replaced by _
def canonical(x): return re.sub("[ ,;{}()\n\t=]+", '_', x.lower())

renamed_cols = [canonical(c) for c in df.columns]
df = df.toDF(*renamed_cols)

如果您也想从列名中删除重音符号,则可以使用:

import unicodedata

# strips accents from string value
def strip_accent(x): return unicodedata.normalize('NFKD', x).encode('ASCII', 'ignore').decode()

放在一起:

renamed_cols = [strip_accent(canonical(c)) for c in df.columns]
df = df.toDF(*renamed_cols)

答案 1 :(得分:1)

对于包含空格的列名,我也遇到了同样的问题。
解决方案的第一部分是将名称放在反引号中。
解决方案的第二部分是用下划线替换空格。

对不起,但是我只准备好了pyspark代码:

from pyspark.sql import functions as F

df_tmp.select(*(F.col("`" + c+ "`").alias(c.replace(' ', '_')) for c in df_tmp.columns)

答案 2 :(得分:1)

这是我使用Regex的解决方案,以便按照实木复合地板约定重命名数据框的所有列:

df.columns.foldLeft(df){
  case (currentDf,  oldColumnName) => currentDf.withColumnRenamed(oldColumnName, oldColumnName.replaceAll("[ ,;{}()\n\t=]", ""))
}

我希望对您有帮助,

答案 3 :(得分:0)

使用alias更改字段名称,而不使用这些特殊字符。

答案 4 :(得分:0)

尝试使用正则表达式替换坏符号。检查我的answer

答案 5 :(得分:0)

对于在pyspark中遇到此问题的每个人:重命名列后,这甚至都发生在我身上。在一些迭代之后,我可以使它工作的一种方法是:

file = "/opt/myfile.parquet"
df = spark.read.parquet(file)
for c in df.columns:
    df = df.withColumnRenamed(c, c.replace(" ", ""))

df = spark.read.schema(df.schema).parquet(file)