Summary
graph.shortest_path() and graph.weighted_shortest_path() take no edge_types argument, while graph.expand() and graph.traverse() do. There is no way to restrict a shortest path to a subset of relationship types.
graph.shortest_path(
source_table regclass,
source_id text,
target_table regclass,
target_id text,
max_depth int DEFAULT 20,
hydrate boolean DEFAULT true
)
Why it matters
Relationship-typed shortest path is the common shape of the query. "How is this chunk connected to that chunk through shared entities" is a different question from "how is it connected through any edge", and only the first is usually meaningful.
The current workaround is to register and build a second property graph containing only the wanted edge types, then select_graph() before querying. That works, but:
- On a 1.29M node / 3.2M edge graph the restricted build took ~55 s (
build_graph() → nodes_loaded=1288553 edges_loaded=3199812 build_time_ms=54611).
- It produces a second on-disk artifact and a second in-memory projection, so the cost is per relationship-type combination rather than per query.
- With
max_loaded_graphs_per_backend = 1, alternating between the full graph and the restricted graph inside one backend causes unload/reload, so callers need connection pinning to avoid it.
How I hit it
I was comparing shortest_path() against a hand-written recursive CTE on the same tables. My graph had two edge types (m_chunk/m_entity from a junction table, plus has_chunk). Without edge-type restriction the two engines were answering different questions — shortest_path() was routing through has_chunk, producing shorter paths than the MENTIONS-only CTE. Path lengths disagreed on 6 of 6 sampled pairs until I rebuilt a MENTIONS-only graph, after which they matched exactly on all 6.
That is a correctness trap for anyone benchmarking or cross-checking shortest_path() against another engine, since nothing in the signature signals that all edge types participate.
Request
Add edge_types text[] DEFAULT NULL to shortest_path() and weighted_shortest_path(), with the same semantics as in expand()/traverse() (NULL = all types). This would also remove the need for per-type graph registration in the common case.
If restricting inside the CSR traversal is not straightforward, even documenting the current behavior in api-reference.mdx — "all registered edge types participate; register a separate graph to restrict" — would prevent the mismatch above.
Environment
ghcr.io/evokoa/pggraph:1.0.0, PostgreSQL 17.10, linux/arm64.
Summary
graph.shortest_path()andgraph.weighted_shortest_path()take noedge_typesargument, whilegraph.expand()andgraph.traverse()do. There is no way to restrict a shortest path to a subset of relationship types.Why it matters
Relationship-typed shortest path is the common shape of the query. "How is this chunk connected to that chunk through shared entities" is a different question from "how is it connected through any edge", and only the first is usually meaningful.
The current workaround is to register and build a second property graph containing only the wanted edge types, then
select_graph()before querying. That works, but:build_graph()→nodes_loaded=1288553 edges_loaded=3199812 build_time_ms=54611).max_loaded_graphs_per_backend = 1, alternating between the full graph and the restricted graph inside one backend causes unload/reload, so callers need connection pinning to avoid it.How I hit it
I was comparing
shortest_path()against a hand-written recursive CTE on the same tables. My graph had two edge types (m_chunk/m_entityfrom a junction table, plushas_chunk). Without edge-type restriction the two engines were answering different questions —shortest_path()was routing throughhas_chunk, producing shorter paths than the MENTIONS-only CTE. Path lengths disagreed on 6 of 6 sampled pairs until I rebuilt a MENTIONS-only graph, after which they matched exactly on all 6.That is a correctness trap for anyone benchmarking or cross-checking
shortest_path()against another engine, since nothing in the signature signals that all edge types participate.Request
Add
edge_types text[] DEFAULT NULLtoshortest_path()andweighted_shortest_path(), with the same semantics as inexpand()/traverse()(NULL = all types). This would also remove the need for per-type graph registration in the common case.If restricting inside the CSR traversal is not straightforward, even documenting the current behavior in
api-reference.mdx— "all registered edge types participate; register a separate graph to restrict" — would prevent the mismatch above.Environment
ghcr.io/evokoa/pggraph:1.0.0, PostgreSQL 17.10, linux/arm64.