Skip to content

PPL for DQL/Lucene Users

If you are coming from OpenSearch Dashboards Query Language (DQL) or Lucene query syntax, you may be looking for the language dropdown in Discover. The Observability Stack defaults to PPL in the observability workspace because PPL covers every DQL/Lucene use case and goes far beyond what those query languages can express.

This guide maps the patterns you already know to their PPL equivalents so you can be productive immediately.

Try PPL in the live playground →
DQL / LucenePPL
severityText:ERRORseverityText="ERROR"
field1:a AND field2:bfield1="a" AND field2="b"
severityText:ERROR OR severityText:FATALseverityText="ERROR" OR severityText="FATAL"
NOT severityText:DEBUGNOT severityText="DEBUG"
severityNumber >= 17severityNumber>=17
severityText: (ERROR OR WARN)severityText IN ("ERROR", "WARN")

Both the search keyword and source= are optional and can be omitted:

  • search keyword: Always optional. search source=logs-otel-v1* severityText="ERROR" and source=logs-otel-v1* severityText="ERROR" are identical.
  • source= clause: In the Discover UI, the dataset picker sets your index automatically. You just type the filter expression directly in the search bar - exactly like DQL.

In the Discover UI, you select your dataset from the dataset picker dropdown. This sets the source= automatically - you never need to type it. Your query starts directly with the filter, exactly like typing a DQL query in the search bar:

DQL search barPPL search bar (Discover UI)
severityText: ERRORseverityText="ERROR"
severityText: ERROR AND service.name: cartseverityText="ERROR" AND \resource.attributes.service.name`=“cart”`
(empty - show all)(empty - show all)

The experience is the same: pick your index, type your filter, hit refresh. The dataset picker handles the index selection, so you write exactly the filter expression and nothing more.

When you want to go beyond filtering - aggregate, extract patterns, compute fields - just add a pipe (|) and keep going. That is the part DQL/Lucene cannot do.

This is the most familiar pattern for DQL/Lucene users - just type a word and search. It works identically in PPL:

Lucene:

error

PPL:

error

Unquoted terms in PPL work exactly like Lucene - they search across all fields. Multiple terms are combined with AND by default. Use quotes for phrase matching: "connection refused".

Free-text search in PPL — type a term and search, just like Lucene

Try in playground →

DQL:

severityText: ERROR

PPL:

severityText="ERROR"

In the Discover UI, both are typed directly into the search bar. The only change is : to =.

Try in playground →

DQL:

severityText: ERROR AND resource.attributes.service.name: cart

PPL:

severityText="ERROR" AND `resource.attributes.service.name`="cart"
Try in playground →

Boolean AND works identically. The only extra detail: dotted field names like resource.attributes.service.name need backticks in PPL to prevent them from being interpreted as nested object access.

DQL:

severityText: ERROR OR severityText: FATAL

PPL:

severityText="ERROR" OR severityText="FATAL"
Try in playground → Try in playground →

DQL:

severityText: (ERROR OR WARN OR FATAL)

PPL:

severityText IN ("ERROR", "WARN", "FATAL")
Try in playground →

PPL’s IN operator is cleaner than DQL’s repeated OR syntax for matching against a set of values.

DQL:

severityNumber >= 17

PPL:

severityNumber>=17
Try in playground →

Range operators (>, <, >=, <=) are identical in both DQL and PPL.

DQL and Lucene stop at filtering. Once you have your filtered results, you are limited to what the UI can do. PPL keeps going - after the filter, add a pipe (|) and chain aggregation, transformation, pattern discovery, and more. This is the power of the pipeline.

Aggregate and visualize (not possible in DQL/Lucene)

Section titled “Aggregate and visualize (not possible in DQL/Lucene)”

Start with the same filter, then count and sort:

severityText="ERROR"
| stats count() as errors by `resource.attributes.service.name`
| sort - errors
Try in playground →

This filters for errors, counts them by service, and sorts by count - all in one query. The Discover UI automatically switches to a visualization view when you use stats.

| stats count() as total,
sum(case(severityText = 'ERROR', 1 else 0)) as errors
by `resource.attributes.service.name`
| eval error_rate = round(errors * 100.0 / total, 2)
| sort - error_rate
Try in playground →
severityText="ERROR"
| patterns body
Try in playground →

The patterns command automatically clusters similar log messages. During incident triage, this shows the shape of the problem in seconds - no manual regex needed. This is one of PPL’s most powerful features with no equivalent in DQL or Lucene.

severityText="ERROR"
| timechart timefield=time span=5m count() by `resource.attributes.service.name`
Try in playground →
| grok body '%{IP:client_ip} - %{DATA:user} \[%{HTTPDATE:timestamp}\] "%{WORD:method} %{DATA:url}"'
| stats count() as requests by method, url
| sort - requests
| head 20
Try in playground →
CapabilityDQL/LucenePPL
Field-value filteringYesYes (same syntax, = instead of :)
Boolean logic (AND/OR/NOT)YesYes (identical)
Full-text searchYesYes (unquoted terms, identical)
Range queriesYesYes (>=, <=, identical)
Regex filteringLucene onlyYes (regex command)
AggregationNoYes (stats, timechart, chart)
Computed fieldsNoYes (eval)
Pattern discoveryNoYes (patterns)
Field extractionNoYes (parse, grok, rex)
DeduplicationNoYes (dedup)
Top/rare analysisNoYes (top, rare)
Rolling statisticsNoYes (streamstats, trendline)
Cross-index joinsNoYes (join, lookup, subquery)
Machine learningNoYes (ml, kmeans)
Auto visualizationNoYes (Discover switches to chart on stats)

This is the only operator change. Everything else carries over:

DQL: severityText: ERROR
PPL: severityText="ERROR"

The full form of a PPL query is:

search source=logs-otel-v1* severityText="ERROR"

But both search and source= are optional:

  • search keyword - always optional. Omit it freely.
  • source= clause - in the Discover UI, the dataset picker sets this for you. Just type your filter.

So in the Discover UI search bar, you simply type:

severityText="ERROR"

OpenTelemetry fields contain dots. In DQL, you reference them directly. In PPL, wrap them in backticks to prevent them from being interpreted as nested object access:

DQL: resource.attributes.service.name: cart
PPL: `resource.attributes.service.name`="cart"

PPL’s search expressions use double quotes for string values:

severityText="ERROR"

In PPL, OR binds tighter than AND (the opposite of SQL and Lucene). When combining both, use explicit parentheses:

(severityText="ERROR" OR severityText="FATAL") AND `resource.attributes.service.name`="cart"
Try in playground →
  • search command - Full syntax for the search command, including boolean expressions and full-text search
  • where command - Extended filtering with functions, LIKE, BETWEEN, and computed expressions
  • PPL Overview - Why PPL and how it compares to other query languages
  • Observability Examples - Real-world PPL queries for OTel logs, traces, and AI agent data
  • Discover Logs - Using PPL in the Logs Discover interface