Hi team, I’m wondering if I found a bug in Window ...
# troubleshooting
d
Hi team, I’m wondering if I found a bug in Window TVF not correctly propagating
rowtime
in the
toDataStream
conversion, at least in batch execution mode. The core logic of what I’m doing is in the attached snippet. At a high level, the code extracts a field from a POJO in a DataStream, converts to the Table API, performs a Window TVF, and converts back to a DataStream<Tuple<>>. Then, that DataStream is converted back into a Table, where another Window TVF is applied, and the output is converted back to a different Tuple DataStream. I realize there’s no need to convert the first table back to DataStream, but the point is the
toDataStream
conversion isn’t, apparently, propagating the
rowtime
on the first Table. When this logic runs in batch execution mode, the error is:
org.apache.flink.util.FlinkRuntimeException: Could not find timestamp in DataStream API record. Make sure that timestamps have been assigned before and the event-time characteristic is enabled.
. From inserting some .shuffle calls to split the operators and narrow down the error source, it looks like the first phase of the 2nd window TVF is where it happens, i.e. this stage fails:
Copy code
[40]:TableSourceScan(table=[[*anonymous_datastream_source$6*]], fields=[f0, f1, rowtime])
+- [41]:Calc(select=[f0, f1, CAST(rowtime AS TIMESTAMP_LTZ(3) *ROWTIME*) AS rowtime])
   +- [42]:WindowTableFunction(window=[HOP(time_col=[rowtime], size=[86400000 ms], slide=[1 h])])
      +- [43]:Calc(select=[f0, window_start, window_end, window_time AS rowtime, f1])
         +- [44]:LocalHashAggregate(groupBy=[f0, window_start, window_end, rowtime], select=[f0, window_start, window_end, rowtime, Partial_SUM(f1) AS sum$0])
The earlier stage looks like this:
Copy code
[37]:HashAggregate(isMerge=[true], groupBy=[f0, window_start, window_end, rowtime], select=[f0, window_start, window_end, rowtime, Final_COUNT(count1$0) AS f3])
+- [38]:Calc(select=[f0, f3, rowtime])
   +- [39]:ConstraintEnforcer[NotNullEnforcer(fields=[f3, rowtime])]
      +- TableToDataSteam(type=ROW<`f0` INT, `f3` BIGINT NOT NULL, `rowtime` TIMESTAMP_LTZ(3) NOT NULL> NOT NULL, rowtime=false)
Not sure if it’s relevant, but I thought the
rowtime=false
was unusual. I expected the first Window TVF should propagate a time attribute. The documentation says
window_time
is a time attribute, and shows how it’s used in a subsequent TVF as the
rowtime
. So, I’d expect it to propagate via
toDataStream
, too.
If I run the job in streaming mode, when the watermark advances, it seems to output rows from the operators that failed in batch mode. I’m on Flink 1.17.
I can’t find any documentation online about whether it’s possible to force a column of an existing Table to be a ROWTIME column. Usually, the documentation shows how to get it as a metadata column when the table is first created, and says that as long as there’s a single time attribute column,
toDataStream
will set the timestamp of outgoing rows as that. But something’s going wrong in that process, at least in batch mode.
I think I found a workaround to this. It took a long while 😕 . It’s not pretty, but it looks like it gives correct results. It is to convert the DataStream to type
Row
, and fetch the
window_time
as Java type
Instant
. Then, that can be converted
toMillisEpoch()
, and emitted inside a tuple alongside the other data fields I want. Then, I call
assignTimestampsAndWatermarks
with an out-of-orderness of 0 to assign a timestamp. I am not sure how existing watermarks are handled in this approach. But I think this workaround may generate new watermarks equal to the
window_time
? After assigning the timestamp, I
.map
the tuple to a new tuple that drops the
Long
milliseconds epoch, since that’s now carried along with the DataStream element as a proper timestamp.