Miscellaneous operators :: Kloudfuse Docs

Miscellaneous operators

compare timeshift

Adds one or more columns containing time-shifted historical values alongside the current aggregated data. Use compare timeshift to perform day-over-day, week-over-week, or custom-period comparisons in a single query — each shifted column contains the metric value from the specified duration ago.

compare timeshift can only be used after an aggregation operator such as count, sum, or avg. It requires aggregated data to perform time-based comparisons.

Syntax

| compare timeshift <duration>
| compare timeshift <duration> <count>
| compare timeshift <duration> as <alias>
| compare timeshift <duration> as <alias>, timeshift <duration2> as <alias2>

Parameters

Parameter Required Description
<duration> Required How far back to shift. Supported units: m (minutes), h (hours), d (days), w (weeks).
<count> Optional Number of shifted periods to generate. Creates <count> columns, one for each successive period. Default is 1.
as <alias> Optional Custom name for the comparison column. Without an alias, columns are named <metric>_<duration>_<index> (e.g., count_1d_1).
Multiple timeshifts Optional Specify additional timeshift <duration> as <alias> clauses separated by commas to compare against multiple reference periods simultaneously.

Example

Compare hourly nginx request counts with both yesterday and last week.

source="nginx"
| timeslice 1h
| count by (_timeslice)
| compare timeshift 1d as yesterday, timeshift 1w as last_week
_timeslice _count count_yesterday count_last_week
2026-06-27 18:00:00 UTC 650,712 598,240 612,450
2026-06-27 19:00:00 UTC 474,040 441,800 488,920

Expected output (illustrative)

Rows return NULL for the shifted columns when no matching historical data exists for that time period. When timeslice is present, the operator normalizes time values to align with the baseline period. Column naming rules: with alias → <metric><alias>; without alias → <metric>_<duration>_<index>; duplicate aliases → <metric>_<alias>_<index>.

compose

Converts query results into a FuseQL filter expression (a boolean OR of field=value conditions). compose is primarily used as the final stage of a subquery, but can also be run standalone to preview the generated filter. Use it to dynamically build filters from aggregated data — for example, generating a filter from the top error-producing hosts discovered in one query and applying it to another.

Syntax

| compose <field1>[, <field2>, ...] [maxresults=<N>] [keywords]

Parameters

Parameter Required Description
<field1>, …​ Required One or more field names. Multiple fields create AND conditions within each row; rows are combined with OR.
maxresults=<N> Optional Limits the number of result rows used in filter generation. Default: 2500. Maximum: 10000.
keywords Optional Generates keyword grep searches ("value") instead of field equality filters (field="value").

Example

Generate a filter from the level and org_id combinations found in query-service logs, then use it to filter another source.

