使用不同的字段名称映射 Java class 上的 Avro 文件
Map Avro files on Java class with different field names
我遇到了一个简单的 spark 任务问题,它读取 Avro 文件然后将其保存为 Hive parquet table。
我有两种类型的文件,一般来说它们是相同的,但关键结构有点不同 - 字段名称。
类型 1
root
|-- pk: strucnt (nullable = true)
|-- term_id: string (nullale = true)
类型 2
root
|-- pk: strucnt (nullable = true)
|-- id: string (nullale = true)
我正在使用 spark-avro 阅读 Avro。然后像这样将这个 DF 映射到 bean
Dataset<SomeClass> df = avroDF.as(Encoders.bean(SomeClass.class));
SomeClass 是一个简单的单字段 class,具有 getter 和 setter。
public class SomeClass{
private String term_id;
...
}
因此,如果我正在阅读 Avro 类型 1 - 没关系。但是如果我正在阅读 Avro type 2 - 就会发生错误。反之亦然,如果我将字段名称更改为 private String id;
我的问题有通用的解决方案吗?我找到了@AvroName,但它不允许设置多个名称。
谢谢。
只有一种方法是将数据集字段名更改为架构中的名称。
使用这个例子来做:
val newName = Seq("id", "x1", "x2", "x3")
Dataset<SomeClass> df = avroDF.toDF(newNames: _*).as(Encoders.bean(SomeClass.class));
您不能将数据帧转换为具有不同字段名称的 BeanClass。
可能的解决方案是
StructType avroExtendedSchema = avroDF.schema().add("id",DataTypes.StringType);
avroDF.map(row->RowFactory(row.getStruct(0),row.getStruct(0).getString(0)),
RowEncoder.apply(avroExtendedSchema)).toDF();
因此 DF 的第二个字段将被命名为 "id" 并包含字符串键。第一个 "pk" 结构将来可以删除。
avroDF.drop("pk");
PS
我找到了第三种模式:
root
|-- pk: strucnt (nullable = true)
|-- id: int(nullale = true)
所以最终的代码是这样的:
DataType keyType = avroDF.select("pk.*").schema().fields[0].dataType();
StructType avroExtendedSchema = avroDF.schema().add("id",keyType);
avroDF.map(row->RowFactory(row.getStruct(0),row.getStruct(0).get(0)),
RowEncoder.apply(avroExtendedSchema)).drop("pk").toDF();
此代码适用于任何 primitive\String 键。
我遇到了一个简单的 spark 任务问题,它读取 Avro 文件然后将其保存为 Hive parquet table。
我有两种类型的文件,一般来说它们是相同的,但关键结构有点不同 - 字段名称。
类型 1
root
|-- pk: strucnt (nullable = true)
|-- term_id: string (nullale = true)
类型 2
root
|-- pk: strucnt (nullable = true)
|-- id: string (nullale = true)
我正在使用 spark-avro 阅读 Avro。然后像这样将这个 DF 映射到 bean
Dataset<SomeClass> df = avroDF.as(Encoders.bean(SomeClass.class));
SomeClass 是一个简单的单字段 class,具有 getter 和 setter。
public class SomeClass{
private String term_id;
...
}
因此,如果我正在阅读 Avro 类型 1 - 没关系。但是如果我正在阅读 Avro type 2 - 就会发生错误。反之亦然,如果我将字段名称更改为 private String id;
我的问题有通用的解决方案吗?我找到了@AvroName,但它不允许设置多个名称。 谢谢。
只有一种方法是将数据集字段名更改为架构中的名称。 使用这个例子来做:
val newName = Seq("id", "x1", "x2", "x3")
Dataset<SomeClass> df = avroDF.toDF(newNames: _*).as(Encoders.bean(SomeClass.class));
您不能将数据帧转换为具有不同字段名称的 BeanClass。
可能的解决方案是
StructType avroExtendedSchema = avroDF.schema().add("id",DataTypes.StringType);
avroDF.map(row->RowFactory(row.getStruct(0),row.getStruct(0).getString(0)),
RowEncoder.apply(avroExtendedSchema)).toDF();
因此 DF 的第二个字段将被命名为 "id" 并包含字符串键。第一个 "pk" 结构将来可以删除。
avroDF.drop("pk");
PS 我找到了第三种模式:
root
|-- pk: strucnt (nullable = true)
|-- id: int(nullale = true)
所以最终的代码是这样的:
DataType keyType = avroDF.select("pk.*").schema().fields[0].dataType();
StructType avroExtendedSchema = avroDF.schema().add("id",keyType);
avroDF.map(row->RowFactory(row.getStruct(0),row.getStruct(0).get(0)),
RowEncoder.apply(avroExtendedSchema)).drop("pk").toDF();
此代码适用于任何 primitive\String 键。