huyuanfeng2018 opened a new issue, #10708:
URL: https://github.com/apache/paimon/issues/10708

   ### Search before asking
   
   - [x] I searched in the [issues](https://github.com/apache/paimon/issues) 
and found nothing similar.
   
   
   ### Motivation
   
   <html><head></head><body><h2><span>Title</span></h2><p><span>[Feature] 
Support cumulative hourly deltas over daily snapshot baselines in Chain 
Tables</span></p><h2><span>Motivation</span></h2><p><span>In our batch data 
warehouse pipelines, we maintain daily full-state tables 
(</span><code><span>_d</span></code><span>) and hourly full-state tables 
(</span><code><span>_h</span></code><span>).</span></p><p><span>Each hourly job 
currently:</span></p><ol start="1"><li><p><span>Reads the previous day's full 
dataset.</span></p></li><li><p><span>Reads the cumulative changes from the 
start of the current day through the end of the target 
hour.</span></p></li><li><p><span>Performs a full outer join and resolves 
updates by business key.</span></p></li><li><p><span>Writes the resulting full 
dataset into the target hourly partition.</span></p></li></ol><p><span>For 
example, a job running after </span><code><span>2026-10-20 
02:00</span></code><span> processes changes in </span><code><span>[2026
 -10-20 00:00, 2026-10-20 02:00)</span></code><span> and produces hourly 
partition 
</span><code><span>2026102001</span></code><span>.</span></p><p><span>Most rows 
remain unchanged between hourly results, so this pattern repeatedly reads, 
merges, and stores a large amount of unchanged data.</span></p><p><span>Chain 
Tables already support hourly partitioning and reconstruction from a snapshot 
and subsequent delta partitions. We would like to extend this model to support 
</span><strong><span>daily snapshot baselines and independently reconstructable 
hourly cumulative deltas</span></strong><span>, matching the output of our 
existing batch pipelines.</span></p><p><span>The desired reconstruction 
is:</span></p><pre><code><span>FullState(target_hour)
       = Merge(previous_day_snapshot, 
cumulative_delta(target_hour))</span></code></pre><p><span>Earlier hourly delta 
partitions would not be inputs to this 
reconstruction.</span></p><h2><span>Solution</span></h2><h3><span>1. Daily 
snapshots and hourly cumulative deltas</span></h3><p><span>Use the snapshot 
branch for daily full-state partitions and the delta branch for hourly 
cumulative change sets.</span></p><p><span>The partition naming conventions 
would be:</span></p><ul><li><p><strong><span>Daily 
snapshot:</span></strong><span> </span><code><span>yyyyMMdd</span></code><span> 
identifies the day whose end-of-day full state is 
stored.</span></p></li><li><p><strong><span>Hourly delta:</span></strong><span> 
</span><code><span>yyyyMMddHH</span></code><span> identifies the hour by its 
start time. Its contents include the cumulative changes from the start of that 
day through the end of that hour.</span></p></li></ul><p><span>For 
example:</span></p>
   Branch | Partition | Contents
   -- | -- | --
   snapshot | 20261019 | Full state at the end of October 19, serving as the 
baseline at October 20, 00:00
   delta | 2026102000 | Cumulative changes during October 20, [00:00, 01:00)
   delta | 2026102001 | Cumulative changes during October 20, [00:00, 02:00)
   delta | 2026102006 | Cumulative changes during October 20, [00:00, 07:00)
   delta | 2026102023 | Cumulative changes during October 20, [00:00, October 
21 00:00)
   snapshot | 20261020 | Full state at the end of October 20, serving as the 
next day's baseline
   
   <p><span>All boundaries would use the same configured business time 
zone.</span></p><p><span>Querying logical hourly partition 
</span><code><span>2026102006</span></code><span> should therefore 
reconstruct:</span></p><pre><code><span>FullState(2026102006)
       = Merge(
           Snapshot(20261019),
           CumulativeDelta(2026102006)
         )</span></code></pre><p><span>The query should read the daily baseline 
and the target delta partition, without reading hourly delta partitions 
</span><code><span>2026102000</span></code><span> through 
</span><code><span>2026102005</span></code><span>.</span></p><h3><span>2. 
Cumulative delta contract</span></h3><p><span>Each hourly cumulative delta 
contains the final complete row image for every business key affected since the 
start of the day.</span></p><p><span>For example, if a key changes during 
</span><code><span>00:00–01:00</span></code><span> and does not change again, 
its updated row must still appear in 
</span><code><span>CumulativeDelta(2026102006)</span></code><span>.</span></p><p><span>Rows
 unchanged since the daily baseline do not need to be 
repeated.</span></p><p><span>This gives the following 
semantics:</span></p><ul><li><p><span>A key present in the cumulative delta 
contributes its final state according to the configured key and sequence 
semantics.</span></p
 ></li><li><p><span>A key absent from the cumulative delta retains its baseline 
 >state.</span></p></li><li><p><span>If deletion support is included, it 
 >requires explicit deletion semantics; absence from the cumulative delta must 
 >not implicitly mean deletion.</span></p></li></ul><p><span>An initial scope 
 >could focus on </span><strong><span>batch reads with deduplicate semantics 
 >and complete row images</span></strong><span>.</span></p><h3><span>3. 
 >Explicit mapping between hourly targets and daily 
 >baselines</span></h3><p><span>For the example above, the mapping 
 >is:</span></p><pre><code><span>target delta partition = 2026102006
   baseline partition     = 20261019</span></code></pre><p><span>This mapping 
should follow the declared baseline relationship, rather than selecting a 
snapshot through raw partition-value comparison.</span></p><p><span>In 
particular, </span><code><span>snapshot/20261020</span></code><span> represents 
the state at October 21, 00:00. Even after it becomes available, it must not be 
used to reconstruct an earlier hourly result such as 
</span><code><span>2026102006</span></code><span>.</span></p><p><span>A 
possible implementation could retain the same partition schema on both 
branches, such as a single </span><code><span>pt STRING</span></code><span> 
partition column, while interpreting snapshot values as daily partitions and 
delta values as hourly partitions. The initial implementation would not need 
different partition-column layouts between branches.</span></p><h3><span>4. 
Proposed integration with Chain Tables</span></h3><p><span>This could be 
introduced as an opt-in cumulative-delta
  mode, preserving the existing behavior by default.</span></p><p><span>The 
read planner would:</span></p><ol start="1"><li><p><span>Resolve the requested 
logical hourly partition.</span></p></li><li><p><span>Locate its declared daily 
baseline.</span></p></li><li><p><span>Select only the corresponding cumulative 
delta partition.</span></p></li><li><p><span>Reuse the existing Chain Table 
merge reader to produce the full result under the requested logical hourly 
partition.</span></p></li></ol><p><span>The current 
</span><code><span>ChainGroupReadTable.ChainTableBatchScan</span></code><span> 
seems a relevant place to investigate the planning changes. Baseline 
resolution, partition-time interpretation, compaction, and expiration would 
also need to follow the new semantics.</span></p><h3><span>5. Correctness and 
lifecycle considerations</span></h3><p><span>The following behaviors would need 
to be defined:</span></p><ul><li><p><strong><span>Empty 
results:</span></strong><span> distinguish 
 a successfully published empty cumulative delta from a partition that has not 
been produced successfully.</span></p></li><li><p><strong><span>Baseline 
availability:</span></strong><span> a missing required baseline must not 
silently fall back to an unrelated daily 
snapshot.</span></p></li><li><p><strong><span>Reruns:</span></strong><span> 
define how an hourly overwrite or a daily baseline correction affects published 
results and any materialized full-state 
partitions.</span></p></li><li><p><strong><span>Retention:</span></strong><span>
 retain a daily baseline while any retained hourly version depends on it. 
Earlier hourly deltas should be independently removable without changing later 
hourly 
results.</span></p></li><li><p><strong><span>Compaction:</span></strong><span> 
preserve the distinction between daily baselines and any optional materialized 
hourly results.</span></p></li><li><p><strong><span>Read-path 
compatibility:</span></strong><span> define the behavior of streaming and lo
 okup reads before enabling them for cumulative 
deltas.</span></p></li></ul><h2><span>Anything else?</span></h2><p><span>The 
expected benefits are to reduce repeated full-data writes and avoid scanning 
redundant earlier cumulative delta partitions when reconstructing a target 
hour.</span></p><p><span>There are also trade-offs: cumulative deltas repeat 
some changed rows across hours, and reconstructing a full hourly result still 
requires reading the relevant baseline data. The storage and read-cost benefits 
should be evaluated against both hourly full copies and ordinary interval-delta 
Chain Tables.</span></p><p><span>I would appreciate community feedback 
on:</span></p><ol start="1"><li><p><span>Whether this use case fits an 
extension of the existing Chain Table 
model.</span></p></li><li><p><span>Whether baseline selection should use an 
explicit baseline reference, a configurable period-based rule, or another 
existing mechanism.</span></p></li><li><p><span>What would be an appropriate
  initial scope for supporting daily snapshots with hourly cumulative 
deltas.</span></p></li></ol><p><span>Related 
references:</span></p><ul><li><p><a 
href="https://cwiki.apache.org/confluence/display/PAIMON/PIP-37%3A+Introduce+Chain+Table";><span>PIP-37:
 Introduce Chain Table</span></a></p></li><li><p><a 
href="https://paimon.apache.org/docs/master/primary-key-table/chain-table/";><span>Chain
 Table documentation</span></a></p></li><li><p><a 
href="https://github.com/apache/paimon/blob/8c09824c060520f3f1f4a03ce2369de371e5c7c6/paimon-core/src/main/java/org/apache/paimon/table/ChainGroupReadTable.java#L363-L499";><span>ChainGroupReadTable
 planning implementation</span></a></p></li></ul></body></html>## Title
   
   [Feature] Support cumulative hourly deltas over daily snapshot baselines in 
Chain Tables
   
   ## Motivation
   
   In our batch data warehouse pipelines, we maintain daily full-state tables 
(`_d`) and hourly full-state tables (`_h`).
   
   Each hourly job currently:
   
   1. Reads the previous day's full dataset.
   2. Reads the cumulative changes from the start of the current day through 
the end of the target hour.
   3. Performs a full outer join and resolves updates by business key.
   4. Writes the resulting full dataset into the target hourly partition.
   
   For example, a job running after `2026-10-20 02:00` processes changes in 
`[2026-10-20 00:00, 2026-10-20 02:00)` and produces hourly partition 
`2026102001`.
   
   Most rows remain unchanged between hourly results, so this pattern 
repeatedly reads, merges, and stores a large amount of unchanged data.
   
   Chain Tables already support hourly partitioning and reconstruction from a 
snapshot and subsequent delta partitions. We would like to extend this model to 
support **daily snapshot baselines and independently reconstructable hourly 
cumulative deltas**, matching the output of our existing batch pipelines.
   
   The desired reconstruction is:
   
   ```text
   FullState(target_hour)
       = Merge(previous_day_snapshot, cumulative_delta(target_hour))
   ```
   
   Earlier hourly delta partitions would not be inputs to this reconstruction.
   
   ## Solution
   
   ### 1. Daily snapshots and hourly cumulative deltas
   
   Use the snapshot branch for daily full-state partitions and the delta branch 
for hourly cumulative change sets.
   
   The partition naming conventions would be:
   
   - **Daily snapshot:** `yyyyMMdd` identifies the day whose end-of-day full 
state is stored.
   - **Hourly delta:** `yyyyMMddHH` identifies the hour by its start time. Its 
contents include the cumulative changes from the start of that day through the 
end of that hour.
   
   For example:
   
   | Branch | Partition | Contents |
   | --- | --- | --- |
   | `snapshot` | `20261019` | Full state at the end of October 19, serving as 
the baseline at October 20, 00:00 |
   | `delta` | `2026102000` | Cumulative changes during October 20, `[00:00, 
01:00)` |
   | `delta` | `2026102001` | Cumulative changes during October 20, `[00:00, 
02:00)` |
   | `delta` | `2026102006` | Cumulative changes during October 20, `[00:00, 
07:00)` |
   | `delta` | `2026102023` | Cumulative changes during October 20, `[00:00, 
October 21 00:00)` |
   | `snapshot` | `20261020` | Full state at the end of October 20, serving as 
the next day's baseline |
   
   All boundaries would use the same configured business time zone.
   
   Querying logical hourly partition `2026102006` should therefore reconstruct:
   
   ```text
   FullState(2026102006)
       = Merge(
           Snapshot(20261019),
           CumulativeDelta(2026102006)
         )
   ```
   
   The query should read the daily baseline and the target delta partition, 
without reading hourly delta partitions `2026102000` through `2026102005`.
   
   ### 2. Cumulative delta contract
   
   Each hourly cumulative delta contains the final complete row image for every 
business key affected since the start of the day.
   
   For example, if a key changes during `00:00–01:00` and does not change 
again, its updated row must still appear in `CumulativeDelta(2026102006)`.
   
   Rows unchanged since the daily baseline do not need to be repeated.
   
   This gives the following semantics:
   
   - A key present in the cumulative delta contributes its final state 
according to the configured key and sequence semantics.
   - A key absent from the cumulative delta retains its baseline state.
   - If deletion support is included, it requires explicit deletion semantics; 
absence from the cumulative delta must not implicitly mean deletion.
   
   An initial scope could focus on **batch reads with deduplicate semantics and 
complete row images**.
   
   ### 3. Explicit mapping between hourly targets and daily baselines
   
   For the example above, the mapping is:
   
   ```text
   target delta partition = 2026102006
   baseline partition     = 20261019
   ```
   
   This mapping should follow the declared baseline relationship, rather than 
selecting a snapshot through raw partition-value comparison.
   
   In particular, `snapshot/20261020` represents the state at October 21, 
00:00. Even after it becomes available, it must not be used to reconstruct an 
earlier hourly result such as `2026102006`.
   
   A possible implementation could retain the same partition schema on both 
branches, such as a single `pt STRING` partition column, while interpreting 
snapshot values as daily partitions and delta values as hourly partitions. The 
initial implementation would not need different partition-column layouts 
between branches.
   
   ### 4. Proposed integration with Chain Tables
   
   This could be introduced as an opt-in cumulative-delta mode, preserving the 
existing behavior by default.
   
   The read planner would:
   
   1. Resolve the requested logical hourly partition.
   2. Locate its declared daily baseline.
   3. Select only the corresponding cumulative delta partition.
   4. Reuse the existing Chain Table merge reader to produce the full result 
under the requested logical hourly partition.
   
   The current `ChainGroupReadTable.ChainTableBatchScan` seems a relevant place 
to investigate the planning changes. Baseline resolution, partition-time 
interpretation, compaction, and expiration would also need to follow the new 
semantics.
   
   ### 5. Correctness and lifecycle considerations
   
   The following behaviors would need to be defined:
   
   - **Empty results:** distinguish a successfully published empty cumulative 
delta from a partition that has not been produced successfully.
   - **Baseline availability:** a missing required baseline must not silently 
fall back to an unrelated daily snapshot.
   - **Reruns:** define how an hourly overwrite or a daily baseline correction 
affects published results and any materialized full-state partitions.
   - **Retention:** retain a daily baseline while any retained hourly version 
depends on it. Earlier hourly deltas should be independently removable without 
changing later hourly results.
   - **Compaction:** preserve the distinction between daily baselines and any 
optional materialized hourly results.
   - **Read-path compatibility:** define the behavior of streaming and lookup 
reads before enabling them for cumulative deltas.
   
   ## Anything else?
   
   The expected benefits are to reduce repeated full-data writes and avoid 
scanning redundant earlier cumulative delta partitions when reconstructing a 
target hour.
   
   There are also trade-offs: cumulative deltas repeat some changed rows across 
hours, and reconstructing a full hourly result still requires reading the 
relevant baseline data. The storage and read-cost benefits should be evaluated 
against both hourly full copies and ordinary interval-delta Chain Tables.
   
   I would appreciate community feedback on:
   
   1. Whether this use case fits an extension of the existing Chain Table model.
   2. Whether baseline selection should use an explicit baseline reference, a 
configurable period-based rule, or another existing mechanism.
   3. What would be an appropriate initial scope for supporting daily snapshots 
with hourly cumulative deltas.
   
   Related references:
   
   - [[PIP-37: Introduce Chain 
Table](https://cwiki.apache.org/confluence/display/PAIMON/PIP-37%3A+Introduce+Chain+Table)](https://cwiki.apache.org/confluence/display/PAIMON/PIP-37%3A+Introduce+Chain+Table)
   - [[Chain Table 
documentation](https://paimon.apache.org/docs/master/primary-key-table/chain-table/)](https://paimon.apache.org/docs/master/primary-key-table/chain-table/)
   - [[ChainGroupReadTable planning 
implementation](https://github.com/apache/paimon/blob/8c09824c060520f3f1f4a03ce2369de371e5c7c6/paimon-core/src/main/java/org/apache/paimon/table/ChainGroupReadTable.java#L363-L499)](https://github.com/apache/paimon/blob/8c09824c060520f3f1f4a03ce2369de371e5c7c6/paimon-core/src/main/java/org/apache/paimon/table/ChainGroupReadTable.java#L363-L499)
   
   ### Solution
   
   _No response_
   
   ### Anything else?
   
   _No response_
   
   ### Are you willing to submit a PR?
   
   - [x] I'm willing to submit a PR!


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to