Search in ClickHouse Observability and Elastic
ClickHouse is a SQL-native engine, designed from the ground up for high-performance analytical workloads. In contrast, Elasticsearch provides a SQL-like interface, transpiling SQL into the underlying Elasticsearch query DSL — meaning it isn’t a first-class citizen, and feature parity is limited. ClickHouse not only supports full SQL but extends it with a range of observability-focused functions, such asargMax, histogram, and quantileTiming, that simplify querying structured logs, metrics, and traces.
For simple log and trace exploration, the observability UI provides a Lucene-style syntax for intuitive, text-based filtering for field-value queries, ranges, wildcards, and more. This is comparable to the Lucene syntax in Elasticsearch and elements of the Kibana Query Language.
The search interface supports this familiar syntax but translates it behind the scenes into efficient SQL WHERE clauses, making the experience familiar for Kibana users while still allowing users to leverage the power of SQL when needed. This allows you to exploit the full range of string search functions, similarity functions and date time functions in ClickHouse.
The search syntax below applies to both managed and self-managed services. Field names depend on your schema; the examples use standard OpenTelemetry log fields where applicable.
ClickHouse Observability search syntax vs Elasticsearch query string
Both ClickHouse Observability and Elasticsearch provide flexible query languages to enable intuitive log and trace filtering. While Elasticsearch’s query string is tightly integrated with its DSL and indexing engine, ClickHouse Observability supports a Lucene-inspired syntax that translates to ClickHouse SQL under the hood. The table below outlines how common search patterns behave across both systems, highlighting similarities in syntax and differences in backend execution.Schema and missing fields
The standard OpenTelemetry schema uses fields such asBody, SeverityText, and ServiceName, with log and resource attributes in LogAttributes and ResourceAttributes. Translate Elastic field names to the corresponding fields in your ingested data—for example, level:error becomes SeverityText:error.
For non-nullable columns, an omitted value is represented by the column’s default, such as an empty string. An empty ServiceName therefore does not tell you whether the sender omitted the value or explicitly sent an empty string.
For self-managed deployments with custom tables, use your column names and check their defaults and nullability. Nullable columns can contain NULL.
For SQL queries, ServiceName != '' checks for a non-empty service name. Attributes stored in a Map are distinct from top-level columns: use mapContains(LogAttributes, 'log.file.path') to check whether an attribute key exists, including when its value is empty.