Skip to content

Parquet-Java Compatibility

The hardwood-parquet-java-compat module runs code written against Apache parquet-java's ParquetReader<Group> API on Hardwood's reader. It implements the same org.apache.parquet.* interfaces and includes Hadoop shims (Path, Configuration), so no Hadoop dependency is required.

Experimental

The hardwood-parquet-java-compat module is experimental; its API surface and behavior may change in future releases without prior deprecation. This module is not available from Maven Central; build it from source.

Mutually exclusive with parquet-java

This module provides its own type shims in the org.apache.parquet.* namespace. It cannot be used alongside parquet-java on the same classpath; pick one or the other.

Reading Local Files

import org.apache.hadoop.fs.Path;
import org.apache.parquet.example.data.Group;
import org.apache.parquet.hadoop.GroupReadSupport;
import org.apache.parquet.hadoop.ParquetReader;

Path path = new Path("data.parquet");

try (ParquetReader<Group> reader = ParquetReader.builder(new GroupReadSupport(), path).build()) {
    Group record;
    while ((record = reader.read()) != null) {
        long id = record.getLong("id", 0);
        String name = record.getString("name", 0);

        Group address = record.getGroup("address", 0);
        String city = address.getString("city", 0);
    }
}

Reading from S3

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.parquet.hadoop.util.HadoopInputFile;

Configuration conf = new Configuration();
conf.set("fs.s3a.access.key", "...");
conf.set("fs.s3a.secret.key", "...");
conf.set("fs.s3a.endpoint", "https://s3.us-east-1.amazonaws.com");

Path path = new Path("s3a://my-bucket/data.parquet");

try (ParquetReader<Group> reader = ParquetReader.builder(new GroupReadSupport(), path)
        .withConf(conf)
        .build()) {
    // read as usual
}

HadoopInputFile reads the same fs.s3a.* configuration properties as parquet-java. S3 support requires hardwood-s3 on the classpath. The compat layer loads it via reflection; if it is missing, the error message names the dependency to add.

Filter Pushdown

Filters use the standard FilterApi / FilterCompat classes:

import static org.apache.parquet.filter2.predicate.FilterApi.*;
import org.apache.parquet.filter2.compat.FilterCompat;

FilterPredicate pred = and(
    gtEq(longColumn("id"), 100L),
    lt(doubleColumn("amount"), 500.0)
);

try (ParquetReader<Group> reader = ParquetReader.builder(new GroupReadSupport(), path)
        .withFilter(FilterCompat.get(pred))
        .build()) {
    // only matching rows are returned
}

in and notIn take a Set of values:

FilterPredicate pred = in(binaryColumn("country"), Set.of(Binary.fromString("DE"), Binary.fromString("FR")));

parquet-java Compat Filters lists the supported predicates, how a Binary literal converts on each column type, and how nulls are handled.