///|
/// parquet 列存内存模型演示: 基因表达表 -> 行组统计 -> 谓词下推 ->
/// 投影下推 -> 字典编码 -> JSON 持久化.
fn main raise {
// 1. 构建基因表达列存表(3 个行组, fpkm 量级按行组分离)
let t = @src.ParquetTable::new([
("gene", @src.PStr),
("chrom", @src.PStr),
("fpkm", @src.PDouble),
("log2fc", @src.PDouble),
("padj", @src.PDouble),
("expressed", @src.PBool),
])
let rng = @src.Rng::from_int(42)
let bases = [0.0, 50.0, 200.0]
let chroms = ["chr1", "chr2", "chr3"]
for g in 0..<3 {
for i in 0..<40 {
let gi = g * 40 + i
let fpkm = bases[g] + rng.next_int(40).to_double()
let padj = (rng.next_int(100).to_double() + 1.0) / 400.0
ignore(
t.add_row([
@src.PvStr("gene" + (gi + 1).to_string()),
@src.PvStr(chroms[rng.next_int(3)]),
@src.PvDouble(fpkm),
@src.PvDouble((rng.next_int(200).to_double() - 100.0) / 100.0),
@src.PvDouble(padj),
@src.PvBool(fpkm > 1.0),
]),
)
}
ignore(t.flush_row_group())
}
println("=== parquet 列存表 (120 行 x 6 列, 3 行组) ===")
println(" 列: " + t.column_names().join(", "))
println(
" 行组: " +
t.num_row_groups().to_string() +
", 总行数: " +
t.num_rows().to_string(),
)
// 2. 行组统计(min/max 元数据)
println("=== 行组统计 (fpkm 列 min/max) ===")
for g in 0..<3 {
let st = t.chunk_stats(g, "fpkm")
let lo = match st.min {
Some(@src.PvDouble(v)) => v.to_string()
_ => "?"
}
let hi = match st.max {
Some(@src.PvDouble(v)) => v.to_string()
_ => "?"
}
println(" 行组 " + g.to_string() + ": [" + lo + ", " + hi + "]")
}
// 3. 谓词下推: fpkm >= 100 只应扫描行组 3
let hot = t.scan(filters=[
{ column: "fpkm", op: @src.OpGe, value: @src.PvDouble(100.0), },
])
println("=== 谓词下推 scan (fpkm >= 100) ===")
println(
" 命中 " +
hot.rows.length().to_string() +
" 行; 扫描行组 " +
hot.groups_scanned.to_string() +
" / 跳过 " +
hot.groups_skipped.to_string() +
" (统计区间裁剪, 未读行组数据)",
)
// 4. 投影下推 + 组合谓词
let sig = t.scan(columns=["gene", "fpkm", "padj"], filters=[
{ column: "padj", op: @src.OpLt, value: @src.PvDouble(0.05), },
{ column: "expressed", op: @src.OpEq, value: @src.PvBool(true), },
])
println("=== 投影 + 谓词 scan (padj < 0.05 AND expressed) ===")
println(
" 显著差异基因: " +
sig.rows.length().to_string() +
" 个 (只物化 3/6 列)",
)
if sig.rows.length() > 0 {
let row = sig.rows[0]
let gn = match row[0] {
@src.PvStr(s) => s
_ => "?"
}
let fv = match row[1] {
@src.PvDouble(v) => v.to_string()
_ => "?"
}
let pv = match row[2] {
@src.PvDouble(v) => v.to_string()
_ => "?"
}
println(" 示例: " + gn + " fpkm=" + fv + " padj=" + pv)
}
// 5. 字典编码(chrom 列高度重复)
let chrom_col : Array[@src.ParquetValue] = t.read_column("chrom")
let chrom_strs : Array[String] = []
for v in chrom_col {
match v {
@src.PvStr(s) => chrom_strs.push(s)
_ => ()
}
}
let (dict, idx) = @src.parquet_dict_encode(chrom_strs)
println("=== 字典编码 (chrom 列, DICT 编码语义) ===")
println(
" " +
chrom_strs.length().to_string() +
" 个值 → 字典 " +
dict.length().to_string() +
" 项 (压缩比 " +
(chrom_strs.length().to_double() / dict.length().to_double()).to_string() +
"x); 首行索引: " +
idx[0].to_string(),
)
// 6. JSON 持久化往返
let json = t.to_json()
let back = @src.parquet_from_json(json).unwrap()
println("=== JSON 持久化往返 ===")
println(
" 行数 " +
back.num_rows().to_string() +
" == " +
t.num_rows().to_string() +
", 行组 " +
back.num_row_groups().to_string() +
" == " +
t.num_row_groups().to_string() +
", JSON 字节数: " +
json.length().to_string(),
)
println("")
println(
"注: 本模块为 parquet 列存内存模型(JSON 持久化), 非 .parquet 二进制",
)
println(
" 容器; 与 .parquet 互操作建议经 JSON/CSV 导入导出衔接.",
)
}