Advanced: ALONG, FOLD, BEST BY¶
ALONG (Path-Carried Values)¶
ALONG carries state through recursive expansion.
CREATE RULE shortest AS
MATCH (a)-[e:EDGE]->(b)
ALONG dist = prev.dist + e.weight
YIELD KEY a, KEY b, dist
Use prev.<field> to reference prior recursive step values.
FOLD (Aggregation)¶
FOLD aggregates rule outputs after derivation.
Standard Aggregators¶
Standard aggregators work in non-recursive strata only. They can decrease between iterations, which violates fixpoint requirements:
| Operator | Description | Example |
|---|---|---|
COUNT(*) |
Row count | FOLD n = COUNT(*) |
COUNT(expr) |
Non-null count | FOLD n = COUNT(b.value) |
SUM(expr) |
Sum | FOLD total = SUM(b.amount) |
AVG(expr) |
Average | FOLD avg = AVG(b.score) |
MIN(expr) |
Minimum | FOLD low = MIN(b.price) |
MAX(expr) |
Maximum | FOLD high = MAX(b.price) |
COLLECT(expr) |
Collect into list | FOLD paths = COLLECT(b.name) |
Monotonic Aggregators (Safe in Recursion)¶
Monotonic variants guarantee the aggregate never decreases between iterations, enabling safe use inside recursive strata:
| Operator | Formula | Identity | Use When |
|---|---|---|---|
MSUM(expr) |
Running sum | 0 |
Non-negative additive accumulation |
MMAX(expr) |
Running maximum | −∞ |
Worst-case / dominant value |
MMIN(expr) |
Running minimum | +∞ |
Best-case / bottleneck |
MCOUNT(expr) |
Running count | 0 |
Monotonically growing count |
MNOR(expr) |
1 − ∏(1 − pᵢ) |
0.0 |
Independent OR-causes (probabilities) |
MPROD(expr) |
∏ pᵢ |
1.0 |
Independent AND-conditions (probabilities) |
Monotonic Probabilistic Folds¶
For probability domains, use MNOR (noisy-OR) and MPROD (product):
CREATE RULE failure_risk AS
MATCH (c:Component)-[:HAS_SIGNAL]->(s:QualitySignal)
FOLD risk = MNOR(1.0 - s.pass_rate)
YIELD KEY c, risk
See Probabilistic Logic for full documentation.
Multiple FOLD Clauses¶
A rule can have multiple FOLD clauses to compute several aggregates simultaneously:
CREATE RULE exposure AS
MATCH (a:Account)-[t:TRANSFER*]->(b:Account)
WHERE b IS suspicious
FOLD total = MSUM(t.amount)
FOLD path_count = MCOUNT(*)
YIELD KEY a, total, path_count
Post-FOLD WHERE (HAVING)¶
A WHERE clause after FOLD filters aggregated groups — equivalent to SQL's HAVING. Only rows where the condition holds are kept.
CREATE RULE frequent_payer AS
MATCH (p:Person)-[r:PAID]->(i:Invoice)
FOLD n = COUNT(*)
WHERE n >= 3
YIELD KEY p, n
This yields only people who made 3 or more payments. The WHERE n >= 3 runs after FOLD computes the count.
Multiple Conditions¶
Combine conditions with AND:
CREATE RULE big_spenders AS
MATCH (p:Person)-[r:PAID]->(i:Invoice)
FOLD n = COUNT(*), total = SUM(r.amount)
WHERE n >= 2 AND total >= 1000
YIELD KEY p, n, total
Available Columns¶
Post-FOLD WHERE can reference:
- FOLD output columns (n, total in the examples above)
- KEY columns (the grouped-by entities)
It cannot reference pre-aggregation columns that were consumed by FOLD.
Relationship to QUERY WHERE¶
Post-FOLD WHERE filters during rule evaluation. QUERY ... WHERE filters after:
-- Filter inside the rule (during FOLD):
CREATE RULE counts AS
MATCH (e:Ev) FOLD n = COUNT(*)
WHERE n >= 3
YIELD KEY e.action, n
-- Filter outside (at query time):
QUERY counts WHERE n >= 5 RETURN *
Both are valid. Use post-FOLD WHERE when the filter is intrinsic to the rule's semantics. Use QUERY WHERE for ad-hoc filtering at call sites.
BEST BY (Witness Selection)¶
BEST BY picks the best candidate row by ordering expression.
CREATE RULE cheapest AS
MATCH (a)-[e:EDGE]->(b)
ALONG cost = prev.cost + e.weight
BEST BY cost ASC
YIELD KEY a, KEY b, cost
Using similar_to in ALONG and BEST BY¶
The similar_to() expression function works in ALONG accumulators and BEST BY selectors, enabling semantic similarity scoring along recursive paths.
Semantic Relevance Along Paths¶
CREATE RULE semantic_path AS
MATCH (a:Document)-[:LINKS_TO]->(b:Document)
ALONG relevance = prev.relevance * similar_to(b.embedding, $query)
YIELD KEY a, KEY b, relevance
Best Semantically Similar Path¶
CREATE RULE best_match AS
MATCH (a:Topic)-[:RELATED]->(b:Topic)
ALONG score = prev.score + similar_to(b.embedding, $query)
BEST BY score DESC
YIELD KEY a, KEY b, score
Hybrid Scoring in Rules¶
CREATE RULE hybrid_relevant AS
MATCH (q:Query)-[:SEARCHES]->(d:Document)
WHERE similar_to([d.embedding, d.content], q.text,
{method: 'weighted', weights: [0.7, 0.3]}) > 0.5
YIELD KEY q, KEY d
See the Vector Search guide for full similar_to documentation.
Practical Guidance¶
- Use
ALONGfor accumulators (distance, risk, confidence, similarity). - Use
FOLDwhen you need grouped summaries. - Use post-FOLD
WHEREto discard groups that don't meet a threshold (e.g.,WHERE count >= 3). - Use
BEST BYwhen you need one witness path, not all candidates.