Apache spark 将包含无效字符的嵌套字段从Spark 2导出到Parquet
我正在尝试使用spark 2.0.2将JSON文件转换为拼花地板Apache spark 将包含无效字符的嵌套字段从Spark 2导出到Parquet,apache-spark,spark-dataframe,parquet,Apache Spark,Spark Dataframe,Parquet,我正在尝试使用spark 2.0.2将JSON文件转换为拼花地板 JSON文件来自外部源,因此在模式到达之前无法对其进行更改 该文件包含属性映射。属性名在我收到文件之前是未知的 属性名称包含不能在拼花地板中使用的字符 空格和equals字符都不能用于拼花地板,我得到以下错误: org.apache.spark.sql.AnalysisException: Attribute name "name=attribute" contains invalid character(s) among "
- JSON文件来自外部源,因此在模式到达之前无法对其进行更改
- 该文件包含属性映射。属性名在我收到文件之前是未知的
- 属性名称包含不能在拼花地板中使用的字符
到目前为止,我发现唯一有效的解决方案是使用修改过的模式重新加载数据。新模式将把属性加载到映射中
Dataset<Row> newData = sql.read().json(path);
StructType newSchema = (StructType) toMapType(newData.schema(), null, "attributes");
newData = sql.read().schema(newSchema).json(path);
Dataset newData=sql.read().json(路径);
StructType newSchema=(StructType)toMapType(newData.schema(),null,“attributes”);
newData=sql.read().schema(newSchema).json(path);
private数据类型toMapType(数据类型DataType,字符串fullColName,字符串col){
if(数据类型instanceof StructType){
StructType StructType=(StructType)数据类型;
列表重命名=Arrays.stream(structType.fields()).map(
f->toMapType(f,fullColName==null?f.name():fullColName+““+f.name(),col)).collect(Collectors.toList());
返回新的StructType(重命名为.toArray(新的StructField[重命名为.size()]);
}
返回数据类型;
}
私有StructField toMapType(StructField StructField,String fullColName,String col){
if(fullColName.equals(col)){
返回新的StructField(col,new-MapType(DataTypes.StringType,DataTypes.LongType,true),true,Metadata.empty());
}else if(col.startsWith(fullColName)){
返回新的StructField(StructField.name()、toMapType(StructField.dataType()、fullColName、col)、StructField.nullable()、StructField.metadata());
}
返回结构域;
}
我对@:
也有同样的问题
在我们的例子中,我们解决了美化数据帧的问题
val ALIAS_RE: Regex = "[_.:@]+".r
val FIRST_AT_RE: Regex = "^_".r
def getFieldAlias(field_name: String): String = {
FIRST_AT_RE.replaceAllIn(ALIAS_RE.replaceAllIn(field_name, "_"), "")
}
def selectFields(df: DataFrame, fields: List[String]): DataFrame = {
var fields_to_select = List[Column]()
for (field <- fields) {
val alias = getFieldAlias(field)
fields_to_select +:= col(field).alias(alias)
}
df.select(fields_to_select: _*)
}
将被转换的[对象,架构。@类型,架构。name@id]。
@和点(在您的情况下,=)将为SparkSQL创建问题
所以在我们选择字段之后,您可以以
[对象、模式类型、模式名称\u id]。恭维的数据帧。我通过以下方式解决了问题:
val ALIAS_RE: Regex = "[_.:@]+".r
val FIRST_AT_RE: Regex = "^_".r
def getFieldAlias(field_name: String): String = {
FIRST_AT_RE.replaceAllIn(ALIAS_RE.replaceAllIn(field_name, "_"), "")
}
def selectFields(df: DataFrame, fields: List[String]): DataFrame = {
var fields_to_select = List[Column]()
for (field <- fields) {
val alias = getFieldAlias(field)
fields_to_select +:= col(field).alias(alias)
}
df.select(fields_to_select: _*)
}
df.toDF(df
.schema
.fieldNames
.map(name => "[ ,;{}()\\n\\t=]+".r.replaceAllIn(name, "_")): _*)
我将所有不正确的符号替换为“u”。您得到解决方案了吗?我仍在使用我发布的解决方案。不应将其标记为重复。这个问题是关于嵌套列的,与另一个问题完全不同@eliasah你怎么看?这只适用于没有嵌套字段的模式,OP的问题是关于嵌套字段的。你可以重做任何你想要的模式。您只需要实现scheme树,并对所有名称应用regexp模式。如何实现树下降超出了这个问题的范围
private DataType toMapType(DataType dataType, String fullColName, String col) {
if (dataType instanceof StructType) {
StructType structType = (StructType) dataType;
List<StructField> renamed = Arrays.stream(structType.fields()).map(
f -> toMapType(f, fullColName == null ? f.name() : fullColName + "." + f.name(), col)).collect(Collectors.toList());
return new StructType(renamed.toArray(new StructField[renamed.size()]));
}
return dataType;
}
private StructField toMapType(StructField structField, String fullColName, String col) {
if (fullColName.equals(col)) {
return new StructField(col, new MapType(DataTypes.StringType, DataTypes.LongType, true), true, Metadata.empty());
} else if (col.startsWith(fullColName)) {
return new StructField(structField.name(), toMapType(structField.dataType(), fullColName, col), structField.nullable(), structField.metadata());
}
return structField;
}
val ALIAS_RE: Regex = "[_.:@]+".r
val FIRST_AT_RE: Regex = "^_".r
def getFieldAlias(field_name: String): String = {
FIRST_AT_RE.replaceAllIn(ALIAS_RE.replaceAllIn(field_name, "_"), "")
}
def selectFields(df: DataFrame, fields: List[String]): DataFrame = {
var fields_to_select = List[Column]()
for (field <- fields) {
val alias = getFieldAlias(field)
fields_to_select +:= col(field).alias(alias)
}
df.select(fields_to_select: _*)
}
{
object: 'blabla',
schema: {
@type: 'blabla',
name@id: 'blabla'
}
}
df.toDF(df
.schema
.fieldNames
.map(name => "[ ,;{}()\\n\\t=]+".r.replaceAllIn(name, "_")): _*)