AllShortestPaths
Selects every shortest matching path per group. Built by PathPattern.all_shortest.
Methods
.per()
AllShortestPaths.per(*args: Value) -> AllShortestPathsGroup the matching paths.
AllShortestPaths.paths and AllShortestPaths.count return and count (respectively) paths that have
the shortest length, where shortest is determined per group - this call defines
the groups. Required before .count() or .paths().
Currently the only supported grouping is the pattern’s endpoint pair,
.per(initial_node, final_node) with the pattern’s initial and final
endpoint identifiers in that order; any other grouping raises.
Returns:
AllShortestPaths- This selector (self), to allow chaining.paths()or.count().
Raises:
relationalai.util.error.RAIException-PathPerAppliedTwiceErrorif.per(...)has already been applied to this selector.
.paths()
AllShortestPaths.paths() -> DerivedColumnReturn every shortest PathTraversal per group.
For each group (see AllShortestPaths.per) containing at least one matching path, yields
every matching path of that group’s minimum length. A group whose minimum
length is reached by several paths yields all of them, whereas
AnyShortestPath.paths yields one per group.
Returns:
DerivedColumn-PathTraversalvalues, one per shortest path. Use it insideModel.where/Model.select, and read the per-path details (length,nodes,relationships,relationship_fields) via the correspondingPathTraversalproperties.
Raises:
relationalai.util.error.RAIException-PathSelectorPerErrorif.per(...)is missing or not yet supported. Currently, the only supported grouping is the pattern’s endpoint pair,.per(initial_node, final_node)with the pattern’s initial and final endpoint identifiers in that order; any other grouping raises.
Examples:
reached_person = Person.ref()p = ( m.path(Person.follows.repeat(1, 5), reached_person) .where(Person.name == "Alice") .all_shortest() .per(Person, reached_person) .paths())m.where(p).select(p, p.length, reached_person.name)Notes:
Only the path’s endpoint identifiers unify with the enclosing scope. Filters on
interior nodes must be attached with PathPattern.where on the pattern;
a filter referencing interior nodes placed in an enclosing
Model.where cannot be routed into the path and
raises.
Performance: Unlike AnyShortestPath.paths, the number of results is
not bounded by the number of groups. A group can have exponentially many
shortest paths in the size of the graph, and every one of them is enumerated.
Use AllShortestPaths.count first to check how many there are; it runs in time polynomial
in the size of the graph, even if the counts grow exponentially.
.count()
AllShortestPaths.count() -> AggregateReturn the number of paths that are shortest within their group.
The returned object acts like any other PyRel sum or count aggregate. When
used bare, it has an implied empty .per(), so returns the single global count
of selected paths, exactly like a bare count(x) aggregates globally. Group the
count by applying .per(...) to the result with the endpoint identifiers:
.per(initial_node, final_node) counts per connected pair,
.per(final_node) counts per final node, and so on.
Returns:
Aggregate- The Integer count, usable insideModel.where/Model.select, grouped by an optional.per(...)at the use site.
Raises:
-
relationalai.util.error.RAIException-PathSelectorPerErrorif.per(...)is missing or not yet supported. Currently, the only supported grouping is the pattern’s endpoint pair,.per(initial_node, final_node)with the pattern’s initial and final endpoint identifiers in that order; any other grouping raises.PathNonDeterminismErrorif the pattern is ambiguous. Counting requires the pattern to be deterministic, i.e., there is only one way to match each path. An ambiguous pattern likepath(x.follows.repeat(0, 1), y.follows.repeat(0, 1), z), wherexandyare Refs of the same Concept, raises when used with this method.
Examples:
Define the count of shortest paths from each criminal to each suspect. Suppose
the below pattern path(Criminal.works_with.repeat(1, 5), suspect) matches:
- 3 paths of length 1 from Alice to Bob
- 2 paths of length 2 from Alice to Bob
- 1 path of length 3 from Alice to Charlie
The length-2 paths will be excluded from
shortest_counts, because there are shorter paths in the group (Alice, Bob).
suspect = Person.ref()shortest_counts = ( m.path(Criminal.works_with.repeat(1, 5), suspect) .all_shortest() .per(Criminal, suspect) .count())Select the number of shortest paths, grouped by both path endpoints, assuming that Alice is the only Criminal in the model:
m.select(Criminal.name, suspect.name, shortest_counts.per(Criminal, suspect)).inspect()# name name_2 sum# 0 Alice Alice <NA># 1 Alice Bob 3# 2 Alice Charlie 1Select the total number of shortest paths:
m.select(shortest_counts).inspect()# sum# 0 4Select the number of shortest paths, grouped by the initial node:
m.select(Criminal.name, shortest_counts.per(Criminal)).inspect()# name sum# 0 Alice 4Select the number of shortest paths, grouped by the final node:
m.select(suspect.name, shortest_counts.per(suspect) | 0).inspect()# name v0# 0 Alice 0# 1 Bob 3# 2 Charlie 1Select the suspects with 2 or more shortest paths from a Criminal:
m.where(shortest_counts.per(suspect) >= 2).select(suspect.name).inspect()# name# 0 BobNotes:
Only the path’s endpoint identifiers unify with the enclosing scope. Filters on
interior nodes must be attached with PathPattern.where on the pattern;
a filter referencing interior nodes placed in an enclosing
Model.where cannot be routed into the path and
raises.
The count’s per (.count().per()) is distinct from the selector’s .per
(path(...).all_shortest().per().count()): the selector’s .per groups
the selection (which paths count as shortest), while the count’s .per
groups the count of those paths.
A group with no selected paths gets no count. If you select the group’s keys
together with the count, its count shows as empty, not 0. Use | 0 to get a
0 instead.
Performance: The paths are counted without being enumerated: computing the counts is polynomial in the size of the graph, even when the number of shortest paths is exponential.