Window Join #
Streaming media
Window connection adds the time dimension to the connection standard itself. In doing so, the window join connects the elements of two streams that share a common key and reside in the same window. Semantics and of window connection The semantics of DataStream window connection are the same
For streaming queries, unlike other joins on continuous tables, window joins do not issue intermediate results, but only the final results at the end of the window. In addition, window connections clear all intermediate states when they are no longer needed.
Usually, Window Join and Windowing TVF Use together. In addition, Window Join can be based on Windowing TVF After the operation of, for example Window Aggregation,Window TopN and Window Join.
At present, Window Join requires that the join on condition includes that the start of the window of the input table is equal to the end of the window of the input table.
Window Join supports INNER/LEFT/RIGHT/FULL OUTER/ANTI/SEMI JOIN.
Inside / left / right / all outside #
The syntax of the INNER / LEFT / RIGHT / FULL OUTER Window Join statement is shown below.
SELECT ... FROM L [LEFT|RIGHT|FULL OUTER] JOIN R -- L and R are relations applied windowing TVF ON L.window_start = R.window_start AND L.window_end = R.window_end AND ...
The syntax of INNER / LEFT / RIGHT / FULL OUTER WINDOW JOIN is very similar. Here we only give an example of FULL OUTER JOIN. When a window connection is performed, all elements with a common key and a common flip window are connected together. We only give an example of Window Join for Tumble Window TVF. By limiting the connected time area to a fixed five minute interval, we divided the dataset into two different time windows: [12:00, 12:05) and [12:05, 12:10). L2 and R2 rows cannot be connected together because they fall into separate windows.
Flink SQL> desc LeftTable; +----------+------------------------+------+-----+--------+----------------------------------+ | name | type | null | key | extras | watermark | +----------+------------------------+------+-----+--------+----------------------------------+ | row_time | TIMESTAMP(3) *ROWTIME* | true | | | `row_time` - INTERVAL '1' SECOND | | num | INT | true | | | | | id | STRING | true | | | | +----------+------------------------+------+-----+--------+----------------------------------+ Flink SQL> SELECT * FROM LeftTable; +------------------+-----+----+ | row_time | num | id | +------------------+-----+----+ | 2020-04-15 12:02 | 1 | L1 | | 2020-04-15 12:06 | 2 | L2 | | 2020-04-15 12:03 | 3 | L3 | +------------------+-----+----+ Flink SQL> desc RightTable; +----------+------------------------+------+-----+--------+----------------------------------+ | name | type | null | key | extras | watermark | +----------+------------------------+------+-----+--------+----------------------------------+ | row_time | TIMESTAMP(3) *ROWTIME* | true | | | `row_time` - INTERVAL '1' SECOND | | num | INT | true | | | | | id | STRING | true | | | | +----------+------------------------+------+-----+--------+----------------------------------+ Flink SQL> SELECT * FROM RightTable; +------------------+-----+----+ | row_time | num | id | +------------------+-----+----+ | 2020-04-15 12:01 | 2 | R2 | | 2020-04-15 12:04 | 3 | R3 | | 2020-04-15 12:05 | 4 | R4 | +------------------+-----+----+ Flink SQL> SELECT L.num as L_Num, L.id as L_Id, R.num as R_Num, R.id as R_Id, L.window_start, L.window_end FROM ( SELECT * FROM TABLE(TUMBLE(TABLE LeftTable, DESCRIPTOR(row_time), INTERVAL '5' MINUTES)) ) L FULL JOIN ( SELECT * FROM TABLE(TUMBLE(TABLE RightTable, DESCRIPTOR(row_time), INTERVAL '5' MINUTES)) ) R ON L.num = R.num AND L.window_start = R.window_start AND L.window_end = R.window_end; +-------+------+-------+------+------------------+------------------+ | L_Num | L_Id | R_Num | R_Id | window_start | window_end | +-------+------+-------+------+------------------+------------------+ | 1 | L1 | null | null | 2020-04-15 12:00 | 2020-04-15 12:05 | | null | null | 2 | R2 | 2020-04-15 12:00 | 2020-04-15 12:05 | | 3 | L3 | 3 | R3 | 2020-04-15 12:00 | 2020-04-15 12:05 | | 2 | L2 | null | null | 2020-04-15 12:05 | 2020-04-15 12:10 | | null | null | 4 | R4 | 2020-04-15 12:05 | 2020-04-15 12:10 | +-------+------+-------+------+------------------+------------------+
Note: in order to better understand the windowing behavior, we have simplified the display of timestamp value to not display trailing zeros. For example, if the type is 2020-04-15 08:05, it should be 2020-04-15 08:05:00.000. In Flink SQL client, TIMESTAMP(3).
SEMI connection #
If there is at least one matching row to the right of Semi Window Joins, the half window join returns one row from a left record.
Flink SQL> SELECT * FROM ( SELECT * FROM TABLE(TUMBLE(TABLE LeftTable, DESCRIPTOR(row_time), INTERVAL '5' MINUTES)) ) L WHERE L.num IN ( SELECT num FROM ( SELECT * FROM TABLE(TUMBLE(TABLE RightTable, DESCRIPTOR(row_time), INTERVAL '5' MINUTES)) ) R WHERE L.window_start = R.window_start AND L.window_end = R.window_end); +------------------+-----+----+------------------+------------------+-------------------------+ | row_time | num | id | window_start | window_end | window_time | +------------------+-----+----+------------------+------------------+-------------------------+ | 2020-04-15 12:03 | 3 | L3 | 2020-04-15 12:00 | 2020-04-15 12:05 | 2020-04-15 12:04:59.999 | +------------------+-----+----+------------------+------------------+-------------------------+ Flink SQL> SELECT * FROM ( SELECT * FROM TABLE(TUMBLE(TABLE LeftTable, DESCRIPTOR(row_time), INTERVAL '5' MINUTES)) ) L WHERE EXISTS ( SELECT * FROM ( SELECT * FROM TABLE(TUMBLE(TABLE RightTable, DESCRIPTOR(row_time), INTERVAL '5' MINUTES)) ) R WHERE L.num = R.num AND L.window_start = R.window_start AND L.window_end = R.window_end); +------------------+-----+----+------------------+------------------+-------------------------+ | row_time | num | id | window_start | window_end | window_time | +------------------+-----+----+------------------+------------------+-------------------------+ | 2020-04-15 12:03 | 3 | L3 | 2020-04-15 12:00 | 2020-04-15 12:05 | 2020-04-15 12:04:59.999 | +------------------+-----+----+------------------+------------------+-------------------------+
Note: in order to better understand the windowing behavior, we have simplified the display of timestamp value to not display trailing zeros. For example, if the type is 2020-04-15 08:05, it should be 2020-04-15 08:05:00.000. In Flink SQL client, TIMESTAMP(3).
ANTI connection (ANTI) #
Anti Window Joins are the opposite of inner window joins: they contain all unconnected rows in each public window.
Flink SQL> SELECT * FROM ( SELECT * FROM TABLE(TUMBLE(TABLE LeftTable, DESCRIPTOR(row_time), INTERVAL '5' MINUTES)) ) L WHERE L.num NOT IN ( SELECT num FROM ( SELECT * FROM TABLE(TUMBLE(TABLE RightTable, DESCRIPTOR(row_time), INTERVAL '5' MINUTES)) ) R WHERE L.window_start = R.window_start AND L.window_end = R.window_end); +------------------+-----+----+------------------+------------------+-------------------------+ | row_time | num | id | window_start | window_end | window_time | +------------------+-----+----+------------------+------------------+-------------------------+ | 2020-04-15 12:02 | 1 | L1 | 2020-04-15 12:00 | 2020-04-15 12:05 | 2020-04-15 12:04:59.999 | | 2020-04-15 12:06 | 2 | L2 | 2020-04-15 12:05 | 2020-04-15 12:10 | 2020-04-15 12:09:59.999 | +------------------+-----+----+------------------+------------------+-------------------------+ Flink SQL> SELECT * FROM ( SELECT * FROM TABLE(TUMBLE(TABLE LeftTable, DESCRIPTOR(row_time), INTERVAL '5' MINUTES)) ) L WHERE NOT EXISTS ( SELECT * FROM ( SELECT * FROM TABLE(TUMBLE(TABLE RightTable, DESCRIPTOR(row_time), INTERVAL '5' MINUTES)) ) R WHERE L.num = R.num AND L.window_start = R.window_start AND L.window_end = R.window_end); +------------------+-----+----+------------------+------------------+-------------------------+ | row_time | num | id | window_start | window_end | window_time | +------------------+-----+----+------------------+------------------+-------------------------+ | 2020-04-15 12:02 | 1 | L1 | 2020-04-15 12:00 | 2020-04-15 12:05 | 2020-04-15 12:04:59.999 | | 2020-04-15 12:06 | 2 | L2 | 2020-04-15 12:05 | 2020-04-15 12:10 | 2020-04-15 12:09:59.999 | +------------------+-----+----+------------------+------------------+-------------------------+
Note: in order to better understand the windowing behavior, we have simplified the display of timestamp value to not display trailing zeros. For example, if the type is 2020-04-15 08:05, it should be 2020-04-15 08:05:00.000. In Flink SQL client, TIMESTAMP(3).
Limitation description #
Join clause limitations #
Currently, window join requires that the join on condition include equal window start and equal window end. In the future, we can also simplify the join on clause to include only the window. When TVF is toggle or HOP, the window start is equal.
Input window TVF limits #
At present, the left and right input windows TVF must be the same. This can be extended in the future, for example, by adding a tumble window to a sliding window with the same window size.
Restrictions on Window Join after windowing TVF directly #
At present, if Windowing TVF Followed by Window Join, then Windowing TVF You must use Tumble Windows, Hop Windows, or Cumulate Windows instead of the Session window.