Skip to content

shortest_path() has no edge_types filter, unlike expand()/traverse() #23

Description

@ysys143

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions