I’m looking for methods (any kind of combinations of algorithms & corresponding data structures) that can be used as a generic matching engine in case of arbitrary message/event types. Let me formalize the problem a bit:

Let $C$ denote a condition type consisting of an arbitrary data type (numeric values/strings/dates/enumerations/ranges/etc.)
and a compatible comparison operator: $C = (text{Type}, text{Operator})$. For
instance, in the case of numeric values, $C_1 = (text{Integer},
<=)$, or for strings $C_2 = (text{String}, text{Contains})$.

The condition types can be instantiated with an actual reference value of the
condition’s underlying data type, for instance: $c_1 =
(text{Integer} = 5, <=)$ or $c_2 = (text{String} = text{“xy”},
text{Contains})$.

Obviously, multiple conditions can be combined which requires the
definition of a condition set $S = (C_1, C_2, ldots, C_n)$. A
concrete condition set can be e.g.: $s = ((text{Real} = 3.14, >),
(text{String} = text{“abc”}, text{!=}))$. For simplicity, the
logical connection between the conditions of a set is always
$text{AND}$ (so in order for a set to be a match for an event, all
the conditions of $s$ must be met).

Finally, multiple such condition sets can coexist which we can
visualize like the rows of a data table: $t = {s_1, s_2, ldots,
s_m}$.
The use case would be that one assigns some operations/actions to the individual condition sets (rows) and executes only the operations whose conditions matched the properties of the incoming event in realtime (note that this is a difference compared against traditional filtering – we define the conditions first, then we wait for the data, and not the other way around). These properties must be identified in advance and they must correspond to the condition types of the given scenario (e.g., $c_1 = (text{Integer} = 5, <=)$ always uses the API int EventT::get_some_field()
of the event type), however, such implementation details are not relevant from the core algorithmic problem’s point of view.
To sum up: the input of the algorithm (or matching engine) is $(t, e)$ where $e$ is a compatible event, while the output $t’$ is a subset of $t$ (the most complete possible) such that $forall s in t’$ it’s true that all conditions in $s$ matched $e$.
Let’s see a complete example, starting with $t$:
ID 
$C_1$ 
$C_2$ 
1 
$(text{Integer} = 66, =)$ 
$(text{String} = text{“*”}, =)$ 
2 
$(text{Integer} = 50, > text{(greater than)})$ 
$(text{String} = text{“abc”}, text{!=})$ 
A wildcard (see the first value in the $C_2$ column) basically means that we won’t utilize the 2nd condition (any string will match).
And now a couple of events:
 $e_1 = (35, text{“xy”})$ – won’t match any of the 2 condition sets,
 $e_2 = (66, text{“abc”})$ – will match only the 1st set,
 $e_3 = (77, text{“def”})$ – will match only the 2nd set,
 $e_4 = (66, text{“xy”})$ – will match both sets,
 $e_5 = (88, text{“abc”})$ – won’t match any of the 2 condition sets.
One possible way I can think of to implement this engine are trees: the levels of the tree represent the condition types (and on a particular level there are as many nodes as the number of rows in $t$), while the nodes the actual conditions, and whenever the conditions of all the nodes through a path in the tree till a leaf node (including the leaf node) are met, we have a match.
Other approaches are welcome, still, I’d appreciate concrete, possibly opensource implementations (with optimized/efficient underlying algorithms) even more. If there is a treebased solution out somewhere, I’d be happy to take a look at it, too.