如何在Java Parquet-Avro Schema中定义JSON逻辑类型
现有如下JSON对象:
{ "key1" : "value1", "key2" : { "key3" : "value3", ... } }
其中key2是可空且无固定键集合的JSON对象。需要在Avro Schema中将key2定义为JSON逻辑类型,使用Java Parquet-Avro 1.12.0实现,但未找到合适示例。期望的Schema如下:
{ "name": "Json", "type": "record", "fields": [ { "name": "key1", "type": "string" }, { "name": "key2", "type": [ "null", { "type": "string", "logicalType": "json" } ] } ] }
尝试上述Schema通过AvroParquetWriter转换后,pyarrow等工具中key2的元数据显示为logical_type: byte_array,而非预期的logical_type: json。另外参考Timestamp逻辑类型的实现方式时,发现Java Parquet-Avro的LogicalTypes类中并没有JSON类型。需要在不自行实现LogicalType的前提下解决该问题。
Avro 1.12.0官方并未内置JSON逻辑类型,不过可以通过手动为Avro字段添加Parquet元数据的方式,让下游工具识别出JSON逻辑类型,无需自行实现LogicalType:
方法:给Avro字段添加Parquet逻辑类型元数据
在Java代码中构建Avro Schema时,为key2字段手动添加Parquet层面的元数据属性,指定其逻辑类型为JSON:
import org.apache.avro.Schema; import java.util.Arrays; // 构建key2的联合类型(null + string) Schema key2UnionType = Schema.createUnion(Arrays.asList( Schema.create(Schema.Type.NULL), Schema.create(Schema.Type.STRING) )); // 创建key2字段并添加Parquet元数据 Schema.Field key2Field = new Schema.Field( "key2", key2UnionType, "可空的JSON对象", null ); // 标记Parquet逻辑类型为json key2Field.addProp("parquet.logical.type", "json"); // 指定存储变体为string(对应Avro的string类型) key2Field.addProp("parquet.logical.type.variant", "string"); // 构建完整的Record Schema Schema jsonRecordSchema = Schema.createRecord( "Json", null, null, false, Arrays.asList( new Schema.Field("key1", Schema.create(Schema.Type.STRING), null, null), key2Field ) );
使用这个Schema创建AvroParquetWriter写入数据后,pyarrow等工具读取时就能识别到key2的logical_type: json。
原理说明
Avro本身的logicalType字段仅对官方内置类型(如timestamp、decimal等)生效,自定义的logicalType: json不会被Parquet-Avro自动解析。通过直接添加Parquet原生的元数据属性,能绕过Avro的逻辑类型限制,让下游工具正确识别JSON类型。
内容的提问来源于stack exchange,提问作者user25703408

