Transform operators
FuseQL transform operators reshape the result set produced by earlier pipeline stages: bucketing events by time, removing duplicates, pivoting columns, and shifting rows.
backshift
Returns the value of a numeric field from N rows back in a time-ordered result set. The default shift is 1 row. Use backshift to compute period-over-period deltas — subtract the shifted value from the current value to get the change between consecutive time buckets.
Parameters
| Parameter | Required | Description |
|---|---|---|
|
Required |
The numeric field whose previous-row value is retrieved. |
|
Optional |
Number of rows to shift back. Defaults to |
|
Optional |
Output column name for the shifted value. Defaults to |
Example
Count nginx requests per 1-minute bucket, shift by 1 row to get the previous minute’s count, and compute the per-minute delta.
source="nginx"
| timeslice 1m
| count as requests by _timeslice
| backshift requests, 1 as prev_requests
| (requests - prev_requests) as delta
| _timeslice | requests | prev_requests | delta |
|---|---|---|---|
2026-06-27 18:53:00 UTC |
61,441 |
(null) |
(null) |
2026-06-27 18:54:00 UTC |
650,712 |
61,441 |
589,271 |
2026-06-27 18:55:00 UTC |
474,040 |
650,712 |
-176,672 |
|
The first row always returns null for the shifted field because there is no preceding row. |
dedup
Removes duplicate log lines from the result set, retaining only one row per unique combination of the specified fields. Optionally, keep the first N duplicate rows per group instead of just one. Use dedup to collapse repeated log events — for example, keeping only the first occurrence of each unique error message per source.
Parameters
| Parameter | Required | Description |
|---|---|---|
|
Required |
One or more fields that define uniqueness. Rows with the same values for all listed fields are considered duplicates. |
|
Optional |
Number of rows to keep per unique group. Defaults to |
Example
Parse nginx logs and keep only the first log line per unique combination of HTTP method and status code, eliminating repeated entries for the same method/status pair.
source="nginx"
| parse "* - - [*] \"* *\" * * *" as ip,date,method,url,status,bytes,rest
| dedup by method, status
| method | status | url |
|---|---|---|
GET |
200 |
/index.html |
POST |
201 |
/api/users |
GET |
404 |
/missing.html |
|
|
timeslice
Buckets each event’s timestamp into fixed-width time windows for use in time-series aggregation.
The bucket value is exposed as _timeslice (epoch milliseconds) and is the standard grouping field for log-based time-series aggregations.
- Syntax
-
| timeslice <duration> | timeslice <duration> as <alias>none<duration>accepts FuseQL duration literals such as1m,5m,1h,1d,7d. Whenas <alias>is omitted, the bucket field is named_timeslice. - Examples
-
Count events per 5-minute bucket:
* | timeslice 5m | count by (_timeslice)noneGroup by an additional dimension to produce one series per source:
* | timeslice 1m | count by (_timeslice, source)noneUse a custom alias for the bucket field:
* | timeslice 1m as bucket | count by (bucket, status_code)none
To produce a time series, include _timeslice (or the alias) in the by clause. Without it, the aggregation collapses the entire query range into a single value:
* | count
* | timeslice 1m | count by (_timeslice)
The Window operators (accum, rollingstd, smooth, total) and Algorithmic operators all expect a timeslice-produced series upstream.
Bucket alignment
Buckets are anchored to the Unix epoch (1970-01-01 00:00:00 UTC), not to a calendar week, month, or year. Boundaries fall at every multiple of <duration> measured from the epoch:
-
Durations that evenly divide 24 hours (
1m,5m,15m,1h,4h,12h) align to UTC midnight, because UTC midnight is itself a multiple of the duration measured from the epoch. -
Durations that do not divide 24 hours (
7h,13m) remain anchored to the epoch grid but their boundaries drift across the day — they do not land on UTC midnight. -
Multi-day durations (
2d,7d,10d) follow the epoch grid, not calendar boundaries. Withtimeslice 7d, week boundaries always fall on a Thursday because 1970-01-01 was a Thursday. Withtimeslice 10d, boundaries shift through the calendar and do not realign at the start of a month or year.
| Multi-day buckets do not align to calendar weeks or months. For calendar-aligned buckets (for example, "Monday–Sunday" or "first of the month"), pre-process the timestamp with formatDate and group by the formatted value instead. |
Bucket label
_timeslice is the bucket’s right (upper) edge, expressed as epoch milliseconds in UTC. An event with timestamp T lands in (B, B + <duration>] where B + <duration> is the smallest grid boundary ≥ T; that value is the label.
For example, with timeslice 5m and a query starting at 2026-05-04T12:03:00Z, bucket labels are 12:05, 12:10, 12:15, … An event at 12:07:42Z falls in (12:05, 12:10] and is labeled 12:10.
A small number of operators upstream of timeslice (json multi, parse multi, dedup, cat, backshift, compose) cause the engine to emit the bucket’s left edge instead. Plain aggregation queries use the right-edge labeling described here.
|
Bucket labels can fall in the future
Because the label is the right edge, the in-progress bucket is labeled slightly after the events it contains. For minute-scale buckets the offset is negligible; for hour- or day-scale buckets it can be significant, and the label can sit later than the current wall-clock time.
Example with timeslice 7d. If today is Friday 2026-05-01 and you ingest logs with current timestamps, the most recent 7-day boundary is Thursday 2026-04-30 00:00 UTC, so today’s logs land in (2026-04-30 00:00, 2026-05-07 00:00] — labeled 2026-05-07 00:00 UTC, six days in the future.
The same applies to any large <duration> (12h, 1d, 7d, 30d, …): the in-progress bucket’s label leads its latest event by up to <duration>. Practical consequences:
-
Dashboards rendering
_timesliceon the x-axis plot the in-progress bucket at a future timestamp. -
To recover the bucket start, subtract the duration:
_timeslice - <duration_ms>. -
The in-progress bucket is partial; subsequent queries can change its value as more data arrives.
transpose
Converts aggregate query results from a long format into a wide tabular format by pivoting row values into column headers. Similar to a pivot table, transpose transforms a long list of rows into a wide table, making it easier to compare values across dimensions — for example, displaying request counts per status code as separate columns across time.
transpose dynamically creates columns for aggregate search results, allowing you to design queries without knowing the output schema in advance. This is particularly useful for formatting data for dashboard panels and charts.
Syntax
| transpose row <row_field1>[, <row_field2>, ...] column <column_field1>[, <column_field2>, ...]
Parameters
| Parameter | Required | Description |
|---|---|---|
|
Required |
One or more fields whose values become the row labels in the output table. |
|
Required |
One or more fields whose unique values become column headers in the output table. |
Example
Without transpose, the following query produces a long-format table that is difficult to read:
source="nginx"
| timeslice 5m
| count by _timeslice, status
With transpose, pivot the results to display status codes as columns and timeslices as rows:
source="nginx"
| timeslice 5m
| count by _timeslice, status
| transpose row _timeslice column status
| _timeslice | 200 | 404 | 500 |
|---|---|---|---|
2026-06-27 18:50:00 UTC |
412,840 |
1,203 |
87 |
2026-06-27 18:55:00 UTC |
389,120 |
987 |
62 |
|
|