Streaming #
Search on Pizza is real-time — documents are visible the moment they are
written. The stream block attaches delivery directives to a search
request: how the engine should pace and batch the emission of a result
that outgrows one response, instead of making the client poll.
POST /my-collection/_search
How it works #
stream is a native, parsed block of the Pizza request DSL
(StreamConfig in lib/engine/src/search/request/mod.rs) — accepted,
validated, and carried through the engine with every request. Its knobs
describe the emission strategy of the search pipeline:
batch(the default) is the linear pipeline — execute fully, rank, return one JSON answer.progressivepaces emission per segment: partial results become available as each segment completes, rather than after all of them.thresholdholds hits back until scores drop belowscore_threshold(ormax_wait_mspasses), trading a little latency for a stable top of the list.buffer_sizemicro-batches whatever is emitted;aggs_prioritydecides whether aggregations in the same request yield to hit delivery (deferredships hits first and fills the aggregation results in afterwards).
Honest delivery status: over the HTTP gateway every mode currently
answers as one complete, buffered JSON body — the block is parsed and
executed, but the gateway does not yet translate it into a chunked or
event-stream HTTP response, and the in-page widget executes one-shot
queries against a WebAssembly engine either way. What is fully real
today is the realtime half of the story: there is no refresh interval,
so a query re-issued immediately after a write sees that write (see
How realtime works) — polling with
search_after cursors is an effective stand-in for push delivery while
wire-level streaming matures.
Example #
This page has no live playground demo: streaming directives shape how a long-running result is paced, while the in-page widget executes one-shot queries against a WebAssembly engine and renders a complete JSON result. Over the gateway today the request below simply returns the usual buffered JSON answer — the block is accepted and executed, wire-level chunked delivery is not switched on yet.
{
"query": { "match": { "field": "message", "query": "error" } },
"size": 0,
"stream": {
"mode": "progressive",
"buffer_size": 4,
"max_wait_ms": 250
}
}
Use cases #
- Dashboards over big scans.
progressivewith a generousbuffer_size: the first segments’ hits reach the UI while later segments are still being searched, instead of a spinner until the whole corpus is ranked. - Alerting-style consumers.
thresholdmode with a highscore_thresholdand a small buffer: only strong matches flush early, andmax_wait_msbounds how long a partial buffer waits. - Hits before aggregates. A request combining a large hit page with
heavy aggregations under
aggs_priority: "deferred"ships the hits first and lets the aggregation totals follow. - Fresh-as-possible tails. Realtime visibility means a polling loop
with
search_afteroverlogssees a freshly written error line on its very next request — no refresh window to wait out.
Parameters for stream
#
mode
(Required,batch|progressive|threshold) Delivery mode:batch— normal one-shot search; the block only configures timing.progressive— flush partial results as the query makes progress, then keep pushing newly matching documents.threshold— hold results back until a score threshold or wait budget is met, trading freshness for stability.
buffer_size
(Optional, integer, default:4) Micro-batching of pushed hits — more is cheaper per hit, less is lower latency.score_threshold
(Optional, float) Inthresholdmode, the score a hit must reach before the buffer flushes.max_wait_ms
(Optional, integer) Upper bound on how long a partially filled buffer may wait before flushing regardless.aggs_priority
(Optional,normal|low|deferred, default:normal) Whether aggregations in the same request block streaming delivery.deferredships hits first and fills in aggregation results later.
Notes #
- Streaming interacts with realtime visibility: a hit can arrive in the same request that indexed it — there is no refresh interval to wait for.
- Cursors (
search_after) combine with streaming for durable consumption; the change feed is the complementary write-path stream (CDC). - Keep
buffer_sizesmall for alerting-style consumers and large for dashboard-style consumers.
Related #
- API conventions — the request
envelope every
streamblock rides in, andpitsnapshots for stable re-queries while data moves. - Sort and pagination —
search_aftercursors: the polling leg of the streaming story. - Change feed — the write-path stream (CDC) for consumers that need every change, not every match.
- How realtime works — the write path (WAL, mutable layer, epoch freeze) that removes the refresh window streaming builds on.