Noções Básicas de Dados
9 exemplos para você começar com dados de alto desempenho em Rust - 7 básicos e 2 intermediários.
Pré-requisitos
cargo new data-playground && cd data-playground
cargo add polars --features lazy,csv,parquet
cargo add arrow
cargo add clap --features deriveFerramentas: Os exemplos visam Rust 1.97.0 (edição 2024) e Polars 0.46+.
Exemplos Básicos
1. Ler um CSV com Polars (eager)
Carregue um arquivo pequeno e inspecione o schema antes de qualquer transformação.
use polars::prelude::*;
fn main() -> PolarsResult<()> {
let df = CsvReadOptions::default()
.with_has_header(true)
.try_into_reader_with_file_path(Some("sales.csv".into()))?
.finish()?;
println!("{}", df.head(Some(3)));
Ok(())
}CsvReadOptionscentraliza delimitador, dtypes e tratamento de nulos.- O modo eager materializa o frame completo - bom para arquivos que cabem na RAM.
- Defina dtypes explícitos cedo para evitar inferência silenciosa de string em colunas numéricas.
Relacionado: I/O de CSV/Parquet - ajuste específico do formato
2. Escanear preguiçosamente e filtrar antes de coletar
Empurre predicados para baixo para que o Polars leia menos dados do disco.
use polars::prelude::*;
fn main() -> PolarsResult<()> {
let q = LazyCsvReader::new("events.csv".into())
.with_has_header(true)
.finish()?
.filter(col("amount").gt(lit(100)))
.select([col("user_id"), col("amount")]);
let df = q.collect()?;
println!("linhas: {}", df.height());
Ok(())
}- Planos preguiçosos otimizam antes da execução - filtros e seleções de coluna se fundem.
collect()é o limite onde a memória é alocada para o resultado.- Prefira pipelines preguiçosos quando a fonte for maior que a RAM disponível.
Relacionado: Polars - compromissos entre lazy e eager
3. Agregação group-by em uma expressão
Resuma métricas sem mapas hash manuais.
use polars::prelude::*;
fn revenue_by_region(df: LazyFrame) -> PolarsResult<LazyFrame> {
Ok(df
.group_by([col("region")])
.agg([col("revenue").sum().alias("total_revenue")])
.sort(["total_revenue"], SortMultipleOptions::default()))
}group_by+aggmapeia claramente paraGROUP BYdo SQL.- Ordenar no plano preguiçoso mantém junções downstream mais baratas.
- Nomeie aliases explicitamente - expressões sem nome são mais difíceis de depurar em planos.
4. Juntar dois frames em uma chave
Mesclagens estilo relacional sem sair do Rust.
use polars::prelude::*;
fn join_users(orders: LazyFrame, users: LazyFrame) -> LazyFrame {
orders.join(
users,
[col("user_id")],
[col("id")],
JoinArgs::new(JoinType::Inner),
)
}- Junções internas descartam chaves não correspondentes - valide contagens de linhas após a junção.
- Converta colunas de chave para o mesmo dtype antes de juntar para evitar incompatibilidades silenciosas.
- Para tabelas grandes, filtre cada lado antes de juntar para reduzir os conjuntos de trabalho.
5. Escrever Parquet para análise downstream
Saída colunar comprime bem e preserva tipos.
use polars::prelude::*;
fn write_parquet(df: &mut DataFrame, path: &str) -> PolarsResult<()> {
let file = std::fs::File::create(path)?;
ParquetWriter::new(file).finish(df)?;
Ok(())
}- Parquet armazena estatísticas de coluna - motores de consulta podem pular grupos de linhas.
- Compressão ZSTD é um bom padrão para cargas de trabalho analíticas.
- Particione saídas grandes por data ou região para leituras seletivas mais rápidas.
Relacionado: I/O de CSV/Parquet - compressão e schema
6. Transmitir CSV em blocos
Limite a memória quando o arquivo exceder a RAM.
use polars::prelude::*;
use std::fs::File;
fn process_chunks(path: &str, chunk_rows: usize) -> PolarsResult<()> {
let file = File::open(path)?;
let reader = CsvReader::new(file).with_chunk_size(chunk_rows);
for chunk in reader.into_iter() {
let df = chunk?;
println!("linhas do bloco: {}", df.height());
}
Ok(())
}- Leitores em blocos nunca carregam o arquivo completo de uma vez.
- Agregue parciais por bloco, depois reduza - não mantenha cada bloco na memória.
- Escolha o tamanho do bloco a partir da RAM disponível e da largura da coluna.
Relacionado: Streaming e Dados Grandes - padrões de backpressure
7. Construir uma CLI de dados com clap
Envie ETL como um binário único com flags tipadas.
use clap::Parser;
use polars::prelude::*;
#[derive(Parser)]
struct Cli {
#[arg(long)]
input: String,
#[arg(long, default_value = "out.parquet")]
output: String,
}
fn main() -> PolarsResult<()> {
let cli = Cli::parse();
let mut df = CsvReadOptions::default()
.try_into_reader_with_file_path(Some(cli.input.into()))?
.finish()?;
ParquetWriter::new(std::fs::File::create(&cli.output)?).finish(&mut df)?;
Ok(())
}clapderive fornece texto de ajuda e validação gratuitamente.- Retorne
PolarsResultdemainpara cadeias de erro legíveis. - Adicione flags
--filterou--columnsconforme seu pipeline cresce.
Relacionado: Construindo CLIs e Serviços de Dados - layout de CLI de produção
Exemplos Intermediários
8. RecordBatch Apache Arrow entre processos
Compartilhe memória colunar sem serializar JSON linha por linha.
use arrow::array::{Int32Array, StringArray};
use arrow::record_batch::RecordBatch;
use std::sync::Arc;
fn sample_batch() -> RecordBatch {
let ids = Int32Array::from(vec![1, 2, 3]);
let names = StringArray::from(vec!["alpha", "beta", "gamma"]);
RecordBatch::try_from_iter(vec![
("id", Arc::new(ids) as _),
("name", Arc::new(names) as _),
])
.expect("valid batch")
}RecordBatché a unidade de intercâmbio para Arrow, Polars, DataFusion e Python.- Arrays de coluna são imutáveis e com contagem de referência - baratos para clonar identificadores.
- O schema é aplicado na criação do batch - comprimentos incompatíveis falham rapidamente.
Relacionado: Apache Arrow - semântica de cópia zero
9. Incorporar SQL com DataFusion
Consulte tabelas Arrow em memória sem um servidor de banco de dados separado.
use datafusion::prelude::*;
use datafusion::error::Result;
#[tokio::main]
async fn main() -> Result<()> {
let ctx = SessionContext::new();
ctx.register_csv("orders", "orders.csv", CsvReadOptions::default()).await?;
let df = ctx.sql("SELECT region, SUM(amount) AS total FROM orders GROUP BY region").await?;
df.show().await?;
Ok(())
}- DataFusion analisa SQL, otimiza planos lógicos e executa sobre Arrow.
- Registre tabelas de CSV, Parquet ou batches em memória.
- Use para análise incorporada, motores de consulta personalizados ou serviços SQL-sobre-arquivos.
Relacionado: DataFusion - UDFs e otimizadores personalizados
Versões da Stack: Esta página foi escrita para Rust 1.97.0 (edição 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4 e Polars 0.46+.