Bilješka
Pristup ovoj stranici zahtijeva provjeru vjerodostojnosti. Možete pokušati da se prijavite ili promijenite direktorije.
Pristup ovoj stranici zahtijeva provjeru vjerodostojnosti. Možete pokušati promijeniti direktorije.
Sometimes the incoming message doesn't contain everything you need. A temperature reading might arrive with a device ID, but the display name, location, and calibration offset live in a separate lookup table. Enrichment lets you pull that external data into your transform rules.
For an overview of data flow graphs, see Data flow graphs overview.
Transforms use an expression language to compute values, test conditions, and reference fields. Expressions refer to inputs by position, not by name: the first input in the inputs list is $1, the second is $2, and so on. Built-in functions such as cToF convert and manipulate those values.
For the complete list of operators, functions, data types, and metadata fields, see the Expressions reference.
Enrichment is optional, and it's a separate feature from the datasets you might define on an asset. In data flow graphs, a dataset always means a contextualization dataset that's read from the state store. If your messages already contain the fields you need, you don't need to configure datasets at all.
Enrichment works with map, filter, and branch transforms, and with trigger rules in window transforms for version 1.1 or later.
Prerequisites
- An instance of Azure IoT Operations deployed in a Kubernetes cluster. For more information, see Deploy Azure IoT Operations.
- Deployment automatically creates a default registry endpoint named
defaultthat points tomcr.microsoft.com.
The Azure CLI examples in this article use environment variables so that you can set each value once and then copy and paste the commands as-is. If you're using the Azure IoT Operations Codespaces environment from the quickstart, these variables are already set for you and you can skip this step. Otherwise, set the following environment variables in your shell before you run the commands.
The following scripts set the most commonly used environment variables:
| Environment variable | Description |
|---|---|
SUBSCRIPTION_ID |
The ID of the subscription that contains your Azure IoT Operations instance. |
RESOURCE_GROUP |
The name of the resource group that contains your Azure IoT Operations instance. |
AIO_INSTANCE_NAME |
The name of your Azure IoT Operations instance. To list your instances, run az iot ops list -o table. |
CLUSTER_NAME |
The name of the Azure Arc-enabled Kubernetes cluster that hosts your instance. |
LOCATION |
The Azure region to use for new resources, for example eastus. |
SUBSCRIPTION_ID=<subscription-id>
RESOURCE_GROUP=<resource-group-name>
AIO_INSTANCE_NAME=<instance-name>
CLUSTER_NAME=<cluster-name>
LOCATION=<region>
You only need to set the variables that this article uses. This article might use additional environment variables for resource names that you choose. The article explains how to set them where they're introduced.
Set up the state store
The runtime reads dataset records from the Azure IoT Operations distributed state store. Each dataset key maps to one or more records in NDJSON format (one JSON object per line). The runtime caches records and receives change notifications, so state store updates take effect during processing.
For information on configuring the distributed state store, see State store overview.
Populate the state store key
The state store isn't prepopulated. Write dataset records to it over MQTT by using the state store's SET command. For the device-metadata as device dataset configured later in this article, publish the following request to seed two NDJSON records (one per line) under the device-metadata key. Include every field referenced by rules that use this dataset, including location. The Deploy a data flow graph with enrichment example uses location later in this article. Otherwise, the field resolves to null for every message:
mosquitto_pub -h <BROKER_HOST> -p <BROKER_PORT> -V mqttv5 -q 1 \
-t 'statestore/v1/FA9AE35F-2F64-47CD-9BFF-08E2B32A0FE8/command/invoke' \
-D publish response-topic 'clients/dataflow-docs-client/services/statestore/_any_/command/invoke/response' \
-D publish correlation-data '1' \
-D publish user-property __ts "$(date +%s%3N):0:dataflow-docs-client" \
-m $'*3\r\n$3\r\nSET\r\n$15\r\ndevice-metadata\r\n$153\r\n{"deviceId":"dev-001","displayName":"Line 1 Sensor","location":"Building A"}\n{"deviceId":"dev-002","displayName":"Line 2 Sensor","location":"Building B"}\r\n'
The $15 and $153 values are the byte lengths of the key (device-metadata) and value that follow. A successful SET responds with +OK on the response topic. For the full request format, required MQTT v5 properties, and response codes, see the state store protocol reference.
Configure a dataset
Define datasets in the datasets array at the top level of your rules configuration for map, filter, and branch transforms.
For window transforms (version 1.1 or later), configure datasets inside the triggers configuration. For details, see Aggregate data with window transforms in data flow graphs.
In the transform configuration, add a dataset. Configure:
| Setting | Description |
|---|---|
| State store key | The key where dataset records are stored. Use as to assign an alias (for example, device-metadata as device). |
| Match inputs | Fields to compare: one from the source message ($source.<field>) and one from the dataset ($context.<field>). |
| Match expression | A boolean expression (for example, $1 == $2). |
Each dataset entry has these properties:
| Property | Required | Description |
|---|---|---|
key |
Yes | The state store key where the dataset records are stored. Supports an optional alias with the as keyword. To populate this key, publish a SET request over MQTT (see Populate the state store key). |
dynamicValues |
No | List of message field paths substituted into $N placeholders in key, letting the runtime derive the state store key for each message. See Dynamic keys. |
inputs |
Yes | List of field references used in the match expression. Each entry uses a $source. or $context. prefix. |
expression |
Yes | A boolean expression that determines which dataset record matches the incoming message. |
Key and alias
The key value is the state store key that the runtime reads. Assign a shorter alias by using the as keyword. For example, datasets.parag10.rule42 as position lets you reference fields as $context(position).WorkingHours.
A key can also be a template that the runtime resolves separately for each message. For more information, see Dynamic keys.
Dynamic keys
A static key works well when you enrich every message from the same state store record. But sometimes each message needs a different record. For example, with per-device calibration data, the record to look up depends on a field in the incoming message.
Instead of deploying a separate dataset (and a separate graph) for every possible lookup value, make key a template with $1, $2, and so on, placeholders. Add a dynamicValues property that lists the message field to substitute for each placeholder. The runtime resolves the template for every message before it queries the state store.
Tip
Pair a dynamic key with an alias by using as. The alias, not the resolved key, is the fixed name you reference in rules as $context(<alias>).<field>. Keep the alias a stable identifier even though the underlying key changes per message.
Prerequisite: Populate a dynamic state store key
Because the resolved key is data-driven, you need to populate the state store with a record for each resolved value you expect to look up. In the example in the following section, for a message with sensorId: "TEMP-42", the runtime looks up calibration:TEMP-42, so publish a SET request for that exact key. The record must include every field used by the dataset's match inputs (here, sensorId, compared against the incoming message's $source.sensorId), in addition to any field the rules enrich with, such as offset. Otherwise, the match never succeeds and the enrichment fields stay unavailable:
mosquitto_pub -h <BROKER_HOST> -p <BROKER_PORT> -V mqttv5 -q 1 \
-t 'statestore/v1/FA9AE35F-2F64-47CD-9BFF-08E2B32A0FE8/command/invoke' \
-D publish response-topic 'clients/dataflow-docs-client/services/statestore/_any_/command/invoke/response' \
-D publish correlation-data '1' \
-D publish user-property __ts "$(date +%s%3N):0:dataflow-docs-client" \
-m $'*3\r\n$3\r\nSET\r\n$19\r\ncalibration:TEMP-42\r\n$33\r\n{"sensorId":"TEMP-42","offset":5}\r\n'
The $19 and $33 values are the byte lengths of the key (calibration:TEMP-42) and value that follow. A successful SET responds with +OK on the response topic. For the full request format, required MQTT v5 properties, and response codes, see the state store protocol reference.
Configure a dataset with dynamic values
In the transform configuration, add a dataset and configure:
| Setting | Description |
|---|---|
| State store key | A template such as calibration:$1 as calibration, where a message field replaces $1 at processing time. To populate the resolved key, publish a SET request over MQTT (see Populate a dynamic state store key). |
| Dynamic values | The message field to substitute for each placeholder, in order (for example, sensorId). |
| Match inputs / Match expression | Configure the same way as a static-key dataset. |
For a message with sensorId: "TEMP-42", the runtime resolves the template to calibration:TEMP-42 before querying the state store. The matched record's offset field becomes available as $context(calibration).offset.
Default values for missing fields
Each entry in dynamicValues can include a ?? default, used when the message field is missing or null. Without a default, a missing or null field fails processing for that message.
{
"key": "calibration:$1 as calibration",
"dynamicValues": ["sensorId ?? \"unknown\""]
}
Escaping a literal $
If the state store keys in your system already contain a literal $ character, escape it as $$ in the template. Only $N (a $ followed by digits) is treated as a placeholder. $$ always produces a single literal $.
{
"key": "rate:$$USD:$1",
"dynamicValues": ["region ?? \"us\""]
}
For a message with region: "eu", this resolves to rate:$USD:eu.
Composite keys
A template can reference more than one message field. Each $N maps to the corresponding entry in dynamicValues, in order:
{
"key": "line:$1:station:$2 as lineStatus",
"dynamicValues": ["lineId ?? \"unknown\"", "stationId ?? \"0\""]
}
For a message with lineId: "L-3" and stationId: "7", this resolves to line:L-3:station:7.
Note
Only string, number, and boolean message fields can be substituted into a key. Object and array fields aren't supported as dynamic key values. Using one results in an error when the message is processed.
Important
The following errors are validated when the graph is applied, not when messages are processed:
- A
$Nplaceholder whose index is greater than the number of entries indynamicValues. - A
dynamicValueslist configured on akeythat contains no unescaped$Nplaceholder. - A malformed placeholder, such as
$0or a$not followed by a digit.
Fix these errors before applying the graph. They don't surface later as message-processing failures.
Because the resolved key is data-driven, it can be different for every message. If you enable diagnostic logging or tracing for enrichment lookups, expect to see the resolved key (for example, calibration:TEMP-42), not the configured template.
Dataset inputs
Each entry in the inputs array uses a prefix to indicate where the value comes from:
$source.<field>: reads from the incoming message.$context.<field>: reads from the dataset record being evaluated.
Inputs can appear in any order and you can mix $source and $context references freely. Wildcard inputs aren't supported in dataset definitions.
Match expression
The expression evaluates to a boolean. The runtime loads the dataset from the state store as NDJSON (one JSON object per line), iterates through the records, and returns the first record where the expression evaluates to true.
If no record matches, the enrichment fields aren't available. Rules that depend on them still run, but they write their output field with a null value instead of failing the message. The rule isn't removed from the output, only its resolved value is null.
Use enriched data in rules
Reference matched record fields in any rule's inputs array by using $context(<alias>).<fieldPath>.
Map example
Add map rules that reference enriched fields:
| Input | Output |
|---|---|
$context(position).WorkingHours |
WorkingHours |
rawValue and $context(product).multiplier |
adjustedValue (expression: $1 * $2) |
Filter example
Add a filter rule with inputs rawValue, $context(limits).multiplier, and $context(limits).baseLimit, and expression $1 * $2 > $3.
Branch example
Configure a branch rule with inputs quantity, $context(mult).factor, and $context(mult).threshold, and expression $1 * $2 > $3.
Wildcards with datasets
In map rules, use $context(<alias>).* to copy all top-level fields from the matched dataset record:
Add a map rule with input $context(device).* and output *.
Wildcards can also target a nested object within the dataset record. For example, $context(device).configuration.* copies only the fields under configuration.
Only map rules support wildcard enrichment inputs. Filter and branch rules don't support wildcard inputs.
Deploy a data flow graph with enrichment
In the Operations experience, create a data flow graph with enrichment:
- Add a source that reads from your MQTT topic.
- Add a map transform. In the dataset configuration, add a dataset with the state store key and match condition.
- In the map rules, reference enriched fields by using
$context(<alias>).<field>syntax. - Add a destination that sends to your output topic.
Enrichment limitations
- Window support is trigger-only. In window transforms, dataset enrichment is available for trigger rules (
triggers.datasets) inazureiotoperations/graph-dataflow-window:1.1.0or later, not for accumulation rules. - First match wins. The runtime uses the first record where the expression evaluates to
true. - Missing matches don't fail the message. If no dataset record matches, rules that reference
$context(<alias>)fields still run but resolve tonull. The output field is present with anullvalue, not omitted. The transformation doesn't fail. - State store errors propagate. If the state store is unreachable, the transformation fails for that message.
- No wildcard inputs in dataset definitions. Each input must be a specific
$source.<field>or$context.<field>reference.