Recipe: Route Decisions Without Row Loops
Route approved, review, and block records with grouped decision indices.
When throughput matters, do not loop over every row and inspect a Python string one by one. Ask BatchResult for row groups and pass those row indices to your downstream writers.
result = engine.evaluate_ndjson(payload)
approved = result.indices_for_decision("APPROVE")
blocked = result.indices_for_decision("BLOCK")
needs_action = result.indices_for_not_decision("APPROVE")
all_groups = result.grouped_decision_indices()CLI equivalent: emit decision rows instead of routing in Python
cat events.ndjson | \
blazerules_agent \
--rules rules.yaml \
--input stdin \
--output ndjson \
--output-path decisions.ndjsonTail or consume decisions.ndjson and route by the decision field. For high-throughput Python routing, use the grouped index arrays shown above.
Use these arrays to slice your original Arrow batch, Kafka metadata list, or application buffer.
def send_rows(writer, rows):
if len(rows):
writer.write_indices(rows)
groups = result.grouped_decision_indices()
send_rows(service_a, groups.get("APPROVE", []))
send_rows(service_b, result.indices_for_not_decision("APPROVE"))CLI equivalent: split compact decision logs by decision
jq -c 'select(.decision == "APPROVE")' decisions.ndjson > approve.ndjson
jq -c 'select(.decision != "APPROVE")' decisions.ndjson > action.ndjsonIf you need rule-level routing, use winning-rule groups:
by_rule = result.grouped_winning_rule_indices()
high_amount_rows = by_rule.get("high_amount_foreign_or_rooted", [])CLI equivalent: split by winning rule from decision logs
jq -c 'select(.winning_rule_id == "high_amount_foreign_or_rooted")' \
decisions.ndjson > high_amount_rows.ndjsonFor detailed debugging, enable OutputDetail.BITMASKS and use:
rows = result.indices_for_rule("high_amount_foreign_or_rooted")
mask = result["high_amount_foreign_or_rooted"]BITMASKS is useful for audits and rule debugging, but DECISIONS is the cheaper production default for routing.