Skip to content

Support exports to Parquet format - #1040

Draft
labianchin wants to merge 8 commits into
masterfrom
parquetQ
Draft

labianchin wants to merge 8 commits into
masterfrom
parquetQ

Conversation

@labianchin

@labianchin labianchin commented Apr 17, 2026 •

Copy link
Copy Markdown
Collaborator

Motivation

Fixes #143: export JDBC tables directly to Parquet, not only Avro.

Change

Adds a dbeam-parquet module that reuses dbeam-core for connections, query building, partitioning, parallel queries and metering.

This branch is stacked on #1046 (Beam 2.77.0 and JDBC driver bumps). Until #1046 merges, its two commits also show here. Review from 66c0f29 onwards.

Review guide

One commit per concern, best read in order:

  1. Drop Java 11 support, raise floor to JDK 17: CI matrix and compiler release.
  2. Parameterize shade plugin main class with dbeam.mainClass: each module sets its own shaded-jar main class. The dbeam-core jar is unchanged.
  3. Extract format-agnostic JdbcMetering and BenchJdbcJob: shared metering and benchmark code moves out of the Avro classes. JdbcAvroMetering becomes a subclass and keeps its metric namespace, so Dataflow counters keep their names. PsqlReplicationCheck.validateOptions becomes public. No behavior change for Avro.
  4. Add dbeam-parquet module: JdbcParquetJob, PsqlParquetJob, BenchJdbcParquetJob, schema conversion, write support, and tests. This is the bulk of the PR.
  5. Run Parquet exports in e2e tests and CI: Parquet e2e suite validated with parquet-tools, and Codecov for the new module.
    • PostgreSQL goes from 16 to 18. The data volume now mounts at /var/lib/postgresql, because 18+ images refuse the old /var/lib/postgresql/data mount.
    • parquet-cli runs with hadoop-mapreduce-client-core and the dbeam-parquet shaded jar on its classpath, since its runtime jar doesn't bundle Hadoop.
    • Codecov thresholds are relaxed: project may drop up to 3 points, patch up to 5 points below base.
  6. Document dbeam-parquet module: README, docs/parquet-type-conversion.md, CHANGELOG.

Parquet behavior:

  • The Parquet schema comes from JDBC metadata. --parquetSchemaFilePath overrides it.
  • SQL ARRAY columns become Parquet LIST columns with typed elements, and --arrayMode is honored. bytea[] elements are written as BINARY.
  • UUID is written as FIXED_LEN_BYTE_ARRAY(16). DATE and TIMESTAMP are written as TIMESTAMP(MILLIS).
  • The file footer stores the Avro schema under the parquet.avro.schema key. If dbeam-core can't build that Avro schema (for example, a typed_first_row ARRAY column that is NULL on the first row), the job logs a warning and leaves the key out. The export doesn't fail.
  • New options: --parquetCodec, --rowGroupSize (default 128MB) and --pageSize. Without --parquetCodec, --avroCodec maps to the closest Parquet codec.

