Java中JSON转Parquet抛出InvalidSchemaException异常求助
解决Parquet写入时的InvalidSchemaException(空group错误)
这个问题我之前也碰到过,核心原因是Parquet需要明确的、非空的Schema结构,但你用List<Map<String, Object>>作为字段类型时,ReflectData无法推断出Map里具体的字段和类型,最终生成了空的group,触发了异常。
解决方案:用具体实体类替代Map
最可靠的方式是创建一个对应JSON对象的实体类,让ReflectData能正确生成包含所有字段的Schema。
1. 创建对应JSON元素的实体类
新建DataPoint类,对应你JSON数组里的每个对象:
public class DataPoint { private double mainBearingX; private double gearBoxZ; private long _t; private double mainBearingZ; private double gearBoxX; private double mainBearingY; private double gearBoxY; private double generatorX; private double generatorY; private String ts_id; // 必须添加getter方法,ReflectData依赖getter识别字段 public double getMainBearingX() { return mainBearingX; } public double getGearBoxZ() { return gearBoxZ; } public long get_t() { return _t; } public double getMainBearingZ() { return mainBearingZ; } public double getGearBoxX() { return gearBoxX; } public double getMainBearingY() { return mainBearingY; } public double getGearBoxY() { return gearBoxY; } public double getGeneratorX() { return generatorX; } public double getGeneratorY() { return generatorY; } public String getTs_id() { return ts_id; } // 可选:添加setter方便赋值 public void setMainBearingX(double mainBearingX) { this.mainBearingX = mainBearingX; } public void setGearBoxZ(double gearBoxZ) { this.gearBoxZ = gearBoxZ; } public void set_t(long _t) { this._t = _t; } public void setMainBearingZ(double mainBearingZ) { this.mainBearingZ = mainBearingZ; } public void setGearBoxX(double gearBoxX) { this.gearBoxX = gearBoxX; } public void setMainBearingY(double mainBearingY) { this.mainBearingY = mainBearingY; } public void setGearBoxY(double gearBoxY) { this.gearBoxY = gearBoxY; } public void setGeneratorX(double generatorX) { this.generatorX = generatorX; } public void setGeneratorY(double generatorY) { this.generatorY = generatorY; } public void setTs_id(String ts_id) { this.ts_id = ts_id; } }
2. 修改OutPut类的字段类型
把原来的List<Map<String, Object>>换成List<DataPoint>:
public class OutPut { private List<DataPoint> list; // 添加getter和setter public List<DataPoint> getList() { return list; } public void setList(List<DataPoint> list) { this.list = list; } }
3. 完善转换代码(别忘了写入数据)
你原来的代码只创建了Writer,但没有实际写入数据,这里补充上writer.write(output):
public static void toConvert(OutPut output) { String inputFile = "test.parquetFile"; Path dataFile = new Path(inputFile); Schema schema = ReflectData.AllowNull.get().getSchema(OutPut.class); try (ParquetWriter<OutPut> writer = AvroParquetWriter.<OutPut>builder(dataFile) .withSchema(schema) .withDataModel(ReflectData.get()) .withConf(new Configuration()) .withCompressionCodec(CompressionCodecName.SNAPPY) .withWriteMode(Mode.OVERWRITE) .build()) { // 关键:将你的数据对象写入Parquet文件 writer.write(output); } catch (IOException e) { e.printStackTrace(); } }
为什么这样能解决问题?
Parquet是强Schema的列式存储格式,必须提前明确每个字段的名称、类型等信息。Map<String, Object>是动态结构,ReflectData无法确定里面有哪些字段、每个字段是什么类型,所以生成了空的group结构,而Parquet禁止写入空group的Schema。用具体实体类后,ReflectData可以通过类的getter方法自动生成完整合法的Schema,Writer就能正常工作了。
如果你的JSON字段是动态不固定的,可以考虑用Avro的GenericRecord手动构建Schema,但静态实体类是字段固定场景下最简单可靠的方案。
内容的提问来源于stack exchange,提问作者raj03
相关产品推荐
相关产品推荐

