如何在Polars-Rust中将JSON字符串列导出为JSON数组文件
问题描述
我有一个包含合法JSON字符串列的DataFrame,希望将该列内容转换为每行对应一个对象的JSON数组文件,寻求合适的实现方案。
在Python中我用Polars实现的代码如下:
import polars as pl import json df = df.with_columns( pl.col("my_str_column").str.json_decode() ) column_as_list = df.select(pl.col("my_str_column")).to_series().to_list() with open('target_file.json', 'w+') as w: w.write(json.dumps([ob for ob in column_as_list]))
这个方案能正常运行但并非最优。现在想转换成Polars-Rust实现,目前完成了将列转为struct类型的步骤:
df = df.lazy().with_column( col("my_str_column").str().json_decode(None, Some(100)) ).collect()?;
之后我移除了json_decode()保留字符串列,实现了以下可运行的代码,但不确定是否是最优方式,希望得到优化建议:
// hacky way to convert the desired column into a series let binding = df.select("my_str_column").pop().unwrap(); let series_collect: Vec<&str> = binding.str().unwrap().into_no_null_iter().collect(); // Convert input into Vec<Value>, by parsing each string let elems = series_collect.into_iter() .map(serde_json::from_str) .collect::<Result<Vec<Value>,_>>() .unwrap(); let json_val = Value::Array(elems); // now write this json_val into disk let mut path = std::env::current_dir()?; path.push("target_file.json"); let file = File::create(path)?; let mut writer = BufWriter::new(file); serde_json::to_writer(&mut writer, &json_val).unwrap(); writer.flush()?;
优化建议
1. 复用Polars解析结果,避免重复JSON解析
既然已经通过json_decode()将列转为Struct类型,直接基于解析后的Struct序列化,无需先转回字符串再重新解析,减少性能开销:
use polars::prelude::*; use serde_json::{self, Value}; use std::fs::File; use std::io::BufWriter; // 假设已完成json_decode并得到含Struct列的DataFrame let struct_series = df.column("my_str_column").unwrap(); // 将Struct列序列化为JSON数组 let values: Result<Vec<Value>, _> = struct_series .struct_() .unwrap() .iter() .map(|struct_val| serde_json::to_value(struct_val)) .collect(); let json_array = Value::Array(values.unwrap()); // 写入文件 let path = std::env::current_dir()?.join("target_file.json"); let file = File::create(path)?; let mut writer = BufWriter::new(file); serde_json::to_writer(&mut writer, &json_array)?; writer.flush()?;
2. 流式写入降低内存占用
如果处理大数据集,避免把所有JSON对象加载到内存,改用流式写入:手动拼接JSON数组格式,逐个序列化Struct元素写入文件:
use polars::prelude::*; use serde_json; use std::fs::File; use std::io::{BufWriter, Write}; // 假设已完成json_decode的DataFrame let struct_series = df.column("my_str_column").unwrap(); let struct_iter = struct_series.struct_().unwrap().iter(); let path = std::env::current_dir()?.join("target_file.json"); let file = File::create(path)?; let mut writer = BufWriter::new(file); // 写入数组开头 writer.write_all(b"[")?; let mut first = true; for struct_val in struct_iter { if !first { writer.write_all(b",")?; } first = false; // 直接序列化当前Struct到文件 serde_json::to_writer(&mut writer, struct_val)?; } // 写入数组结尾 writer.write_all(b"]")?; writer.flush()?;
3. 优化错误处理与列获取
- 替换
unwrap()为?传播错误,避免生产环境panic,建议将逻辑封装为返回Result<(), Box<dyn std::error::Error>>的函数; - 用
df.column("my_str_column").unwrap()替代df.select("my_str_column").pop().unwrap(),避免不必要的DataFrame拷贝。
内容的提问来源于stack exchange,提问作者willsbit
相关产品推荐
相关产品推荐

