Yaoxuan Wu created FLINK-41506:
----------------------------------
Summary: Batch sliding group window planned as a one-phase
SortWindowAggregate reads the pane time at the input row's time index
Key: FLINK-41506
URL: https://issues.apache.org/jira/browse/FLINK-41506
Project: Flink
Issue Type: Bug
Components: Table SQL / Planner, Table SQL / Runtime
Affects Versions: 2.3.0
Reporter: Yaoxuan Wu
{code:python}
from pyflink.table import TableEnvironment, EnvironmentSettings, DataTypes
from pyflink.table import expressions as T
from pyflink.table.window import Slide
t_env = TableEnvironment.create(EnvironmentSettings.in_batch_mode())
cfg = t_env.get_config()
cfg.set('parallelism.default', '1')
cfg.set('table.local-time-zone', 'UTC')
cfg.set('table.optimizer.agg-phase-strategy', 'ONE_PHASE')
src = t_env.from_elements([(1, 7000)], DataTypes.ROW([DataTypes.FIELD('k',
DataTypes.INT()),
DataTypes.FIELD('v',
DataTypes.BIGINT())]))
t = src.add_columns(T.call_sql("TIMESTAMP '2001-09-09
01:46:40.000'").alias('rt')) # (k, v, rt)
r =
(t.window(Slide.over(T.lit(12).seconds).every(T.lit(3).seconds).on(T.col('rt')).alias('w'))
.group_by(T.col('w'), T.col('k'))
.select(T.col('k'), T.col('w').start, T.col('w').end, T.col('v').sum))
for row in sorted(r.execute().collect(), key=str):
print(row)
# expected: 4 windows starting 2001-09-09 01:46:30, :33, :36, :39
# actual: 4 windows starting 1969-12-31 23:59:57, 1970-01-01 00:00:00,
00:00:03, 00:00:06
{code}
Same on 2.0.1, 2.2.1, 2.3.0 and a 2.4-SNAPSHOT build. The row is placed at 7000
ms, the value of the {{SUM(v)}} buffer. With the input columns in the order
{{(rt, k, v)}} it is placed at 1 ms (the key). With {{(k, rt, v)}} the result
is right. With a fourth column after {{rt}}, the job fails with
{{java.lang.IndexOutOfBoundsException}} in {{WindowsGrouping.getTimeValue}}.
Tumbling windows and the two-phase plan are not affected.
The one-phase plan is not only chosen by ONE_PHASE: with the default strategy,
the same happens when the window input comes from two aggregates, e.g.
{code:python}
a2 = (s2.group_by(T.col('a')).select(T.col('a'), T.lit(1).count.alias('c'))
.group_by(T.col('c')).select(T.col('c').alias('k'), (T.col('c').sum *
7000).alias('v'))
.add_columns(T.call_sql("TIMESTAMP '2001-09-09
01:46:40.000'").alias('rt')))
# s2 = (7, 100), (8, 200): one row (k=1, v=14000); Slide 12 s every 3 s ->
windows around 1970-01-01 00:00:14
{code}
Cause (planner, master):
- {{BatchPhysicalWindowAggregateRule.transformTimeSlidingWindow}}, one-phase
branch: a sliding window with pane optimization ({{enableAssignPane = true}})
becomes a {{BatchPhysicalSortWindowAggregate}} with {{isMerge = false}} and
{{inputTimeFieldIndex}} = the time attribute's index in the input row.
- {{SortWindowCodeGenerator}}: {{enablePreAcc = choosePreAcc || isMerge}}, and
{{choosePreAcc}} is true when {{enableAssignPane}} is set. Input rows are then
pre-accumulated into pane elements laid out as {{[group keys, assignedTs$, agg
buffers]}} ({{WindowCodeGenerator.getWindowsGroupingElementInfo}}).
- {{WindowCodeGenerator.genWindowAggCodes}} passes the same input-row index to
{{genCreateWindowsGroupingCode}}, so {{HeapWindowsGrouping}} reads a pane
element's time ({{WindowsGrouping.getTimeValue}}) at that index. For a
pre-accumulated element the index should be the number of grouping keys (the
{{assignedTs$}} field). The two-phase merge branch already passes
{{newInputTimeFieldIndexFromLocal}}, which points there.
The result is only right when the input's time index happens to equal the
number of grouping keys. This is separate from FLINK-41287, which is about the
same operator. Its reproducer has no key and the time field at index 0, so it
is not affected by this issue.
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)