Matchers
Matchers
Matchers provide a way to match an event to a set of criteria:
The matching criteria may be defined via:
- A set of key-value expressions
- A template that evaluates to a true/false equivalent
{ "burgers-nearby": { "name": "burger$", "rssi": ">-50" }, "burgers-nearby-template": "{{ and (mustRegexMatch \"burger$\" .name) (gt .rssi -50) }}" }
The burgers-nearby
matcher is defined with a set of key-value expressions, while the burgers-nearby-template
matcher is defined with a template.
Either matcher will match an event with following criteria:
- Contains key
rssi
with a value greater than-50
- Contains key
name
with a value ending inburger
Defining Matchers
Matcher Templates
A matcher template is a text template that that evaluates to a true/false equivalent value (1
/t
/T
/true
/True
or 0
/f
/F
/false
/False
).
All template functions in Edge Connect are available for use in the matcher template.
If no true/false equivalent value is built by the template, an error is returned, and the event is not matched.
Matcher Key-Value Expressions
Defining Matcher Keys
Matcher keys are defined with dot notation and/or templating.
Dot Notation
This matcher uses dot notation
{ "is-gouda-burger": { "burger.cheese":"^gouda$" } }
to match this event
{ "burger": { "cheese": "gouda", "patty": "beef, 80% lean" } }
Templating
This matcher uses templating and dot notation in the key
{ "is-food-with-cheese": { "{{ .foodType }}.cheese": "" } }
to match this event
{ "foodType": "burrito" "burrito": { "cheese": "gouda", "meat": "carnitas" } }
Matcher Values
All Matcher values must be a string
. No other input types are valid.
The following value types supported by Matchers:
- Existence
- Numeric (all
int
/uint
/float
types,byte
) - String
- Bytearrays/
ble.UUID
- Boolean
- Arrays (limited support for []interface{}, []ble.UUID])
Text templating in the value is supported. For example, to match someKey
greater than someDynamicValue
in the input event:
{ "greater-than-100": { "someKey": ">{{.someDynamicValue}}" } }
Existence
To check for existence of a key, use the empty string (""
) for the value.
To check if the key cheese
exists:
{
"has-cheese": {
"cheese": ""
}
}
Special Considerations
- To match an empty string, use the regular expression [
"^$"
] where^
marks the beginning of a string and$
marks the end.
Numeric Values
For numeric values the following operators are supported:
Comparison | Operator |
---|---|
Value less than | [<] |
Value greater than | [>] |
Value less than or equal | [<=] |
Value greater than or equal | [>=] |
Value equal | [==] |
Value not equal | [!=] |
For example, to match someKey
greater than 100:
{ "greater-than-100": { "someKey": ">100" } }
Special Considerations
- All comparisons are handled as
float64
regardless of the underlying value type. - The epsilon value is 1e-8 (0.00000001) for equality.
Boolean Values
For bool
values, use any of the following strings to match the desired bool
value:
true
:"true"
,"True"
,"1"
,"t"
,"T"
false
:"false"
,"false"
,"0"
,"f"
,"F"
Strings
To match a string use a regular expression.
If the regular expression fails to compile, the matcher will fallback to a string equality comparison.
For example, this matcher:
{ "is-typical-story-with-sandwiches" : { "story": "^Once upon a time.*[Ss]andwich" } }
Would match this event:
{ "story": "Once upon a time, there was a ham sandwich. The end." }
Special Considerations
- To avoid unexpected matches, use
^
and$
to mark the start/end of the string.
Bytearrays
To match a bytearray
, use a lowercase hexstring regular expression. This also applies to ble.UUID
(used for BLE services)
bytearray | regular expression |
---|---|
[0x12,0xff,0xaa] | [^12ff0a$] |
[0x99, ... ,0x5a] | [^99([0-9a-f]{2})*5a$] |
Special Considerations
- To avoid unexpected matches, use
^
and$
to mark the start/end of thebytearray
. - When matching
ble.UUID
, do not include dashes in the value.
Array Handling
There is limited support for array handling.
[]byte
[]byte
(Byte arrays) are fully supported as seen in Bytearrays.
[]interface{} and []ble.UUID
There is limited support for []interface{}
and []ble.UUID
(ble services).
If event value is of type []interface{}
or []ble.UUID
and ANY item in the array matches the provided matcher value, it is considered a match.
For example, this matcher
{
"is-over-9000" : {
"power-level": ">9000"
}
}
would match this event, despite the two other values in the array failing to match the given value.
{
"power-level": [
123.4,
"negative one million",
9000.1
]
}
Special Considerations
Dynamic Type Handling
Since input types and comparisons are handled dynamically, false matches may occur if unexpected types are in the input event.
The following example applies to boolean types, but this could happen with any type in a similar manner.
Consider this example where we are expecting a boolean value:
{
"is-true":{
"aBoolean": "True"
}
}
"is-true"
matches both of these events:
-
event with a
bool
(as expected):{ "aBoolean": true }
-
event with a
string
(unexpected):{ "aBoolean": "Arnold's best movie is True Lies, not Terminator 2" }
Regular Expressions
Keep in mind that regular expressions are used by default. Entering a regular expression without defining the start/end of the string will likely result unexpected behavior.
Consider this example that tries to match an event that has {"value" : "hamburger"}
:
{ "is-hamburger-bad":{ "value": "hamburger" }, "is-hamburger-good":{ "value": "^hamburger$" } }
is-hamburger-bad
has no explicit start/end for the regular expressionis-hamburger-good
has an explicit start/end for the regular expression
Given these events:
{ "event1" : { "value": "hamburger" }, "event2": { "value": "hamburger helper" } }
"event1"
will be matched by both"is-hamburger-good
" and"is-hamburger-bad"
"event2"
will be matched by"is-hamburger-bad"
since the string starts with"hamburger"
Using Matchers
Matchers can be used in the following places:
- Matcher filter
- Pipeline matchers
- DeviceGroup inclusion matchers
Regardless of the place, the configuration of Matchers is the performed with the following keys.
matchers
defines a list of top-level matchersmatch
defines an inline matcher
All provided Matchers must match the input event to be considered a match.
Matcher Filters
A Matcher filter allows a user to insert matchers anywhere in a pipeline/connection sequence.
In the following example we use matchers to send events to the cloud only if the device's power-level
is over 9000.
{ "matchers": { "is-over-9000": { "power-level": ">9000" } }, "filters" : { "convert-power-level": { "type": "typeConvert", "config" : { "injectKeys": { "power-level": { "source": "mfg" "offset": 2, "length": 4, "type": "uintLE" } } } }, "match-over-9000" : { "type": "matcher", "config" : { "matchers": [ "is-over-9000" ] } }, "publish": { "type": "publish", "config": { "connector": "cloud9000" } }, } "pipelines" : { "publish-over-9000": { "filters": [ "convert-power-level", "match-over-9000", "publish" ] } } }
DeviceGroup Inclusion Matchers
Setting a DeviceGroup inclusion matcher allows dynamically adding devices to a DeviceGroup.
For example, the snippet below would automatically add new devices to the nearby-tacos
DeviceGroup as they are discovered.
{ "matchers": { "is-nearby" : { "rssi": ">-50" }, "is-taco": { "name": "^taco$" } }, "groups" : { "nearby-tacos" : { "matchers": [ "is-nearby", "is-taco" ] } } }
Pipeline Matchers
Setting matchers at the Pipeline level allows processing of only those events which match all the provided matchers in a Pipeline.
Below is a mix of inline and top-level matchers:
{ "matchers": { "is-nearby" : { "rssi": ">-50" }, "is-taco": { "name": "^taco$" } }, "pipelines" : { "nearby-hamburgers" : { "matchers": [ "is-nearby" ], "match": { "name": "^hamburger$" }, "filters": [ "..." ] }, "nearby-tacos" : { "matchers": [ "is-nearby", "is-taco" ], "filters": [ "..." ] } } }
Updated 3 months ago