Filters – Project Haystack

Filters

OverviewUsageNumber ComparisonsArrow OperatorRef ListsGrammar

Overview

Filters are a simple declarative language used to query Haystack data. A filter is a predicate function that takes a dict and returns true/false (match/no match). Some filter constructs require the use of defs in which case the filter must be evaluated in the context of a namespace.

Usage

The simplest filter is just a tag name that matches any record that contains that tag (regardless of its value):

site  // query any record with the "site" tag

To match a tag value you can use any of the equality or comparison operators:

geoPostalCode == "23220"   // equal to
geoPostalCode != "23220"   // not equal to
curVal < 75                // less than
curVal <= 75               // less than or equal to
curVal > 75                // greater than
curVal >= 75               // greater than or equal to

The scalars to compare against are encoded using Zinc encoding (with a couple of exceptions noted below).

You can combine filters using and, or, or not:

site or equip             // has site or equip tag
equip and hvac            // has equip and hvac tag
equip and not ahu         // has equip tag, but not the ahu tag

You can also use a Xeto spec name to match by nominal typing:

Meter
ph::Meter
ph.points::OutsideAirTempSensor

Number Comparisons

Equality and comparison operators for Numbers require an exact unit match, otherwise the operator evaluates to false. Even if the units measure the same quantity, no conversion should be performed. Here are examples:

75 == 75        // true
75°F == 75°F    // true
75°F == 75      // false
75°F == 75°C    // false
1min == 60sec   // false

123 != 123      // false
123 != 123°F    // true
123°C != 123°F  // true
1min != 60sec   // true

5 > 4           // true
5 > 4°F         // false
5°C > 4°F       // false

Arrow Operator

You use the -> operator to dereference a tag that has a Ref value. For example, if your equip rec has a siteRef tag that references the site, you can query for equip in a given city such as:

equip and siteRef->geoCity == "Chicago"

The filter above will match if the following hold true:

  • it has equip tag
  • and it has a siteRef tag that is a Ref
  • and what the siteRef tag points to has the geoCity tag
  • and that the site's geoCity tag is equal to "Chicago"

The arrow operator may also be used if the tag value is a nested Dict.

Ref Lists

Haystack allows a list of refs to be used for relationships where a single ref might be used. When a tag value is configured as a list of refs, then a filter will match if any one of the refs in the list match.

Consider an example with a VAV that has an airRef configured as a list of two refs:

// records
id:@ahu1, dis:"AHU-1", ahu, equip
id:@ahu2, dis:"AHU-2", ahu, equip
id:@vav, airRef:[@ahu1, @ahu2], vav, equip

// all of these filters will match the VAV record
airRef == @ahu1
airRef == @ahu2
airRef->dis == "AHU-1"
airRef->dis == "AHU-2"

Note that pathing through a list of refs using "->" will check the path on each ref iteratively.

This technique should never be used for the fundamental containment tags siteRef, equipRef, or spaceRef.

Grammar

The formal grammar of the filter langauge:

<filter>     :=  <condOr>
<condOr>     :=  <condAnd> ("or" <condAnd>)*
<condAnd>    :=  <term> ("and" <term>)*
<term>       :=  <parens> | <has> | <missing> | <cmp> | <isSpec>
<parens>     :=  "(" <filter> ")"
<has>        :=  <path>
<missing>    :=  "not" <path>
<cmp>        :=  <path> <cmpOp> <val>
<cmpOp>      :=  "==" | "!=" | "<" | "<=" | ">" | ">="
<isSpec>     :=  [<specLib> "::"] <specName>
<specLib>    :=  <name> ("." <name>)*
<specType>   :=
<path>       :=  <name> ("->" <name>)*

<val>        :=  <bool> | <ref> | <str> | <uri> |
                 <number> | <date> | <time>
<bool>       := "true" or "false"
<number>     := same as Zinc (keywords not supported INF, -INF, NaN)
<ref>        := same as Zinc
<symbol>     := same as Zinc
<str>        := same as Zinc
<uri>        := same as Zinc
<date>       := same as Zinc
<time>       := same as Zinc
<name>       := same as Zinc <id>
<specName>   := <alphaHi> (<alphaLo> | <alphaHi> | <digit> | '_')*

See Zinc grammar for productions reused from Zinc. Bools are encoded as "true" or "false" (Zinc encodes as "T" or "F").