The rules processing engine takes a graph of elements. The elements are connected by typed streams. The element type can be:
There are nine defined element types. Two of them are paramterised on another type, the triple pattern: a triple pattern P is a triple where some (possibly zero) of the components have been replaced by named variables.
The notation
[StreamTypein*]Element[StreamTypeout*]
describes an element with input inputs typed by in and output
elements typed by out.
[Bind(B)]subst(P)[Triple]
- the names appearing in
P
must be a subset of the names bound in B
.
Each input binding produces an output triple with the names in
P
replaced by their values from B
.
[Triple]match(P)[Bind(B)]
- the names appearing in
B
must be a subset of those appearing in P
.
Each input triple produces an output binding with all the names in
P
bound to the corresponding element of the triple.
[Bind(Bin)]filter(F(X))[Bind(Bout)]
-
the names in Bin
and Bout
must be the same. (See DROP below.) F
is a predicate
over tuples of values, and X
is a tuple of names; every name
in X
must be bound in Bin
. Each input
binding is validated by applying F
to the tuple of values
obtained by replacing the names in X
with their values from
Bin
. Valid bindings are sent to the output;
invalid bindings are discarded.
[Bind(BL),Bind(BR)]join[Bind(Bout)]
-
The names in Bout
must be the union of the names
in BL
and BR
. Each input
binding L
(R
) generates as output every
consistent union of L
(R
) with all the
previous bindings of R
(L
). (A consistent union
is one in which any variable bound in both the operands is bound to the same
value.)
join
element consumes store; in
general, every binding that arrives must be preserved so that it may
generate new bindings for arrivals on the other input stream.
[Bind(T), Bind(U), Poke]unless[Bind(T)]
- this element
generates no output until a Poke
signal arrives. Then
all bindings T
that have arrived or will arrive are
delivered to the output unless a binding U
arrived
which is a subset of T
.
unless
element consumes
store for every U
, and for every T
that
arrives before the Poke
.
[Bind(X)]ignore
- any bindings that arrive on the input
are discarded.
ignore
makes explict the points where bindings can be
disposed of.
[Sin]fork[Sout*]
- fork
copies its input stream (which may be of any type) to all of its output
streams (which are all of the same type as the input).
[Bind(X), Poke]aggregate(A, Y)[Bind(X), Bind(A)]
-
the names Y
must be a subset of the names bound in
X
. aggregate
copies its input bindings
X
to its X
output. When the
Poke
signal arrives, it outputs down it's A
output a single aggregate value binding A to a collection of
bindings for the subset of X
extracted by Y
.
X
output is not required, in which case
it can be eaten by an ignore
element.
X
must all be stored until the Poke
signal arrives.
[Bind(X), Poke]summarise[H(Y), Bind(X), Bind(Y)]
-
summarise
copies its X
input to its
X
output. When the Poke
signal arrives,
it outputs a summary of all the bindings X
to its Y
stream. The summary is defined by H
and should require much less state than remembering all the X
's.
H
options includes at least
count
,
min
,
max
,
mean
,
sum
,
product
.
summarise
exists to make explicit some obvious optimisations
of aggregation.
[Bind(B)]distinct[Bind(B)]
- each input B
generates an output of that same B
unless such a B
has already been output: duplicates are eliminated.
B
that arrives must be recorded.
[Bind(B)]drop(X)[Bind(B')]
- B'
must be a
subset of B
, and the names X
must all appear
in B
. Each binding B
that arrives generates a
B'
which is B
with all the bindings for names
in X
removed.
drop
makes explicit the points where bindings become
irrelevant.