faucet-source-parquet
Apache Parquet file source for the faucet-stream ecosystem. Reads one or more Parquet files from a local path, a local glob pattern, or Amazon S3 (single object or prefix) and yields each row as a serde_json::Value object.
Built on the parquet + arrow crates wired through object_store, so local and S3 share one vectorized, streaming code path — RecordBatches are decoded and converted to JSON incrementally and the source never buffers a whole file in memory. Reach for it to load columnar data lakes, S3 exports, or partitioned year=/month=/ trees into any faucet-stream sink.
Feature highlights
- Three location modes — single local file, local glob (sorted for determinism), or S3 (single key or prefix listing).
- Column projection —
columns: [a, b]prunes at the Parquet level viaProjectionMask, so unread columns are skipped at the I/O layer, not just in JSON. - Parallel multi-file reads — Glob / S3-prefix modes read up to
concurrencyfiles at once viabuffer_unordered. - Vectorized streaming — one Arrow
RecordBatchper row-group; memory is bounded bybatch_size, not file size. - Fail-fast schema validation — multi-file scans validate every file's Arrow schema up front (cheap footer probe) and surface a mismatch naming both files and the first diverging field, before any rows are committed downstream.
- S3-compatible — custom
endpoint_urlfor MinIO / LocalStack; credentials from the standard AWS chain.
Installation
# As a library:
# In the CLI (opt-in connector feature):
Quick start
# pipeline.yaml — faucet run pipeline.yaml
version: 1
pipeline:
source:
type: parquet
config:
source:
type: local_path
path: /data/events.parquet
sink:
type: jsonl
config:
path: ./events.jsonl
Configuration reference
| Field | Type | Default | Description |
|---|---|---|---|
source |
ParquetLocation |
— (required) | Where to read from — local_path, glob, or s3 (see below). |
batch_size |
int | 1000 |
Per-page row-count hint forwarded to ParquetRecordBatchStreamBuilder::with_batch_size. Arrow treats it as a max — a page may hold fewer rows at a row-group boundary. 0 = no batching: the file's native row-group size drives the page cadence (one page per row-group). |
columns |
array | (all) | Top-level columns to decode. Unknown names error out. Prunes I/O at the Parquet layer. |
concurrency |
int | 4 |
Files read in parallel for Glob / S3-prefix modes. Ignored for single-file modes. Must be > 0. |
source location (ParquetLocation)
# Single local file
source:
# Local glob — all matched files must share one Arrow schema
source:
# S3 — set EXACTLY ONE of key / prefix
source:
type: s3
bucket: my-bucket
prefix: "events/2024/" # or: key: events/2024/data.parquet
region: us-east-1 # optional; defaults to the AWS resolution chain
endpoint_url: http://localhost:9000 # optional; MinIO / LocalStack
ParquetS3Config field |
Type | Description |
|---|---|---|
bucket |
string | S3 bucket (required). |
key |
string | Single object key. Mutually exclusive with prefix. |
prefix |
string | Object-key prefix to list and read. Mutually exclusive with key. |
region |
string | AWS region. Defaults to the standard resolution chain. |
endpoint_url |
string | Custom endpoint for S3-compatible services. HTTP endpoints automatically allow plain HTTP. |
S3 credentials come from the standard object_store AWS chain (AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY, IMDS, profile, …).
Examples
Projected columns from a partitioned tree, 8 files in parallel
source:
type: parquet
config:
source:
columns:
concurrency: 8
batch_size: 4096
S3 prefix, one page per row-group (load-job friendly)
source:
type: parquet
config:
source:
batch_size: 0 # emit one page per native row-group
JSON representation
Each row becomes a serde_json::Value::Object. Field encoding is delegated to arrow_json::ArrayWriter, following Arrow's standard rules:
| Arrow type | JSON shape |
|---|---|
Int32/Int64/Float32/Float64 |
number |
Utf8/LargeUtf8 |
string |
Boolean |
true/false |
Date32/Date64 |
ISO-8601 date string |
Time32/Time64 |
ISO-8601 time string |
Timestamp(unit, tz) |
ISO-8601 timestamp string |
Decimal128/Decimal256 |
string (precision/scale preserved) |
Binary/LargeBinary/FixedSizeBinary |
base64 string |
Struct(...) |
nested object |
List/LargeList/FixedSizeList |
array |
Map(K, V) |
object keyed by K |
| Null values | field omitted |
Streaming & batching
ParquetSource implements Source::stream_pages, writing each Arrow RecordBatch to the sink as it's decoded — memory is bounded by batch_size × row_width, not file size. batch_size is a hint (Arrow may emit smaller batches at row-group boundaries); batch_size: 0 skips the override so the reader emits one batch per row-group. Multi-file scans flatten in sorted-path order, and all files' schemas are validated up front so a later mismatch fails before earlier rows are committed. Every page carries bookmark: None — there is no incremental-replication mode for Parquet.
Config loading & schema
Library usage
use ;
# async
How it works
Each row group is read as an Arrow RecordBatch and converted to JSON on the fly. The S3 client is built once in new() and reused across every per-file read. Glob / S3-prefix mode reads up to concurrency files in parallel via futures::buffer_unordered. Column projection is applied with ProjectionMask::columns so unread columns are skipped at the Parquet I/O layer. A 100k-row, all-primitive file reads in well under 500 ms on a recent laptop in release mode; throughput depends on row width, projection, and storage medium — benchmark with your own data.
Lineage dataset URI
file://<path> (local/glob), s3://<bucket>/<key> or s3://<bucket>/<prefix> — e.g. file:///tmp/data.parquet or s3://my-bucket/events/2024/.
Feature flags
No optional features of its own; enable it in the CLI/umbrella via the source-parquet feature.
Troubleshooting / FAQ
| Symptom | Likely cause & fix |
|---|---|
FaucetError::Config: concurrency |
concurrency is 0. Set it to ≥ 1. |
FaucetError::Config on S3 |
Both key and prefix set, or neither, or an empty bucket. Set exactly one of key/prefix. |
Local read fails with FaucetError::Source |
File missing/unreadable, or not valid Parquet. Check the path and permissions. |
Source error naming a column |
A name in columns doesn't exist in the file schema. Match the Parquet column names exactly. |
Source error naming two files + a field |
Globbed/prefixed files have divergent Arrow schemas. Ensure all files share one schema, or narrow the glob. |
S3 403/credential errors |
Credentials missing from the AWS chain, or wrong region. Set region and the AWS env vars/profile. |
| Connecting to MinIO/LocalStack fails | Set endpoint_url to the service URL (plain HTTP is auto-allowed for HTTP endpoints). |
A Decimal/Timestamp arrives as a string |
Intentional — Arrow encodes these as strings to preserve precision. Cast downstream if you need a number. |
See also
Sharded execution (cluster Mode B)
Under faucet serve --cluster,
a top-level shard: { count: N } block splits this source across cluster
workers automatically — no connector config needed. Each worker reads the
files whose path hashes to its shard index (stable FNV-1a modulo count),
so the partition is disjoint and complete: every file is read by exactly one
worker, and the partition stays stable as new files appear. Outside the
cluster coordinator a run reads every file, unchanged.
Cross-file schema validation still covers the full resolved file set on every worker, so a schema mismatch fails the run even when the mismatching files hash into different shards.
License
Licensed under either of Apache License, Version 2.0 or MIT license at your option.