Skip to content

[lake/iceberg] Support composite bucket keys for Iceberg-tiered tables #4936

Description

@polyzos

Search before asking

  • I searched in the issues and found nothing similar.

Motivation

Fluss supports composite bucket keys ('bucket.key' = 'a,b'), and lookups depend on them: a prefix lookup must use exactly the bucket key, and delta joins look up the other side by it. Tables tiered to Iceberg are limited to a single bucket-key column, so users have to choose between composite bucket keys and Iceberg tiering.

In practice:

  • Multi-column join keys can only use one column for the lookup. For example, a delta join child ⋈ parent ON child.parent_id = parent.id AND child.tenant_id = parent.tenant_id can only bucket child by parent_id. The lookup returns every row for that one column, and the rest of the condition is applied afterwards.
  • Tenant-scoped keys don't fit. Where ids are only unique per tenant, the natural key is (tenant_id, id), and a single-column bucket key can't express it.
  • Cascades of joins have to key every level by one root column, instead of keeping each level's natural composite key.

The single-key assumption lives in several places:

  • the IcebergLakeCatalog table-creation check;
  • IcebergPartitionSpecUtils, which builds a single bucket(key, N) transform;
  • IcebergKeyEncoder / IcebergKeyDecoder, which require exactly one key field.

As explained in #4794, the restriction keeps each Fluss bucket aligned with exactly one Iceberg bucket. That alignment lets tiering be enabled later without redistributing data, and it makes bucket-level union reads and historical subscriptions efficient. Iceberg's bucket transform takes a single column, and several transforms (bucket(N, a), bucket(N, b)) produce a cross product rather than one of the N Fluss buckets.

Related work

Solution

Following the direction suggested in #4794: materialize the Fluss-computed composite bucket id in Iceberg and use it for bucket alignment and pruning, keeping today's layout for single-key tables.

Points to design:

  1. Bucketing for composite keys in the Iceberg format: encode multi-field keys so the client, the tablet servers and tiering all compute the same bucket.
  2. Iceberg layout for multi-key tables: for example the composite bucket id as an identity partition value, so Fluss bucket N maps to exactly one Iceberg partition. External engines keep correct results but lose key-based bucket pruning on these tables.
  3. Read path: the split planner must extract the bucket from that layout, so union reads and historical subscriptions keep bucket-level pruning.
  4. Compatibility: single-key tables unchanged; consistent with the FIP-27 clean table layout; enabling tiering on an existing multi-key table without redistributing data.

Anything else?

No response

Willingness to contribute

  • I'm willing to submit a PR!

Activity

  1. added theissue type on Oct 29, 2026
  2. polyzos commented on Oct 29, 2026

    @polyzos
    ContributorAuthor

    @yangshangqing95 FYI

    @luoyuxia @MehulBatra @fresh-borzoni Can you let me know your thoughts on this? If it makes sense, do you think we need a FIP for this?

  3. SteNicholas commented on Oct 30, 2026

    @SteNicholas
    Member

    Thanks @polyzos for putting this together. I agree that composite bucket keys are valuable for these use cases, and the single-key restriction should not be a long-term limitation.

    I think this deserves a FIP, since it introduces a new Iceberg physical layout and needs a stable encoding and bucket-routing contract across Fluss components. Materializing the Fluss bucket ID looks like a promising direction. A few points would be useful to clarify in the proposal:

    1. Encoding and routing: Define an unambiguous composite-key encoding, including its interaction with primary-key encoding and prefix lookups. Bucket assignments must remain consistent before and after enabling tiering, while preserving existing single-key behavior.
    2. Schema and FIP-27: An identity partition on a helper bucket-ID column requires that column in the Iceberg schema. We should explain how users explicitly opt into it, how it appears to external engines, and how readers and writers distinguish this layout from existing clean and legacy layouts.
    3. Reads and interoperability: Cover bucket extraction and pruning for union reads and historical bootstrap. External Iceberg readers must return correct results even when they cannot derive bucket pruning from predicates on the original key columns.
    4. Compatibility: Clarify which existing tables can enable tiering without redistribution, and the upgrade requirements for clients, servers, tiering services, and lake readers. We should distinguish enabling tiering on a table already using the intended encoding from migrating a table using another encoding.

    A focused FIP covering these contracts and tradeoffs would be a good next step for discussion on the dev mailing list. Meanwhile, the validation in #4795 remains useful until end-to-end support is available.

  4. self-assigned this
    on Oct 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions