github-actions[bot] commented on code in PR #68093:
URL: https://github.com/apache/doris/pull/68093#discussion_r4027208502


##########
be/src/exprs/aggregate/aggregate_function_window_funnel_v2.h:
##########
@@ -288,6 +288,54 @@ struct WindowFunnelStateV2 {
         }
     };
 
+    /// One partial chain of the INCREASE mode.
+    /// first_ts is the timestamp of the chain start and is used for the 
time-window check,
+    /// last_ts is the timestamp of the chain's last matched event and is used 
for the
+    /// strict-increase check, list_idx is the position of that event in 
events_list.
+    struct IncreaseLevelState {
+        TimestampType first_ts = 0;
+        TimestampType last_ts = 0;
+        size_t list_idx = 0;
+    };
+
+    /// Keep the state of `level_states` that can reach at least as far as any 
other one: the
+    /// chain start that is the latest, because every event the other states 
can extend has to be
+    /// strictly greater than their last timestamp, and the earlier chain 
start expires first.
+    static void _merge_increase_state(std::vector<IncreaseLevelState>& 
level_states,
+                                      const IncreaseLevelState& new_state) {
+        level_states.push_back(new_state);
+        IncreaseLevelState best = level_states[0];
+        for (const auto& state : level_states) {
+            if (state.first_ts > best.first_ts ||

Review Comment:
   [P2] Preserve the advertised V1 behavior, or make the semantic break 
explicit. For the reachable sorted order `A@0, B@0, B@1, [email protected], B@2, C@2`, V1 
stops the first start at `B@0` and the second at `C@2`, so it returns 2; 
pre-patch V2 also returns 2 because `B@2` overwrites `B@1`. This helper retains 
`B@1` and returns 3 through `C@2`. V1's timestamp-only sort makes tie order 
unstable, but that does not remove this reachable old=V1/new!=V1 transition. If 
V1 compatibility remains the contract, use its sequential expected-level scan; 
if existential longest-chain semantics are intended, please document that 
compatibility change and add this case as a deliberate divergence.



##########
regression-test/suites/query_p0/aggregate/window_funnel_v2.groovy:
##########
@@ -899,4 +899,39 @@ suite("window_funnel_v2") {
         SELECT window_funnel(864000, 'fixed', ts, val>8, val<8, val>15) FROM 
windowfunnel_v2_fixed_edge;
     """
     sql """ DROP TABLE IF EXISTS windowfunnel_v2_fixed_edge """
+
+    // Test INCREASE mode: a later event of an intermediate level must not 
overwrite the state
+    // that is still able to extend the chain.
+    // A@0 -> B@1 -> C@2 is valid, the second B@2 must not hide B@1 from C@2.
+    sql """ DROP TABLE IF EXISTS windowfunnel_v2_increase_overwrite """
+    sql """
+        CREATE TABLE windowfunnel_v2_increase_overwrite (
+            ts datetimev2(6) NULL,
+            e varchar(10) NULL
+        )
+        DUPLICATE KEY(ts) DISTRIBUTED BY HASH(ts) BUCKETS 3
+        PROPERTIES ("replication_num" = "1");
+    """
+    sql """
+        INSERT INTO windowfunnel_v2_increase_overwrite VALUES
+            ('2022-03-12 10:00:00', 'A'), ('2022-03-12 10:00:01', 'B'),
+            ('2022-03-12 10:00:02', 'B'), ('2022-03-12 10:00:02', 'C');
+    """
+    // increase mode: only c2@1 can be extended by c3@2, so the level is 3.
+    order_qt_v2_increase_extendable_level """
+        SELECT window_funnel(10, 'increase', ts, e = 'A', e = 'B', e = 'C') AS 
level
+        FROM windowfunnel_v2_increase_overwrite;
+    """
+    // default mode is not affected: each condition has a matching event after 
the previous one.
+    order_qt_v2_increase_extendable_level_default """
+        SELECT window_funnel(10, 'default', ts, e = 'A', e = 'B', e = 'C') AS 
level
+        FROM windowfunnel_v2_increase_overwrite;
+    """
+    // deduplication mode also reaches 3: the repeated 'B' row is not inside 
the gap that is
+    // checked when the chain advances, so the chain A@0 -> B@1 -> C@2 stays 
valid.
+    order_qt_v2_increase_extendable_level_dedup """

Review Comment:
   [P2] Make this equal-timestamp regression self-consistent. The old INCREASE 
code fails only when `B@2` is visited before `C@2`, but under that same order 
deduplication finds `B@2` in the gap before `C` and returns 2, not the recorded 
3. Reversing the tie yields deduplication 3, but then the old INCREASE code 
already returns 3, so this SQL case no longer proves the fix. Since `ts` is the 
only key/order value, please force the intended order and expect deduplication 
2, or split/remove the unrelated dedup assertion.



##########
be/src/exprs/aggregate/aggregate_function_window_funnel_v2.h:
##########
@@ -288,6 +288,54 @@ struct WindowFunnelStateV2 {
         }
     };
 
+    /// One partial chain of the INCREASE mode.
+    /// first_ts is the timestamp of the chain start and is used for the 
time-window check,
+    /// last_ts is the timestamp of the chain's last matched event and is used 
for the
+    /// strict-increase check, list_idx is the position of that event in 
events_list.
+    struct IncreaseLevelState {
+        TimestampType first_ts = 0;
+        TimestampType last_ts = 0;
+        size_t list_idx = 0;
+    };
+
+    /// Keep the state of `level_states` that can reach at least as far as any 
other one: the
+    /// chain start that is the latest, because every event the other states 
can extend has to be
+    /// strictly greater than their last timestamp, and the earlier chain 
start expires first.
+    static void _merge_increase_state(std::vector<IncreaseLevelState>& 
level_states,
+                                      const IncreaseLevelState& new_state) {
+        level_states.push_back(new_state);
+        IncreaseLevelState best = level_states[0];
+        for (const auto& state : level_states) {
+            if (state.first_ts > best.first_ts ||
+                (state.first_ts == best.first_ts && state.last_ts < 
best.last_ts)) {
+                best = state;
+            }
+        }
+        level_states.assign(1, best);
+    }
+
+    /// Remove the states of the levels below `updated_level` that can no 
longer be part of a
+    /// better chain: a state of a higher level whose last timestamp is not 
greater can extend
+    /// every event the lower state can extend, and it already reaches a 
higher level.
+    static void 
_prune_increase_levels(std::vector<std::vector<IncreaseLevelState>>& levels,
+                                       int updated_level) {
+        for (int level = updated_level; level >= 0 && !levels[level].empty(); 
--level) {
+            bool dominated = false;
+            for (int higher = level + 1; higher < 
static_cast<int>(levels.size()) && !dominated;

Review Comment:
   [P1] Avoid the all-level scan on every successful event. With 127 supported 
conditions, a valid group containing many event-0 rows followed by one strictly 
increasing match for levels 1..125 and no level 126 never hits the full-chain 
return; this loop performs about 675k higher-level checks per start before the 
normal event scan, versus one predecessor update per event before this patch. 
Repeated level-125 matches add 8,001 checks each even when the retained state 
does not change. Please use flat per-level state and an O(K) frontier/suffix 
pass (or remove the unnecessary cross-level pruning) so this fix does not turn 
high-arity funnels into an O(M*N*K^2) hot path.



##########
regression-test/suites/query_p0/aggregate/window_funnel_v2.groovy:
##########
@@ -899,4 +899,39 @@ suite("window_funnel_v2") {
         SELECT window_funnel(864000, 'fixed', ts, val>8, val<8, val>15) FROM 
windowfunnel_v2_fixed_edge;
     """
     sql """ DROP TABLE IF EXISTS windowfunnel_v2_fixed_edge """
+
+    // Test INCREASE mode: a later event of an intermediate level must not 
overwrite the state
+    // that is still able to extend the chain.
+    // A@0 -> B@1 -> C@2 is valid, the second B@2 must not hide B@1 from C@2.
+    sql """ DROP TABLE IF EXISTS windowfunnel_v2_increase_overwrite """
+    sql """
+        CREATE TABLE windowfunnel_v2_increase_overwrite (
+            ts datetimev2(6) NULL,
+            e varchar(10) NULL
+        )
+        DUPLICATE KEY(ts) DISTRIBUTED BY HASH(ts) BUCKETS 3
+        PROPERTIES ("replication_num" = "1");
+    """
+    sql """
+        INSERT INTO windowfunnel_v2_increase_overwrite VALUES
+            ('2022-03-12 10:00:00', 'A'), ('2022-03-12 10:00:01', 'B'),
+            ('2022-03-12 10:00:02', 'B'), ('2022-03-12 10:00:02', 'C');
+    """
+    // increase mode: only c2@1 can be extended by c3@2, so the level is 3.
+    order_qt_v2_increase_extendable_level """
+        SELECT window_funnel(10, 'increase', ts, e = 'A', e = 'B', e = 'C') AS 
level
+        FROM windowfunnel_v2_increase_overwrite;
+    """
+    // default mode is not affected: each condition has a matching event after 
the previous one.
+    order_qt_v2_increase_extendable_level_default """
+        SELECT window_funnel(10, 'default', ts, e = 'A', e = 'B', e = 'C') AS 
level
+        FROM windowfunnel_v2_increase_overwrite;
+    """
+    // deduplication mode also reaches 3: the repeated 'B' row is not inside 
the gap that is
+    // checked when the chain advances, so the chain A@0 -> B@1 -> C@2 stays 
valid.
+    order_qt_v2_increase_extendable_level_dedup """
+        SELECT window_funnel(10, 'deduplication', ts, e = 'A', e = 'B', e = 
'C') AS level
+        FROM windowfunnel_v2_increase_overwrite;
+    """
+    sql """ DROP TABLE IF EXISTS windowfunnel_v2_increase_overwrite """

Review Comment:
   [P2] Keep this table after the regression runs. The repository test contract 
requires dropping before use, not after completion, so failure state remains 
available for debugging; this block already has the required pre-test DROP at 
line 906. Please remove this trailing cleanup.



-- 
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]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to