Skip to main content

SPL2 Overview

SPL2 is LynxDB's query language, inspired by Splunk's SPL. It's a pipeline language: data flows left-to-right through a series of commands separated by | (pipe).

SPL2 is used everywhere in LynxDB -- CLI queries, REST API, alerts, dashboards, materialized views, and saved queries. Learn it once, use it everywhere.

Pipeline Concept

[search expression] | command1 args | command2 args | command3 args

Each command receives a stream of events, transforms it, and passes the result to the next command. This is analogous to Unix pipes:

# Unix: find | grep | sort | head
# SPL2: search | where | stats | sort | head

Example Pipeline

source=nginx status>=500
| stats count, avg(duration_ms) by uri
| sort -count
| head 10
| table uri, count, avg(duration_ms)

This reads as:

  1. Search nginx events with status 500+
  2. Aggregate count and average duration by URI
  3. Sort by count descending
  4. Limit to top 10
  5. Project specific columns

Implicit Fields

Every event in LynxDB has these built-in fields:

FieldTypeDescription
_time / _timestampdatetimeEvent timestamp (auto-detected or assigned at ingest)
_rawstringOriginal raw text of the event
_sourcestringSource identifier (e.g., "nginx", "api-gateway")
_idstringUnique event ID (ULID, assigned at ingest)

Implicit FROM

If your query starts with | or a command name (not a search expression), LynxDB automatically prepends FROM main:

-- These are equivalent:
| stats count
FROM main | stats count

-- These are also equivalent:
| where level="error" | stats count
FROM main | where level="error" | stats count

Search Expression

The first part of a pipeline (before the first |) is the search expression. It supports:

-- Keywords (full-text search)
error
"connection refused"

-- Field=value
level=error
status=500

-- Comparisons
status>=500
duration_ms>1000

-- Boolean operators
level=error source=nginx -- implicit AND
level=error OR level=warn
level=error NOT source=redis

-- Wildcards
host=web-*
uri="/api/*"

-- FROM clause (explicit data source)
FROM main WHERE level="error"
FROM mv_errors_5m WHERE source="nginx"

Command Categories

Filtering

CommandDescription
searchFull-text keyword search
whereFilter rows by expression
dedupRemove duplicate values
headTake first N results
tailTake last N results

Aggregation

CommandDescription
statsCompute aggregations
timechartTime-series aggregation
topMost common values
rareLeast common values
eventstatsAggregation without grouping
streamstatsRunning aggregation

Transformation

CommandDescription
evalCompute new fields
rexExtract fields via regex
renameRename fields
binBucket numeric/time values
fillnullReplace null values

Output

CommandDescription
tableSelect and order columns
fieldsInclude or exclude fields
sortOrder results

Combining Data

CommandDescription
joinJoin two datasets
appendAppend results from subsearch
multisearchUnion multiple searches
transactionGroup related events

Data Source

CommandDescription
fromRead from index or view

Aggregation Functions

Used in stats, timechart, eventstats, and streamstats:

FunctionDescription
countCount events
sum(field)Sum values
avg(field)Average value
min(field)Minimum value
max(field)Maximum value
dc(field)Distinct count
values(field)List distinct values
stdev(field)Standard deviation
perc50(field)50th percentile (median)
perc75(field)75th percentile
perc90(field)90th percentile
perc95(field)95th percentile
perc99(field)99th percentile
earliest(field)First value by time
latest(field)Last value by time

See Aggregation Functions for details.

Eval Functions

Used in eval and where expressions:

FunctionDescription
IF(cond, true, false)Conditional
CASE(c1,v1, c2,v2, ...)Multi-way conditional
coalesce(a, b, ...)First non-null value
tonumber(s)Convert to number
tostring(n)Convert to string
round(n, d)Round to d decimal places
substr(s, start, len)Substring
lower(s) / upper(s)Case conversion
len(s)String length
match(s, regex)Regex match
strftime(t, fmt)Format timestamp

See Eval Functions for the full list.

CTEs (Common Table Expressions)

Define reusable intermediate results:

$threats = FROM idx_backend WHERE threat_type IN ("sqli", "path_traversal") | FIELDS client_ip, threat_type;
$logins = FROM idx_audit WHERE type="USER_LOGIN" AND res="failed" | STATS count AS failures BY src_ip;
FROM $threats | JOIN type=inner client_ip [$logins] | WHERE failures > 5
| TABLE client_ip, threat_type, failures

Splunk Compatibility

LynxDB's SPL2 is inspired by Splunk's SPL but has some differences. When you accidentally use SPL1 syntax, LynxDB detects it and suggests the SPL2 equivalent:

hint: "index=main" is Splunk SPL syntax. In LynxDB SPL2, use "FROM main" instead.

See Migrating from Splunk SPL for a full compatibility guide.