Apache Arrow
Apache Arrow integration in DataVec — ArrowRecordReader and zero-copy data exchange
Apache Arrow is an in-memory columnar data format designed for high-performance analytics. It defines a standard binary layout for batches of typed columnar data that enables zero-copy reads between systems — no serialization or deserialization overhead when passing data between a DataVec pipeline and an Arrow-aware consumer.
DataVec's Arrow integration lets you use Arrow-formatted data as input to record readers and as an exchange format for large batch operations.
What Arrow Provides
Traditional row-oriented formats (like Java ArrayList<Map<String,Object>>) scatter each record's fields across memory. Arrow lays out each column's values contiguously in memory:
Row-oriented: [row0_col0, row0_col1, row0_col2], [row1_col0, row1_col1, row1_col2], ...
Column-oriented: [row0_col0, row1_col0, row2_col0, ...], [row0_col1, row1_col1, row2_col1, ...]Columnar layout enables:
Vectorized computation: apply an operation to an entire column using SIMD CPU instructions
Better compression: repeated values and similar values are adjacent, compressing well
Zero-copy sharing: share data between JVM and native code (Python, C++) without copying
Selective column reads: read only the columns you need without deserializing the rest
Arrow is used by Apache Spark (Spark's vectorized execution engine uses Arrow internally), Pandas (via PyArrow), Apache Parquet (Arrow as the in-memory representation after Parquet deserialization), and many other data tools.
ArrowRecordReader
ArrowRecordReader reads Arrow-formatted data and produces List<Writable> records compatible with the rest of the DataVec pipeline.
import org.datavec.arrow.recordreader.ArrowRecordReader;
ArrowRecordReader reader = new ArrowRecordReader();
reader.initialize(new FileSplit(new File("/data/batch.arrow")));
while (reader.hasNext()) {
List<Writable> record = reader.next();
// use the record
}Arrow files can be created by Python (via PyArrow), Spark (via df.write.format("arrow")), or any Arrow IPC writer. The Arrow IPC file format (sometimes called "Feather v2") is the standard format for on-disk Arrow data.
ArrowWritableRecordBatch
ArrowWritableRecordBatch is a List<List<Writable>> backed directly by Arrow columnar memory. It provides zero-copy access to Arrow batches — individual Writable values are read directly from the Arrow buffer without copying into Java heap objects.
This is particularly useful when processing large batches where copying each value would be expensive. The batch holds a reference to the underlying Arrow buffers; individual Writable objects returned from batch.get(i).get(j) read directly from those buffers.
Converting Between Arrow and DataVec
From Arrow VectorSchemaRoot to List<List>
From List<List> to Arrow
This conversion enables sending DataVec-processed data to Arrow-compatible consumers (Python via IPC, Spark, etc.) without an intermediate CSV or JSON step.
Use Cases
High-Performance Batch Loading
When loading large pre-processed datasets for repeated training epochs, Arrow's columnar format allows reading an entire column in a single contiguous memory region, which is much faster than reading individual records from CSV.
Python-Java Interoperability
If your data preparation runs in Python (feature engineering in Pandas, image preprocessing, NLP tokenization), you can write Arrow format from Python and read it in DataVec without going through CSV:
Python side:
Java side:
Spark to DataVec
Spark's Arrow-based Pandas UDFs and the spark.createDataFrame path can produce Arrow IPC files. These can be read directly by ArrowRecordReader for local fine-tuning or evaluation after Spark-based feature engineering.
Type Mapping
Arrow types map to DataVec Writable types as follows:
Int8, Int16, Int32
IntWritable
Int64
LongWritable
Float32
FloatWritable
Float64
DoubleWritable
Utf8 (string)
Text
Bool
BooleanWritable
FixedSizeBinary, Binary
BytesWritable
FixedSizeList / Tensor
NDArrayWritable
Null
NullWritable
Memory Management
Arrow allocates memory outside the JVM heap using BufferAllocator. Always close Arrow resources when done to avoid native memory leaks:
ArrowRecordReader manages its own allocator internally and releases memory when close() is called. Always call reader.close() (or use try-with-resources) when done reading.
Last updated
Was this helpful?