Known limitation: --useTimestampMicros (#1042) does not apply to Parquet yet. Parquet timestamps are always MILLIS, so the footer Avro schema is generated with micros disabled to match. Supporting micros can be a follow-up.

Also a follow-up: --parquetSchemaFilePath isn't checked against the JDBC metadata. The writers still take column types from JDBC, so a schema file should only rename fields or change annotations.

Expected impact

  • Avro exports and the dbeam-core shaded jar behave as before.
  • Users get a new dbeam-parquet artifact, which is also listed in dbeam-bom.
  • Users on Java 11 must move to Java 17 or later.

Risk/rollback

  • Most of the code is in the new, separate module.
  • The shared-code risk is in commit 3 (metering and benchmark extraction), which existing Avro tests cover.
  • Adding hadoop-common brings in more transitive dependencies. woodstox and stax2 are pinned, and a few enforcer excludes were added, to satisfy requireUpperBoundDeps.
  • To roll back, revert the PR.

Validation

  • mvn verify passes on the full build, including the enforcer and dbeam-core and dbeam-parquet tests.
  • mvn verify -pl dbeam-core -am passes on commit 3 alone.
  • CI is green on JDK 17, 21 and 25. The JDK 21 job runs e2e (e2e/e2e.sh), which covers the Avro and Parquet suites and checks the parquet.avro.schema footer.
  • Codecov passes with the relaxed thresholds: project 89.09% against master's 91.87%, and patch 86.87%. Most of the remaining gap is in branches of the new module that are only partly covered.

Checklist for PR author(s)

  • Changes are covered by unit tests (no major decrease in code coverage %) and/or integration tests.
  • Ensure code formatting (use mvn com.coveo:fmt-maven-plugin:format org.codehaus.mojo:license-maven-plugin:update-file-header)
  • Document any relevant additions/changes in the appropriate spot in javadocs/docs/README.

@codecov

codecov Bot commented Apr 17, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 87.15847% with 94 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.33%. Comparing base (b05b278) to head (dff8833).

Additional details and impacted files
@@             Coverage Diff              @@
##             master    #1040      +/-   ##
============================================
- Coverage     91.87%   89.33%   -2.55%     
- Complexity      288      436     +148     
============================================
  Files            27       39      +12     
  Lines          1034     1669     +635     
  Branches         90      161      +71     
============================================
+ Hits            950     1491     +541     
- Misses           55      106      +51     
- Partials         29       72      +43     
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Keep Beam on a current, supported release for Dataflow.

Align transitive versions with Beam 2.77.0 to satisfy the
RequireUpperBoundDeps enforcer rule:
- libraries-bom 26.85.0 -> 26.87.0
- netty 4.1.132.Final -> 4.1.133.Final
- pin opentelemetry-gcp-resources 1.45.0-alpha (needed by
  google-cloud-storage, higher than libraries-bom)
Fix open Dependabot alerts on the JDBC drivers.

- postgresql 42.7.11 -> 42.7.14 (1 alert, fixed in 42.7.12)
- mariadb-java-client 3.5.8 -> 3.5.10 (4 alerts, fixed in 3.5.9)
dbeam-parquet pulls hadoop-common 3.5.0, which is compiled to class
file v61 (JDK 17). hadoop-common 3.4.x supports JDK 11 but its UGI
calls Subject.getSubject which is gone on JDK 25 (JEP 486), so we
can't have both Hadoop 3.5 (the JDK 25 fix) and JDK 11. JDK 11 has
been past Oracle's free premier support since Sept 2023.

- maven.compiler.release 11 -> 17
- enforcer requireJavaVersion [11,) -> [17,)
- CI matrix drops '11'
- release.yml builds on JDK 17 instead of 11
Let each module set its own shaded-jar main class.

The parent POM's pack profile now reads ${dbeam.mainClass}, and
dbeam-core sets it to com.spotify.dbeam.jobs.JdbcAvroJob, so the
shaded jar is unchanged. This lets new modules reuse the shade
config instead of duplicating it.
Prepare dbeam-core for reuse by output formats other than Avro.

- JdbcMetering holds the record/byte counters and timing metrics
  previously in JdbcAvroMetering; JdbcAvroMetering now extends it
  and keeps its metric namespace.
- BenchJdbcJob holds the benchmark loop and TSV metrics output
  previously in BenchJdbcAvroJob, which now delegates to it. Missing
  metric keys no longer throw an NPE.
- PsqlReplicationCheck.validateOptions is public so jobs in other
  modules can run the replication check.

No behavior change for Avro exports.
Export JDBC tables to Parquet, reusing dbeam-core for queries,
partitioning, metering, and the Avro schema derived from the
ResultSet (#143).

Jobs:
- JdbcParquetJob, PsqlParquetJob (with replication check), and
  BenchJdbcParquetJob.

Behavior:
- Parquet schema derived from JDBC metadata, or overridden with
  --parquetSchemaFilePath.
- SQL ARRAY columns map to Parquet LIST with typed elements;
  --arrayMode is honored.
- UUID is written as FIXED_LEN_BYTE_ARRAY(16); DATE and TIMESTAMP
  as TIMESTAMP(MILLIS).
- The Avro schema is stored in the footer as parquet.avro.schema
  when it can be generated; otherwise the key is omitted.
  It always uses timestamp-millis to match the Parquet columns, so
  --useTimestampMicros does not apply to Parquet exports yet.
- New options: --parquetCodec, --rowGroupSize (default 128MB),
  --pageSize. Without --parquetCodec, --avroCodec maps to the
  closest Parquet codec.
- Metrics report bytes actually written.

Build:
- Parent POM manages parquet-hadoop, hadoop-common, and pins
  woodstox/stax2 to satisfy requireUpperBoundDeps.
- dbeam-core publishes a test-jar for shared test helpers.
- dbeam-bom includes dbeam-parquet.
Cover the dbeam-parquet module end to end.

- e2e.sh runs BenchJdbcParquetJob against PostgreSQL in the default
  suite (runParquetSuite) and adds a lightParquet target.
- Each run validates output with parquet-tools and fails if the
  parquet.avro.schema footer metadata is missing.
- Bump the e2e PostgreSQL image from 16 to 18.
- CI installs parquet-cli and uploads dbeam-parquet coverage to
  Codecov.
- Mount the PostgreSQL 18 data volume at /var/lib/postgresql; 18+
  images refuse to start with the old /var/lib/postgresql/data mount.
- parquet-cli's runtime jar does not bundle Hadoop, so run it with
  hadoop-mapreduce-client-core and the dbeam-parquet shaded jar
  (which bundles hadoop-common) on the classpath.
- Relax Codecov thresholds (project 3, patch 5 points) while the new
  module's coverage catches up.
Describe Parquet exports for users.

- README: Parquet usage, options, and library dependency.
- docs/parquet-type-conversion.md: SQL to Parquet type mapping,
  including DECIMAL/NUMERIC and DATE handling.
- CHANGELOG: new module, options, and dbeam-core changes.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support for parquet format

1 participant