使用不同的字段名称在Java类上映射Avro文件

时间:2018-01-29 07:42:52

标签: java apache-spark spark-dataframe spark-avro

我遇到了简单的火花任务问题,该任务会读取Avro文件,然后将其保存为Hive镶木桌。

我有两种类型的文件,一般来说它们是相同的,但是关键结构有点不同 - 字段名称。

输入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是一个带getter和setter的简单单字段类。

public class SomeClass{
    private String term_id;
    ...
}

因此,如果我正在阅读Avro类型1 - 那就没关系。但如果我正在阅读Avro类型2 - 则会发生错误。反之亦然,如果我将字段名称更改为private String id;

我的问题有没有通用的解决方案?我找到了@AvroName,但它不允许设置多个名字。 感谢。

2 个答案:

答案 0 :(得分:1)

只有一种方法是将数据集fieldname更改为schema中的名称。 使用此示例执行此操作:

AttachDocuments

您无法将数据框强制转换为具有不同字段名称的BeanClass。

答案 1 :(得分:1)

可能的解决方案是

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的第二个字段将被命名为#34; id&#34;并包含字符串键。第一个&#34; pk&#34; struct可以在将来删除。

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();

此代码适用于任何原始\ String键。