【问题标题】:Spark Avro to parquet writing null values in number fieldsSpark Avro 在数字字段中写入空值
【发布时间】:2017-01-05 18:41:30
【问题描述】:

我将 spark 数据框保存为 parquet 文件,并且该数据框具有从 avro 对象构建的行。相同的确切代码在这里 - https://stackoverflow.com/a/41491999/2440775

我面临的挑战是,当传入数据中缺少整数字段时,我打算能够有空值。 Avro 似乎允许通过使用联合类型来实现这一点,但是当我没有在 avsc 中指定默认值或指定默认值“null”时,我会收到如下错误:

Caused by: org.apache.avro.AvroRuntimeException: Field xxx type:LONG pos:7 not set and has no default value
    at org.apache.avro.generic.GenericData.getDefaultValue(GenericData.java:984)
    at org.apache.avro.data.RecordBuilderBase.defaultValue(RecordBuilderBase.java:135)

Or

Caused by: org.apache.avro.AvroRuntimeException: Field xxx type:UNION pos:7 not set and has no default value
    at org.apache.avro.generic.GenericData.getDefaultValue(GenericData.java:984)
    at org.apache.avro.data.RecordBuilderBase.defaultValue(RecordBuilderBase.java:135)

如果我写一个默认值“0”,它 saveAsParquet 效果很好

我还尝试将 avro 规范更改为首先使用“null”类型,因为联合选择了第一个元素的类型。

"type": ["null","long"], "default": null

这会导致如下异常:

org.apache.spark.SparkException: Job aborted due to stage failure: Task 0 in stage 0.0 failed 1 times, most recent failure: Lost task 0.0 in stage 0.0 (TID 0, localhost): java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Long

在 avro 架构中更改 long 和 null 的顺序会导致以下异常

原因:org.apache.avro.AvroTypeException:long 的非数字默认值:null

【问题讨论】:

    标签: apache-kafka apache-spark-sql avro parquet


    【解决方案1】:

    我没有这样的解决方案,但找到了解决方法。我从 avro 对象构建 Row 的方式是从 avro 对象创建一个列表,然后对其执行 Row.fromSeq。解决方法检查默认值 0 和 int 或 long 数据类型。如果是默认值,则添加 null 。因此,必须小心选择默认值。

    public static List avroToList(AvroData a) throws UnsupportedEncodingException{
            List l = new ArrayList<>();
            for (Schema.Field f : a.getSchema().getFields()) {
                Object value = a.get(f.name());
                if (value == null) {
                    l.add(null);
                }
                else {
                    switch (f.schema().getType().getName()){
                        case "union":
                            l.add(value.toString());
                            break;
    
                        case "int":
                            if(value == 0) {l.add(null);}
                            else {l.add(Integer.valueOf(value.toString()));}
                          break;
    
                        case "long":
                            if(value == 0L) {l.add(null);}
                            else {l.add(Long.valueOf(value.toString()));}
                            break;
    
                        default:l.add(value);
                            break;
                    }
    
                }
            }
            return l;
        }
    

    avsc 文件的类型信息如下

    "type": "long",  "default": 0
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-03-07
      • 2014-01-03
      • 1970-01-01
      • 2022-11-10
      • 2017-05-11
      • 2020-10-28
      • 2014-05-21
      • 1970-01-01
      相关资源
      最近更新 更多