Berserk Docs

The $raw Column

How Berserk resolves column names using $raw in permissive and strict mode

Berserk KQL resolves names differently than Microsoft's Kusto. In Microsoft Kusto, tables always have a fixed schema and unrecognized column names produce errors. Berserk introduces permissive mode and the special $raw column to support semi-structured data common in observability workloads.

What is $raw?

Every dataset (source table) in Berserk has exactly one column: $raw, a dynamic property bag containing the full original record. When data is ingested (e.g. from OpenTelemetry), the entire JSON object is stored in $raw. See OTEL Field Mapping for exactly how OpenTelemetry data is encoded as JSON.

Permissive vs Strict Mode

Berserk has two query modes that control how unknown field names are resolved:

Permissive Mode (default)

In permissive mode, bare identifiers that don't match a declared column are automatically resolved as property paths into $raw. This is called auto-projection.

default | where level == "INFO"

If level is not a declared column but the table has $raw, this is equivalent to:

default | where $raw.level == "INFO"

The auto-projected field has type dynamic, since its actual type is unknown at query time. The editor shows an informational hint on auto-projected fields to indicate they are being resolved from $raw.

Strict Mode

In strict mode, every column reference must match a declared column in the schema. Unknown fields produce an error:

-- Error: unknown column 'level'
Fruit | where level == "INFO"

This is closer to Microsoft Kusto's behavior. Use strict mode when working with well-defined schemas where typos should be caught early.

Explicit $raw Access

You can always access $raw directly using dotted path syntax:

default | where $raw.level == "INFO"

This works in both permissive and strict mode. Nested paths are supported:

default | where $raw.resource.attributes["service.name"] == "api-gateway"

Array indexing is also supported:

default | where $raw.items[0].name == "first"

Type Annotations

Since auto-projected fields are dynamic, arithmetic and comparison operations may need type hints. Use the annotate operator to declare expected types:

default
| annotate response_time:real, status_code:int
| where status_code >= 400
| summarize avg(response_time) by bin($time, 5m)

Without annotation, response_time and status_code would be dynamic, and arithmetic like avg() would require explicit toreal() casts.

Comparison with Microsoft Kusto

BehaviorMicrosoft KustoBerserk (Permissive)Berserk (Strict)
Unknown columnErrorAuto-project from $rawError
$raw columnNo equivalentBuilt-in dynamic columnBuilt-in dynamic column
Type of auto-projected fieldsN/AdynamicN/A

On this page