使用Ruby的red-parquet gem修改Parquet文件列类型的问题
问题解决:Parquet文件列类型从String转Int32(Ruby red-parquet)
问题根源
你的代码没生效是因为Arrow::Table是不可变对象,调用cast方法只会返回转换后的新列,不会修改原table。原代码里调用table.heading.cast('int32')后没有将结果赋值回table,相当于白做了转换,保存的还是原始数据。
修正后的代码
require 'arrow' require 'fileutils' def cast_col(target_col = :heading) files_written = 0 get_parquets.each do |file| table = Arrow::Table.load(file) # 检查目标列的类型是否为string col = table[target_col] next unless col.data_type.to_s == "string" new_file_loc = File.join(@save_dir, File.basename(file)) # 用File.join避免路径拼接问题 puts "Processing: #{new_file_loc}" # 创建目标目录 FileUtils.mkdir_p(File.dirname(new_file_loc)) begin # 转换列类型,返回新的列对象 casted_col = col.cast('int32') # 用转换后的列替换原table中的对应列,生成新的table new_table = table.select(table.schema.fields.reject { |f| f.name == target_col.to_s }) .add_column(casted_col) # 保存新table new_table.save(new_file_loc) files_written += 1 rescue => e puts "Failed to process #{file}: #{e.message}" # 根据需求选择跳过或终止 next end end puts "Number of Files Written: #{files_written}" end
关键改进点
- 不可变对象处理:明确生成新的列和新的table,而不是修改原对象
- 路径安全:用
File.join拼接路径,避免因操作系统差异导致的路径错误 - 异常处理:捕获转换时的异常(比如字符串无法转为整数的情况),避免批量处理中断
- 列选择逻辑:通过
select+add_column确保只替换目标列,保留其他列的结构和数据
额外建议
- 转换验证:处理完部分文件后,加载新文件验证列类型:
test_table = Arrow::Table.load(new_file_loc) puts test_table[target_col].data_type # 应该输出int32 - 性能优化:700个文件可以考虑用并行处理(比如
Parallelgem),但要注意内存占用,避免同时加载过多大文件 - 数据校验:转换前可以先检查列中所有字符串是否都是合法整数,避免转换失败:
invalid_rows = col.data.select { |val| val !~ /^\d+$/ }.compact unless invalid_rows.empty? puts "File #{file} has invalid integer strings: #{invalid_rows.take(5)}" next end
内容的提问来源于stack exchange,提问作者Smithy
相关产品推荐
相关产品推荐

