Evaluation
A TSAL expression is lazy: building it constructs a tree of typed nodes and computes nothing. The
tree is evaluated only when QueryBuilder.solve() runs, which resolves each expression against the
silver-layer data and produces a core-model result per container.
The expression tree
Under the hood, TSAL expressions form a tree of typed nodes:
| Type | Role |
|---|---|
TimeSeriesSelector | Leaf node: selects a physical channel by tag expression. |
TimeSeriesOp | Internal node: arithmetic, comparison, logical, or method-call operation. |
TimeSeriesUDF | User-defined function applied to one or more expressions. |
Operators and signal methods on a TimeSeriesExpression (Defining Expressions)
build TimeSeriesOp nodes around their operands rather than computing anything immediately.
From expression to result
When QueryBuilder.solve() runs, the solver does the following per container:
-
Resolve leaves. Each
TimeSeriesSelectoris matched to a physical channel and loaded into aSampleSeriesfrom the silver-layer data. -
Evaluate bottom-up. Each
TimeSeriesOpcalls the corresponding method/operator on the core-model object its children produced — e.g.eng_rpm > 2000builds aSampleSeriesforeng_rpm, then the>op turns it into anIntervals. The result of the whole tree is one core-model object (or a scalar) per container. -
Serialize into the output DataFrame. Each result type maps to a Spark column type:
Result type Spark column type How it is stored SampleSeriesBinaryTypeserialized (pickle+lz4) IntervalsArrayType(ArrayType(DoubleType))[[tstart, tend], ...]PointsInTimeArrayType(DoubleType)[tstart, ...]PointsInTimeSeriesArrayType(ArrayType(DoubleType))[[tstart, value], ...]scalar DoubleTypethe value
toPandas() deserializes the binary SampleSeries columns back into objects; the array-backed types
are returned as nested lists. See the Core Data Model for the semantics of each
result class, and Query Solvers for the full solver pipeline and the
DefaultSolver that reads the silver layer.