Add batch/columnar write API for Arrow VectorSchemaRoot (Java parity with C++/Python)
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 5/5
- Tempo stimato
- Più di una settimana
- Idoneità per principianti
- 30/100
- Tipo di issue
- Funzionalità
- Chiarezza
- Abbastanza chiara
- Stato di attività
- Attiva
- Stack tecnologico
- java
- Ambito
- data-engineering
Direzione di ricerca
Inizia leggendo il modulo parquet-arrow e le API indicate PageWriteStore, PageWriter, BytesInput e ColumnChunkPageWriteStore. Il lavoro proposto comprende cinque fasi di implementazione, iniziando dalle scritture zero-copy per colonne PLAIN a larghezza fissa non nullable; il completamento dovrebbe essere valutato in base alla fase scelta, mentre l'ambito completo include il supporto per colonne nullable, a larghezza variabile e per i dizionari.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Problem
parquet-java has no public API to write Arrow VectorSchemaRoot to Parquet files. Callers must construct row objects and feed them through ParquetWriter<T>.write(T) one at a time. Arrow C++ and PyArrow support this natively via parquet::WriteTable() / pq.write_table().
Related prior discussion:
- #2264 (open since 2019)
- #3353
Motivation
Several downstream Java projects work with Arrow-columnar data internally and must materialize row objects solely to satisfy ParquetWriter's input API:
- Apache Iceberg (
FileAppender<Record>) — iceberg#17748 - Apache Fluss (Arrow-native streaming storage) — fluss#4047
- Apache Paimon (worked around this by building their own
paimon-arrowwriter that bypassesparquet-java's row API entirely)
Key Insight
For PLAIN-encoded, fixed-width columns, Arrow's in-memory format (contiguous little-endian values) is identical to Parquet's PLAIN page encoding. A zero-copy path is possible by wrapping the Arrow data buffer directly as a BytesInput and passing it to PageWriter.writePage().
For nullable columns, Arrow's validity bitmap can be scanned for contiguous non-null runs, with each run bulk-copied and definition levels encoded as RLE runs of the same value — O(null_transitions) instead of O(N).
Proposed Design
A new ArrowParquetWriter in the parquet-arrow module that writes pages directly to PageWriter rather than going through RecordConsumer/ColumnWriter:
ArrowParquetWriter.writeBatch(VectorSchemaRoot)
→ per column: selects optimal write strategy
→ writes pages to PageWriter via getPageWriter(ColumnDescriptor)
→ manages row groups via ParquetFileWriter
Per-column strategy selection (best to worst):
- Zero-copy (non-null + fixed-width + PLAIN): wrap Arrow buffer as
BytesInputdirectly. RL/DL as single-value RLE runs. Stats from sequential buffer scan. - Bulk-copy with nulls (nullable + fixed-width + PLAIN): scan validity bitmap for non-null runs, bulk-copy each, emit DL as RLE runs per null-transition.
- Variable-width rewrite (PLAIN + string/binary): single-pass transformation of Arrow offset+data buffers to Parquet's length-prefixed format.
- Dictionary: map Arrow's
DictionaryEncodedVectorto Parquet dictionary pages, or build dictionary from plain vector. - Fallback: per-value through
ValuesWriter(same cost as today, for unsupported encoding/type combos).
All verified public APIs exist for this:
PageWriteStore.getPageWriter(ColumnDescriptor)— get column page writer directlyPageWriter.writePage(BytesInput, valueCount, rowCount, stats, encodings)— write pre-encoded pagesBytesInput.from(ByteBuffer)— zero-copy buffer wrappingRunLengthBitPackingHybridEncoder— encode RL/DL levelsColumnChunkPageWriteStore.flushToFileWriter()— flush pages to file
Why Not Extend ParquetWriter?
ParquetWriter.write(T) calls InternalParquetRecordWriter.write() which increments recordCount by 1 per call and checks row-group boundaries based on that count. This is incompatible with batch semantics. The writer must manage ParquetFileWriter and row groups directly.
Scope
- Parquet file format unchanged
- Existing
ParquetWriter<T>API unchanged parquet-arrowgainsparquet-hadoopas a compile dependency (forParquetFileWriter,ColumnChunkPageWriteStore)- No Hadoop runtime dependency for uncompressed output (compression requires caller-supplied
CompressionCodecFactory) - Flat schemas (primitive columns) first; nested types deferred
Implementation Phases
- Core infrastructure + zero-copy for non-null fixed-width PLAIN columns
- Nullable column support (validity bitmap scanning + run-based bulk copy)
- Variable-width types (string/binary offset rewriting)
- Dictionary encoding support
- Bloom filter, nested types, advanced features
- Lingua principale
- Java
- Stelle
- 3.1k
- Fork
- 1.6k
- Merge medio
- 4g 12h
- PR unite (30g)
- 28
Guida per i contributori
Nessuna guida per i contributori indicizzata per questo repository
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di apache/parquet-java
-
Type: bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
apache/parquet-java#3792 ·
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
apache/parquet-java#3767 ·
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
apache/parquet-java#3695 · 1 commento ·
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
apache/parquet-java#3667 ·
-
Type: bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
apache/parquet-java#3587 ·
Tutte le issue di apache/parquet-java
Issue simili
-
certification
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 80/100
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 75/100
-
[BUG] ECR GetAuthorizationToken returns a proxyEndpoint for the default region, not the request's Apertabug ecr
Difficoltà 2/5 1-3 ore Idoneità per principianti 75/100
-
Needs: Triage Type: Feature request
Difficoltà 2/5 1-3 ore Idoneità per principianti 70/100
AntennaPod/AntennaPod#8794 ·
-
agentic-workflows
Difficoltà 2/5 1-3 ore Idoneità per principianti 65/100
github/copilot-sdk#2760 ·