You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将Polars DataFrame的AnyValue类型行/HashMap序列化为JSON?

问题:Polars DataFrame行转JSON时Datetime序列化失败

我通过迭代器读取Parquet文件生成Polars DataFrame的一行,构建代表该行的HashMap后,尝试转换为JSON时遇到了序列化错误。

我的Rust代码如下:

use polars::prelude::*;
use std::iter::zip;
use std::{fs::File, collections::HashMap};

fn main() -> anyhow::Result<()> {

    let file = File::open("0.parquet").unwrap();
    let mut df = ParquetReader::new(file).finish()?;
    dbg!(df.schema());
    let fields = df.fields();
    let columns: Vec<&String> = fields.iter().map(|x| x.name()).collect();

    df.as_single_chunk_par();
    let mut iters = df.iter().map(|s| s.iter()).collect::<Vec<_>>();

    for _ in 0..df.height() {
        let mut row = HashMap::new();
        for (column, iter) in zip(&columns, &mut iters) {
            let value = iter.next().expect("should have as many iterations as rows");
            row.insert(column, value);
        }
        dbg!(&row);
        let json = serde_json::to_string(&row).unwrap();
        dbg!(json);
        break;
    }

    Ok(())
}

启用的特性标志:["parquet", "serde", "dtype-u8", "dtype-i8", "dtype-date", "dtype-datetime"]

执行serde_json::to_string(&row).unwrap()时触发错误:

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error("the enum variant AnyValue::Datetime cannot be serialized", line: 0, column: 0)', src/main.rs:47:48

另外,由于Rust的孤儿规则,我无法自行实现AnyValue::Datetime的序列化。请问将该行序列化为JSON的最佳方法是什么?


解决方案

方法1:利用Polars内置的JSON序列化能力

Polars本身支持将DataFrame或行直接序列化为JSON,不需要手动构建HashMap,能自动处理所有数据类型的序列化:

use polars::prelude::*;
use std::fs::File;

fn main() -> anyhow::Result<()> {
    let file = File::open("0.parquet").unwrap();
    let mut df = ParquetReader::new(file).finish()?;
    df.as_single_chunk_par();

    // 取第一行并转为JSON
    let first_row = df.slice(0, 1);
    let json_str = first_row.write_json(JsonWriterOptions::default())?;
    dbg!(json_str);

    Ok(())
}

方法2:手动转换AnyValue为可序列化类型

如果必须保留手动构建HashMap的逻辑,可以将AnyValue转换为serde_json::Value类型,手动处理每种数据类型的序列化:

use polars::prelude::*;
use std::iter::zip;
use std::{fs::File, collections::HashMap};
use serde_json::Value;

fn any_value_to_json_value(val: AnyValue<'_>) -> Value {
    match val {
        AnyValue::Null => Value::Null,
        AnyValue::Boolean(b) => Value::Bool(b),
        AnyValue::UInt8(n) => Value::Number(n.into()),
        AnyValue::Int8(n) => Value::Number(n.into()),
        AnyValue::Datetime(dt, tu, tz) => {
            // 转为RFC3339格式字符串,可根据需求调整输出格式
            let naive_dt = dt.to_naive_datetime(tu);
            if let Some(tz) = tz {
                let dt_with_tz = naive_dt.and_local_timezone(tz).unwrap();
                Value::String(dt_with_tz.to_rfc3339())
            } else {
                Value::String(naive_dt.to_rfc3339())
            }
        }
        // 按需添加其他数据类型的处理逻辑
        _ => Value::String(val.to_string()), // 兜底用字符串表示未处理的类型
    }
}

fn main() -> anyhow::Result<()> {
    let file = File::open("0.parquet").unwrap();
    let mut df = ParquetReader::new(file).finish()?;
    dbg!(df.schema());
    let fields = df.fields();
    let columns: Vec<&String> = fields.iter().map(|x| x.name()).collect();

    df.as_single_chunk_par();
    let mut iters = df.iter().map(|s| s.iter()).collect::<Vec<_>>();

    for _ in 0..df.height() {
        let mut row = HashMap::new();
        for (column, iter) in zip(&columns, &mut iters) {
            let value = iter.next().expect("should have as many iterations as rows");
            let json_val = any_value_to_json_value(value);
            row.insert(column.clone(), json_val);
        }
        dbg!(&row);
        let json = serde_json::to_string(&row).unwrap();
        dbg!(json);
        break;
    }

    Ok(())
}

方法3:使用Polars的Row类型

Polars的Row类型已实现serde序列化(需启用serde特性),可以直接序列化:

use polars::prelude::*;
use std::fs::File;
use serde_json::to_string;

fn main() -> anyhow::Result<()> {
    let file = File::open("0.parquet").unwrap();
    let mut df = ParquetReader::new(file).finish()?;
    df.as_single_chunk_par();

    // 获取行迭代器并取第一行
    let mut row_iter = df.iter_rows();
    if let Some(row) = row_iter.next() {
        let json = to_string(&row)?;
        dbg!(json);
    }

    Ok(())
}

内容的提问来源于stack exchange,提问作者Al Johri

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 22:35:20