StateAccessor in YTsaurus Flow (Python)
Use StateAccessor to read, modify, and delete state values. For general information about stateful processing, see the Stateful processing section.
How it works
In Flow, the state is stored in sorted dynamic tables. If you’re using external state, you create this table yourself. If you’re using internal state, Flow automatically creates and manages the tables.
For TTransformCompanionComputation, the key columns in the state table match the group_by_schema of the computation. For the internal state of TTransformOrderedSourceCompanionComputation, the source partition key is used instead; this SourceComputation does not support group_by_schema. In both cases, messages with the same key share one state.
Reading and writing data
The worker directly handles table operations (reading, writing, and deleting data). When the worker receives a new batch of messages, it loads the state values for all keys in the batch and sends them to the companion along with the messages and timers. For more details, see the interaction schema.
You write new values to the state table transactionally within an epoch.
Four accessor types
The Python SDK provides four accessor types for working with state:
| Accessor | Format | Retrieval | Description |
|---|---|---|---|
| YsonStateAccessor | YSON (dict) | ctx.state(name, msg) |
Serializes a Python dict to YSON |
| RawStateAccessor | bytes |
ctx.raw_state(name, msg) |
Raw bytes without serialization |
| ProtoStateAccessor | Protobuf | ctx.proto_state(name, msg, ProtoClass) |
Serializes using Protobuf |
| ExternalStateAccessor | Payload (table row) | ctx.external_state("/name", msg) |
Typed access to an external table |
The first three accessors work with internal state (tables are automatically managed by Flow). ExternalStateAccessor works with external state (you create the table yourself).
Common API
All internal accessors (YsonStateAccessor, RawStateAccessor, ProtoStateAccessor) provide the same set of methods:
| Method | Description |
|---|---|
get() |
Get the state value (or None if the state doesn’t exist) |
set(value) |
Set the state value |
clear() |
Delete the state for the current key |
get_or_default(default) |
Get the value or return default |
Getting an accessor
You get an accessor through RuntimeContext (ctx) inside on_message or on_timer:
class MyFunction(RowFunction):
def on_message(self, message, output, ctx):
# YSON (dict)
yson_state = ctx.state("state-name", message)
# Raw bytes
raw_state = ctx.raw_state("state-name", message)
# Protobuf
proto_state = ctx.proto_state("state-name", message, MyProtoClass)
# External (the name must start with "/")
ext_state = ctx.external_state("/state-name", message)
def on_timer(self, timer, output, ctx):
# Similarly, but pass timer instead of message
state = ctx.state("state-name", timer)
Parameters:
name— a string with the state name declared in the static spec. For internal states, this is an arbitrary string frominternal_states; for external states, it’s a key fromexternal_state_managersthat must start with/.message/timer— the message or timer for which you need to get the state for the key.ProtoClass(only forproto_state) — the Protobuf message class for deserialization.
When to use which type
| Situation | Recommended accessor |
|---|---|
| A simple dictionary with several fields | ctx.state() (YSON) |
| Arbitrary binary data | ctx.raw_state() (Raw) |
| Structured data with a fixed schema | ctx.proto_state() (Protobuf) |
| Data that needs to be accessed from other systems | ctx.external_state("/name", msg) (External) |
| Data that requires a custom table | ctx.external_state("/name", msg) (External) |
See also
- Internal State (Python)
- External State (Python)
- Working with states (Python) — a brief overview of all types
- Stateful processing (concept)
- StateAccessor (Java)