Postprocessors
A postprocessor turns the prediction table into the shape an application needs. It receives and returns an eager Polars DataFrame.
For a trained order model with a Boolean order/returned target:
import polars as pl
import relflow as rf
@rf.postprocess
def decision(frame: pl.DataFrame, *, threshold: float) -> pl.DataFrame:
returned = pl.col("predictions").struct.field("order/returned")
probability = returned.struct.field("content").struct.field("probability")
return frame.select(
request_id=pl.col("inputs").struct.field("request_id"),
return_probability=probability,
review=probability >= threshold,
)
# request_table is supplied by the application.
result = model.predict(
request_table,
retain=("request_id",),
postprocess=decision.partial(threshold=0.8),
)One output record has this shape; the probability is a placeholder:
request_id: order-42
return_probability: <probability of true>
review: <true or false>The threshold is an application decision rule. The example uses the content probability; incorporate the predicted value state when your application needs to treat missingness separately.
Compose and reuse
The first callback parameter must be frame; additional parameters are keyword-only and bound with .partial(...). A tuple of decorated processors runs left to right. The pipeline converts Arrow to Polars before its first stage and back to Arrow after its last.
Use the same configured processor in each output path:
processor = decision.partial(threshold=0.8)
writer = rf.Writer("predictions", postprocessor=processor)
deployment = rf.Deployment(model=model, retain=("request_id",)).postprocess(processor)For Writer, configure retain=("request_id",) on the prediction data module. Serving requires relflow[serving].
Processors may change rows or columns, but must return an eager frame with at least one column. Retain every source column they need; source data is not otherwise available in the written table. A Writer requires the same output schema across batches in its shard.
HTTP serving has an additional requirement: preserve one final row per valid request in request order. relflow checks the count; the processor owns order.