Project: YDB (App Definition and Development / Database)
File: session_window.md

YQL supports grouping by session. To standard expressions in `GROUP BY`, you can add a special `SessionWindow` function: ```sql SELECT user, session_start, SessionStart() AS samesessionstart, -- It's same as session_start COUNT(*) AS session_size, SUM(value) AS sumoversession, FROM my_table GROUP BY user, SessionWindow(<timeexpr>, <timeoutexpr>) AS session_start ``` The following happens in this case: 1) The input table is partitioned by the grouping keys specified in `GROUP BY`, ignoring SessionWindow (in this case, it's based on `user`). If `GROUP BY` includes nothing more than SessionWindow, then the input table gets into one partition. 2) Each partition is split into disjoint subsets of rows (sessions). For this, the partition is sorted in the ascending order of the `time_expr` expression. The session limits are drawn between neighboring items of the partition, that differ in their `timeexpr` values by more than `timeoutexpr`. 3) The sessions obtained in this way are the final partitions on which aggregate functions are calculated. The SessionWindow() key column (in the example, it's `sessionstart`) has the value "the minimum `timeexpr` in the session". If `GROUP BY` includes SessionWindow(), you can use a special aggregate function . An extended version of SessionWindow with four arguments is also supported: `SessionWindow(<orderexpr>, <initlambda>, <updatelambda>, <calculatelambda>)` Where: `<order_expr>`: An expression used to sort the source partition `<init_lambda>`: A lambda function to initialize the state of session calculation. It has the signature `(TableRow())->State`. It's called once for the first (following the sorting order) element of the source partition `<updatelambda>`: A lambda function to update the status of session calculation and define the session limits. It has the signature `(TableRow(), State)->Tuple<Bool, State>`. It's called for every item of the source partition, except the first one. The new value of state is calculated based on the current row of the table and the previous

If the first item in the return tuple is `True`, then a new session starts from the current row. The key of the new session is obtained by applying `<calculatelambda>` to the second item in the tuple. `<calculatelambda>`: A lambda function for calculating the session key (the "value" of SessionWindow() that is also accessible via SessionStart()). The function has the signature `(TableRow(), State)->SessionKey`. It's called for the first item in the partition (after `<initlambda>`) and those items for which `<updatelambda>` has returned `True` in the first item in the tuple. Please note that to start a new session, you should make sure that `<calculatelambda>` has returned a value different from the previous session key. Sessions having the same keys are not merged. For example, if `<calculate_lambda>` returns the sequence `0, 1, 0, 1`, then there will be four different sessions. Using the extended version of SessionWindow, you can, for example, do the following: divide a partition into sessions, as in the SessionWindow use case with two arguments, but with the maximum session length limited by a certain constant: Example ```sql $max_len = 1000; -- is the maximum session length. $timeout = 100; -- is the timeout (timeout_expr in a simplified version of SessionWindow). $init = ($row) -> (AsTuple($row.ts, $row.ts)); -- is the session status: tuple from 1) value of the temporary column ts in the session's first line and 2) in the current line $update = ($row, $state) -> { $isendsession = $row.ts - $state.0 > $max_len OR $row.ts - $state.1 > $timeout; $newstate = AsTuple(IF($isend_session, $row.ts, $state.0), $row.ts); return AsTuple($isendsession, $new_state); }; $calculate = ($row, $state) -> ($row.ts); SELECT user, session_start, SessionStart() AS samesessionstart, -- It's same as session_start COUNT(*) AS session_size, SUM(value) AS sumoversession, FROM my_table GROUP BY user, SessionWindow(ts, $init, $update, $calculate) AS session_start ``` You can use SessionWindow in GROUP BY only once.