Skip to content

[FLINK-40426][python] Add Parquet and JSON filesystem I/O to DataFrame API - #29245

Open
csurong wants to merge 2 commits into
apache:masterfrom
csurong:FLINK-40426-dataframe-filesystem-io
Open

csurong wants to merge 2 commits into
apache:masterfrom
csurong:FLINK-40426-dataframe-filesystem-io

Conversation

@csurong

@csurong csurong commented Sep 20, 2026

Copy link
Copy Markdown

What is the purpose of the change

Add Parquet and JSON filesystem I/O to the PyFlink DataFrame API, as described in FLINK-40426 and FLIP-591.

Brief change log

  • Add read_parquet, read_json, write_parquet, and write_json, using the existing filesystem connector.
  • Support format options and append/overwrite writes while preserving write_generic behavior.
  • Add tests and API documentation with a usage example.

Verifying this change

  • Flink CI (Java 17) passed, including basic QA, compilation, packaging/licensing, tests, and end-to-end tests.
  • All 21 tests in test_filesystem_io.py and test_io.py passed, including real JSON/Parquet reads and writes, write modes, format options, and argument validation.
  • Flake8, targeted mypy checks, strict Sphinx build, and a clean build of flink-python with its dependencies passed (Java tests skipped in that build).
  • Full clean verify was attempted, but four OpenTelemetry tests failed because no Docker environment was available locally.

Does this pull request potentially affect one of the following parts:

  • Dependencies: no
  • Public API: yes, the Python helpers specified in FLIP-591
  • Serializers: no
  • Runtime per-record code paths: no
  • Deployment or recovery: no
  • S3 file system connector: no

Documentation

  • New feature: yes
  • Documented in the Python API docstrings and DataFrame I/O reference.

Was generative AI tooling used to co-author this PR?
  • Yes (please specify the tool below)

Generated-by: OpenAI Codex (GPT-6)

@flinkbot

flinkbot commented Sep 20, 2026

Copy link
Copy Markdown
Collaborator

CI report:

Bot commands The @flinkbot bot supports the following commands:
  • @flinkbot run azure re-run the last Azure build

rolling_policy_file_size: str = "128mb",
rolling_policy_rollover_interval: str = "30min",
rolling_policy_check_interval: Optional[str] = None,
partition_commit_trigger: str = "process-time",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partition commit only works for partitioned sinks, but the writer APIs do not expose partition columns and the descriptor never calls partitioned_by(...). Please add complete partition_by support.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for catching this. Added partition_by to both readers and writers in b104961, with the partition keys passed to TableDescriptor.partitioned_by(...). I also added partitioned round-trip/overwrite tests and streaming partition-commit tests, including a non-UTC case.

# ======================== I/O ========================

@PublicEvolving()
def write_parquet(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are many options defined in the filesystem connector, I think we are not limited to the parameters defined in the FLIP-591.

Do you think it makes sense to make the following changes:

  • Evaluate the options defined in the filesystem connector and parquet / json format and make sure frequently used options are defined here.
  • Introduce parameters connector_options and format_options for the options which are not defined here. It could also avoid functionality break if users introduce new features in the filesystem connector or parquet/json format and forget to update this API.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. I went through the connector and format options and added parameters for sink parallelism, inactivity rolling, JSON parsing/timestamps, and Parquet UTC conversion. All four helpers now also accept connector_options and format_options for options without a dedicated parameter.

path: str,
*,
mode: str = "overwrite",
compression: str = "SNAPPY",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JSON provides a generic format_options escape hatch. Could we provide equivalent format_options for Parquet and consider a generic sink_options escape hatch for advanced upstream options? This avoids adding a new public argument for every supported connector option.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parquet now accepts format_options too. I used connector_options for advanced sink options to keep the naming consistent across readers and writers. Defaults are applied after user options, so format_options={"compression": "GZIP"} is preserved rather than overwritten by the SNAPPY default.

Comment thread flink-python/pyflink/dataframe/io.py Outdated

:param path: File or directory URI supported by Flink's filesystem implementations.
:param schema: Mapping of column names to DataFrame data types.
:param monitor_interval: Optional file discovery interval, for example ``"60s"``.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we document the exact semantics here? Setting monitor_interval changes the source from a bounded scan to continuous file discovery, while path_regex_pattern performs a regex full match against the file path. This distinction is important for users configuring streaming reads.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated both reader docstrings and the I/O docs to spell this out: monitor_interval enables unbounded file discovery, while the regex matches the entire path, excluding the scheme and authority. The docs also explain that files aren't tailed and new partition directories aren't discovered. Added tests for full-path matching and rejection of unbounded reads in batch mode.

Add partition columns and connector/format options to JSON and Parquet
readers and writers. Merge explicit settings before applying defaults and
support computed columns and watermarks on both readers.

Cover partitioned writes, continuous discovery and non-UTC partition
commits, and document the filesystem and format semantics.

Generated-by: OpenAI Codex (GPT-6)
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.

3 participants