Markov Chains#
markov(group, states, matrix) models stateful transitions - each call returns the next state based on the current one and a transition probability matrix. Each worker maintains its own chain state, starting at state 0.
The group key tracks state independently, so multiple groups can run separate chains concurrently within the same query.
See the Function Reference for the full signature and lifecycle details.
Example: order status progression#
up {
create_orders `CREATE TABLE IF NOT EXISTS orders (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
status STRING NOT NULL
)`
}
run {
insert_order(type: exec)
`INSERT INTO orders (status) VALUES ($1)` (
markov('order_status',
['pending', 'processing', 'shipped', 'delivered', 'returned'],
[
0.0, 1.0, 0.0, 0.0, 0.0,
0.0, 0.3, 0.7, 0.0, 0.0,
0.0, 0.0, 0.2, 0.8, 0.0,
0.0, 0.0, 0.0, 0.9, 0.1,
0.0, 0.0, 0.0, 0.0, 1.0
]
)
)
}Transition matrix#
The matrix reads left-to-right per row. Each row must sum to 1.0.
| From ↓ \ To → | pending | processing | shipped | delivered | returned |
|---|---|---|---|---|---|
| pending | 0.0 | 1.0 picks up | 0.0 | 0.0 | 0.0 |
| processing | 0.0 | 0.3 | 0.7 ships | 0.0 | 0.0 |
| shipped | 0.0 | 0.0 | 0.2 | 0.8 arrives | 0.0 |
| delivered | 0.0 | 0.0 | 0.0 | 0.9 keeps | 0.1 returns |
| returned | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 |
Results#
After running, query the distribution:
SELECT status, count(*) AS total
FROM orders
GROUP BY 1
ORDER BY 2 DESC;
status | total
-------------+--------
delivered | 2953
processing | 236
returned | 221
shipped | 214
pending | 195Most rows end up in delivered because it has the highest stay probability (0.9). The chain cycles: returned orders flow back to pending, creating a realistic order lifecycle.