source="query-service"
| count by level, org_id
| compose level, org_id
_filter
level="error" and org_id="pisco-shared") or (level="info" and org_id="pisco-shared"

Expected output (the compose operator produces a filter string)

compose is most powerful inside a subquery block:
```none
[subquery: source="query-service"

Linear Forecast

Forecasts future metric values by fitting a linear regression model to historical time-series data. Use Linear Forecast when your data shows a consistent upward or downward trend without strong seasonal patterns — for example, predicting steady traffic growth or a declining error rate.

Linear forecasting is built on the Linear Regression. It extrapolates the trend line forward for a specified duration.

Syntax

| predict (<field>) by <bucket_size>, model=linear, forecast=<duration>

Parameters

Parameter Required Description
(<field>) Required The aggregated numeric field to forecast.
by <bucket_size> Required The time bucket size matching the upstream timeslice duration (e.g., 60s, 5m).
model=linear Required Selects the linear regression model.
forecast=<duration> Required How far forward to project. Expressed in seconds (e.g., 3600s for 1 hour).

Example

source="nginx"
| timeslice 60s
| count_unique(@error) by (_timeslice)
| predict (_count_unique) by 60s, model=linear, forecast=3600s
Linear forecasting works best for data with a clear monotonic trend. For data with hourly or daily cyclical patterns, use Seasonal Forecast instead. The forecast duration determines how many additional projected data points appear after the last historical data point.

Reserved fields

FuseQL provides a set of reserved field names that map to the core columns shown in the Log Search results view. Use these fields to filter, extract, or alias the primary log attributes without parsing them from the raw log line.

Field reference

Field Maps to Description
__kf_msg Message column The full raw log line text. Regex matching against __kf_msg is optimized — the engine performs automatic substring extraction for improved query performance.
__kf_level Level column The log severity level (e.g., ERROR, WARN, INFO, DEBUG).
__kf_source Source column The log source identifier (equivalent to the source facet).

Example

Filter logs by message pattern, level, and source simultaneously using reserved fields.

__kf_msg =~ "ERROR.*connection.*timeout"
__kf_level = "ERROR"
__kf_source = "nginx"

Alias example

Reorder the default log columns by aliasing reserved fields. Using aliases disables the default column display and shows only the aliased versions in the result.

* | __kf_msg as LogMessage | __kf_level as LogLevel | __kf_source as LogSource
Reserved fields are available in all FuseQL contexts — filter expressions, where clauses, and pipe stages. __kf_msg regex matching (=~) is particularly efficient because the engine can use index-based substring extraction rather than scanning the full raw text for every row.

Seasonal Forecast

Forecasts future metric values from time-series data that contains recurring seasonal patterns — hourly, daily, or weekly cycles — in addition to overall trends. Use Seasonal Forecast when your data shows predictable periodic behavior, such as traffic spikes every morning or error rate increases every evening.

Seasonal forecasting is built on Prophet, which handles seasonality, trend, and holiday effects simultaneously.

Syntax

| predict (<field>) by <bucket_size>, model=seasonal, seasonality=<period>, forecast=<duration>

Parameters

Parameter Required Description
(<field>) Required The aggregated numeric field to forecast.
by <bucket_size> Required The time bucket size matching the upstream timeslice duration (e.g., 60s, 5m).
model=seasonal Required Selects the seasonal (Prophet) model.
seasonality=<period> Required The dominant seasonal period. Supported values: hourly (24-hour cycle) or daily (7-day cycle).
forecast=<duration> Required How far forward to project. Expressed in seconds (e.g., 3600s for 1 hour).

Example

source="nginx"
| timeslice 60s
| count_unique(@error) by (_timeslice)
| predict (_count_unique) by 60s, model=seasonal, seasonality=hourly, forecast=3600s
Use seasonality=hourly for data with intra-day cycles (for example, a traffic spike at the top of each hour). Use seasonality=daily for data with day-of-week patterns (for example, higher traffic on weekdays). For data without seasonal patterns, use Linear Forecast instead.

subquery

Executes a nested inner query, converts its results into a filter expression using compose, and applies that filter to the outer query. Use subquery to correlate data across sources without manual copy-paste — for example, finding all logs from hosts that also appear in a separate error log source.

The subquery operator must always include a compose operator as its final stage.

Syntax

[subquery: <inner_query> | compose <fields> [maxresults=<N>] [keywords]]

The subquery block can appear in three positions:

[subquery: <inner_query> | compose <fields>] | <outer_query>

<outer_query> | where [subquery: <inner_query> | compose <fields>]

<outer_query> | if([subquery: <inner_query> | compose <fields>], <true_value>, <false_value>) as <field>

Parameters

Parameter Required Description
<inner_query> Required Any valid FuseQL query. Its results are passed to compose.
compose <fields> Required Converts the inner query’s result rows into a boolean filter expression.
maxresults=<N> Optional Limits how many result rows compose uses. Default: 2500. Maximum: 10000.
keywords Optional Generates keyword grep searches instead of field equality filters. Not supported with where or if.

Example

Filter logs from org_id="pisco-shared" to only those originating from hosts that also appear in query-service logs.

org_id="pisco-shared"
and [subquery: source="query-service" | count by host | compose host]
| timeslice 20s
| count by _timeslice

The inner query produces:

host _count
server-1 250
server-2 180

compose host converts this to host="server-1") or (host="server-2", making the full query equivalent to:

org_id="pisco-shared"
and ((host="server-1") or (host="server-2"))
| timeslice 20s | count by _timeslice
Always test the outer query independently before adding the inner subquery. Subqueries within if or where are typically more expensive than subqueries placed at the start of the search expression. Subqueries are not supported in Scheduled Views.

topk

The topk operator keeps the highest-ranked rows of an aggregation result. Use it to answer questions like "the top 5 hosts by error count" or "the top 3 endpoints by latency per service".

topk runs after an aggregation. It sorts the aggregated rows in descending order by a ranking field, keeps at most k rows, and adds a rank column starting at 1. With a by clause, topk ranks within each group independently and returns the top _k rows for every group.

Syntax

| topk(<k>, <ranking_field>)
| topk(<k>, <ranking_field>) by <field1>, <field2>, ...

Output

topk appends a _rank column to the schema. _rank is 1 for the highest-ranked row in each result set (or per group), 2 for the next, and so on. Within a by group, _rank restarts at 1.

Rows are ordered:

Behavior

Example: Top N across all results

Return the 5 sources producing the most logs:

* | count by source | topk(5, _count)

The result has at most 5 rows ranked by _count descending, with _rank values 1 through 5.

Example: Top N per group

Return the 3 most frequent error sources in each 5-minute window:

level="error"
| timeslice 5m
| count by (_timeslice, source)
| topk(3, _count) by _timeslice

Each _timeslice bucket has up to 3 rows, each carrying a _rank of 1, 2, or 3 for that bucket.

Example: Ranking by an aliased aggregation

topk can rank by any output column, including an aliased aggregation:

* | avg(durationMs) as p_avg by endpoint | topk(10, p_avg)
``` \n
This returns the 10 slowest endpoints by average duration.