Berserk Docs
Scalar FunctionsDynamic / JSON Functions

summarize_graph

Collapse a canonical `{nodes, edges}` graph (from `make_graph`) by a node attribute.

Nodes sharing the same key value merge, and an edge is kept for every node whose immediate parent carries a different key — collapsing a span graph by service yields a service dependency graph, by exe a process-name graph.

A node's count covers every node merged into it; an edge's count covers the parent-child pairs that cross that boundary, one per hand-off. A service emitting ten spans per request therefore carries ten on its node and one on its inbound edge for each request.

Each trailing "<agg>:<attr>" argument aggregates that attribute across the merged nodes, and on an edge across the child of each crossing only, so a callee's internal spans reach its node but not its inbound edge: sum, avg (numeric), min, max (numeric/datetime, or strings compared lexicographically — the comparison follows the type of the earliest value by time, so a numbers-then-strings mix is undefined), countif (boolean → count of trues), set (distinct values), any (a representative), first (value at the earliest time), p<N> (percentile N of the numeric values, e.g. p95 or p99.9, from the same sketch as percentile(); like avg, it ranks the values it is given, so over already-collapsed graphs those are per-graph results). The intrinsic count is summed and time min-merged automatically; the key becomes the new node id; unlisted attributes are dropped. Returns null if g is not a graph or key is null.

make_graph_by fuses this collapse into the make_graph aggregate and returns the same graph from one pass; prefer it unless you also need the raw per-id graph, or want to collapse the same graph by several different keys.

Syntax

summarize_graph(g, key, aggs)

Parameters

Prop

Type

Given a dynamic field

This parameter is string-only. In permissive mode, which every query runs in, almost every field arrives as a dynamic, so passing one works because Berserk injects asstring: extract-or-null, the value when it really is a string and null otherwise, so the call yields null (a predicate yields false). A property bag or array is therefore not matched, and tostring() is never applied implicitly — use it explicitly to match a bag's JSON text, keys included. To search the strings inside an object or array, write body.* contains "x" (also has, hasprefix and hassuffix). See String coercion and the asXXX family.

Returns: dynamic

Examples

Example 1

spans
| summarize g = make_graph(
  span_id,
  parent_span_id,
  start_time,
  "service",
  resource['service.name'],
  "errors",
  status_code == "ERROR"
)
  by trace_id
| project g = summarize_graph(g, "service", "countif:errors")
g (dynamic)
{"edges":[],"nodes":[{"attrs":{"errors":0},"count":2,"id":"unknown","time":1704103260000000000}]}
{"edges":[],"nodes":[{"attrs":{"errors":0},"count":2,"id":"unknown","time":1704103320000000000}]}
{"edges":[],"nodes":[{"attrs":{"errors":0},"count":5,"id":"unknown","time":1704103200000000000}]}

On this page