You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -172,60 +172,289 @@ EMIT ON UPDATE WITH BATCH 1s;
172
172
173
173
This query checks for changes every second and emits results only when updates occur.
174
174
175
-
### `EMIT AFTER KEY EXPIRE`
175
+
### `EMIT AFTER SESSION CLOSE`
176
176
177
-
Designed for **OpenTelemetry trace analysis** and other similar use cases where you need to track **key lifetimes** across high-cardinality datasets (e.g., trace spans).
177
+
Designed for **sessionization**, **OpenTelemetry trace analysis** and other similar use cases where you need to track **session lifetimes** across high-cardinality datasets (e.g., trace spans).
178
178
179
-
This policy emits aggregation results once a key is considered **expired**.
179
+
This policy emits aggregation results once a session is considered**closed** or**expired**.
180
180
181
181
**Syntax**:
182
182
183
183
```sql
184
-
EMIT AFTER KEY EXPIRE [IDENTIFIED BY <col>] WITH [ONLY] MAXSPAN <interval> [AND TIMEOUT <interval>]
184
+
EMIT AFTER SESSION CLOSE
185
+
[IDENTIFIED BY (<ts_col>[, <session_start_col>, <session_end_col>])]
186
+
WITH [ONLY] MAXSPAN <interval>
187
+
[AND TIMEOUT <interval>]
185
188
```
186
189
187
190
**Parameters**:
188
-
*`EMIT AFTER KEY EXPIRE` - enables per-key lifetime tracking.
189
-
*`IDENTIFIED BY <col>` - column used to compute span duration (defaults to **_tp_time** if omitted).
190
-
*`MAXSPAN <interval>` - maximum allowed span before emission.
191
-
*`ONLY` - emit results only if span exceeds MAXSPAN.
192
-
*`TIMEOUT <interval>` - forces emission after inactivity to avoid waiting indefinitely.
191
+
*`EMIT AFTER SESSION CLOSE`. Enables per-session lifetime tracking and emits results when a session ends.
192
+
*`IDENTIFIED BY (<ts_col>[, <session_start_col>, <session_end_col>])`. Defines how session boundaries are identified.
193
+
*`<ts_col>` — Timestamp column used to calculate session span duration. Default: _tp_time.
194
+
*`<session_start_col>` — Boolean column indicating when a session starts. Usually it is predicates evaluated in the SELECT. (Optional)
195
+
*`<session_end_col>` — Boolean column indicating when a session ends. Usually it is predicates evaluated in the SELECT. (Optional)
196
+
*`MAXSPAN <interval>`. The maximum duration allowed for a session before it is emitted, regardless of new activity.
197
+
*`ONLY`. When specified, results are emitted only if the session’s duration exceeds `MAXSPAN`.
198
+
*`TIMEOUT <interval>`. Defines the maximum wall-clock duration a session can remain open. If a session stays active longer than this interval, it is automatically emitted to prevent indefinite waiting.
193
199
194
-
:::info
195
-
Currently must be used with `SETTINGS default_hash_table='hybrid'` to prevent excessive memory usage.
196
-
:::
200
+
#### Variants of `IDENTIFIED BY`
197
201
198
-
**Example**:
202
+
Different configurations of `IDENTIFIED BY` allow flexible session control depending on the availability of start/end indicators:
203
+
204
+
1.`IDENTIFIED BY ts_col`.
205
+
206
+
No explicit session start or end signals.
207
+
* A session closes when `MAXSPAN` or `TIMEOUT` is reached.
208
+
* All events for the same session key are included.
209
+
210
+
2.`IDENTIFIED BY (ts_col, session_start_col, session_end_col)`.
211
+
212
+
Both start and end conditions are explicitly defined.
213
+
* A session opens when `session_start_col = true`.
214
+
* Events before an open session are ignored.
215
+
* The session closes when `session_end_col = true`, or when `MAXSPAN` or `TIMEOUT` is reached.
216
+
217
+
3.`IDENTIFIED BY (ts_col, session_start_col, false)`.
218
+
219
+
Only a session start condition is defined.
220
+
* A session opens when `session_start_col = true`.
221
+
* Events before a session opens are ignored.
222
+
* The session closes when `MAXSPAN` or `TIMEOUT` is reached.
223
+
224
+
4.`IDENTIFIED BY (ts_col, true, session_end_col)`.
225
+
226
+
Only a session end condition is defined.
227
+
* A session opens when the first event is observed.
228
+
* The session closes when `session_end_col = true`, or when `MAXSPAN` or `TIMEOUT` is reached.
229
+
230
+
#### Session Fine-Tuning Settings
231
+
232
+
Timeplus provides several query settings to fine-tune session behavior:
233
+
234
+
1.`merge_open_sessions` — (Default: `false`).
235
+
236
+
Controls whether multiple overlapping or consecutive sessions for the same key should be merged into a single extended session. When set to `true`, if a new session starts before the previous one closes, Timeplus merges them into one continuous session.
237
+
238
+
2.`include_session_end` — (Default: `true`)
239
+
240
+
Determines whether the event that triggers the session end should be included in the final session output. When set to `false`, the session end event itself will be excluded from the emitted session data.
241
+
242
+
#### Examples
243
+
244
+
Assume you have millions of network devices that go through a series of **state transitions** before establishing a connection. You want to analyze metrics such as **time-to-successful-connect** and **consecutive failures** for each device in real time.
199
245
200
246
```sql
201
-
WITH grouped AS
247
+
CREATE STREAM IF NOT EXISTS devices
202
248
(
203
-
SELECT
204
-
trace_id,
205
-
min(start_time) AS start_ts,
206
-
max(end_time) AS end_ts,
207
-
date_diff('ms', start_ts, end_ts) AS span_ms,
208
-
group_array(json_encode(span_id, parent_span_id, name, start_time, end_time, attributes)) AS trace_events
209
-
FROM otel_traces
210
-
SHUFFLE BY trace_id
211
-
GROUP BY trace_id
212
-
EMIT AFTER KEY EXPIRE IDENTIFIED BY end_time WITH ONLY MAXSPAN 500ms AND TIMEOUT 2s
-`phase` represents the current state in the connection workflow. The initial phase of a connection starts with `'assoc'` and ends with `'connection'` when successful.
258
+
-`status` indicates whether the transition was successful or failed.
259
+
260
+
##### Example 1: Time-to-Successful-Connect
261
+
262
+
```sql
263
+
-- Time to successful connect
264
+
WITH connect_phase_events AS
265
+
(
266
+
SELECT
267
+
*,
268
+
phase ='assoc'AS session_start, -- defines the session start predicates
269
+
phase ='connection'AND status ='success'AS session_end -- defines the session ends predicates
270
+
FROM
271
+
devices
272
+
WHERE phase IN ('assoc', 'auth', 'dhcp', 'dns', 'connection')
213
273
)
214
-
SELECT json_encode(trace_id, start_ts, end_ts, span_ms, trace_events) AS event
215
-
FROM grouped
216
-
SETTINGS
217
-
default_hash_table='hybrid',
218
-
max_hot_keys=1000000;
274
+
SELECT device,
275
+
count() AS events,
276
+
count_if(status ='failed') AS fails,
277
+
min(_tp_time) AS session_start_ts,
278
+
max(_tp_time) AS session_end_ts,
279
+
date_diff('ms', session_start_ts, session_end_ts) AS time_to_successful_connect_ms
280
+
FROM connect_phase_events
281
+
GROUP BY device
282
+
EMIT AFTER SESSION CLOSE IDENTIFIED BY (_tp_time, session_start, session_end) WITH MAXSPAN 1s AND TIMEOUT 2s;
219
283
```
220
284
221
285
**Explanation**:
286
+
-`session_start` marks when a session begins (`phase = 'assoc'`).
287
+
-`session_end` marks when the connection succeeds (`phase = 'connection' AND status = 'success'`) and hence session ends.
288
+
-`IDENTIFIED BY (_tp_time, session_start, session_end)` controls when sessions open and close.
289
+
290
+
**Sample events**:
291
+
```sql
292
+
INSERT INTO devices (device, phase, status, _tp_time) VALUES
Without `merge_open_sessions = true`, each `assoc` event will start a new session and the next `assoc` event will force close the previous session, so there will be multiple sessions emitted.
356
+
357
+
##### Example 3: Handling Out-of-Order Events
358
+
359
+
If events arrive slightly out of order, you can use an `IDENTIFIED BY` variant to open sessions for any event from the same device.
360
+
361
+
**Query**:
362
+
```sql
363
+
WITH connect_phase_events AS
364
+
(
365
+
SELECT
366
+
*,
367
+
phase ='connection'AND status ='success'AS session_end -- defines the session ends predicates
368
+
FROM
369
+
devices
370
+
WHERE phase IN ('assoc', 'auth', 'dhcp', 'dns', 'connection')
371
+
)
372
+
SELECT device,
373
+
count() AS events,
374
+
count_if(status ='failed') AS fails,
375
+
min(_tp_time) AS session_start_ts,
376
+
max(_tp_time) AS session_end_ts,
377
+
date_diff('ms', session_start_ts, session_end_ts) AS time_to_successful_connect_ms
378
+
FROM connect_phase_events
379
+
GROUP BY device
380
+
EMIT AFTER SESSION CLOSE IDENTIFIED BY (_tp_time, true, session_end) WITH MAXSPAN 1s AND TIMEOUT 2s
381
+
SETTINGS merge_open_sessions = true;
382
+
```
383
+
384
+
**Sample Events**:
385
+
```sql
386
+
-- out of order
387
+
INSERT INTO devices (device, phase, status, _tp_time) VALUES
0 commit comments