Summary
GFQL native g.hop()/g.chain seeded point lookups are O(degree)-flat and dominate Kuzu at every scale, but native multi-row traversals (many-seed wavefront) grow super-linearly with graph size and lose their lead. Measured same-session, same-box, matched Kuzu, LDBC SF0.1 → SF1 (~11× data), current master 983d2aff, warm-median, gfql_index=use.
Evidence (raw-JSON verified, pandas native-hop backend)
| query |
SF0.1 ms |
SF1 ms |
native growth |
Kuzu growth |
verdict shift |
| seed-lookup (point) |
0.27 |
0.30 |
1.1× (flat) |
~1.5× |
WIN → WIN (widens 4.9→5.9×) |
| message-creator (point) |
0.24 |
0.26 |
1.1× (flat) |
~1.5× |
WIN → WIN (5.8×) |
| message-replies (multi-row) |
6.58 |
57.53 |
8.7× |
23.8→36.0 (1.5×) |
WIN → LOSE |
| new-topics (multi-row) |
15.8 |
91.1 |
5.8× |
— |
erodes |
| recent-replies (multi-row) |
13.1 |
89.7 |
6.8× |
— |
erodes |
Best-engine native-vs-Kuzu tally falls SF0.1 7W/2L → SF1 4W/1T/4L, entirely from multi-row traversal erosion (IS2 WIN→LOSE, IS7 WIN→TIE, IC8 WIN→LOSE). Points and deep-aggregating traversals are unaffected.
Suspected root cause (needs a trace to confirm — do not assume)
The point path hits the #1658 CSR index and is flat. The multi-row path grows ~O(E): candidate causes are (a) the #1658 index not fully engaging when the hop wavefront has many seeds (falls back to a full edge scan), and/or (b) per-call O(E) edge-frame materialization in the harness/executor (the combine_steps/projection family, cf. #1755) that scales with edge count rather than result size.
Why it's fixable (a lever, not a wall)
A prior (uncommitted, never-landed) build with two multi-row opts — memoizing _build_known_pairs and sort/limit-before-projection — recovered the flatness (message-replies stayed a WIN at SF1). So the erosion is addressable; it just isn't on master. This issue tracks landing the real fix + re-measuring.
Ask
- Trace the multi-row hop on SF1 (
gfql_explain + cProfile) to disentangle index-under-engagement vs O(E) materialization.
- Land the multi-row fast path (index engagement on many-seed hops and/or result-sized materialization).
- Re-run the native-vs-Kuzu SF0.1→SF1 matrix to confirm multi-row traversals stay flat/winning at scale.
Related: #1755 (single-row seeded abstraction tax, same executor family), #1709 (polars rows-binding NIE). Evidence: plans/gfql-benchmark-numbers/native-vs-competitor-sf{01,1}.md.
Summary
GFQL native
g.hop()/g.chainseeded point lookups are O(degree)-flat and dominate Kuzu at every scale, but native multi-row traversals (many-seed wavefront) grow super-linearly with graph size and lose their lead. Measured same-session, same-box, matched Kuzu, LDBC SF0.1 → SF1 (~11× data), current master983d2aff, warm-median,gfql_index=use.Evidence (raw-JSON verified, pandas native-hop backend)
Best-engine native-vs-Kuzu tally falls SF0.1 7W/2L → SF1 4W/1T/4L, entirely from multi-row traversal erosion (IS2 WIN→LOSE, IS7 WIN→TIE, IC8 WIN→LOSE). Points and deep-aggregating traversals are unaffected.
Suspected root cause (needs a trace to confirm — do not assume)
The point path hits the #1658 CSR index and is flat. The multi-row path grows ~O(E): candidate causes are (a) the #1658 index not fully engaging when the hop wavefront has many seeds (falls back to a full edge scan), and/or (b) per-call O(E) edge-frame materialization in the harness/executor (the
combine_steps/projection family, cf. #1755) that scales with edge count rather than result size.Why it's fixable (a lever, not a wall)
A prior (uncommitted, never-landed) build with two multi-row opts — memoizing
_build_known_pairsand sort/limit-before-projection — recovered the flatness (message-replies stayed a WIN at SF1). So the erosion is addressable; it just isn't on master. This issue tracks landing the real fix + re-measuring.Ask
gfql_explain+ cProfile) to disentangle index-under-engagement vs O(E) materialization.Related: #1755 (single-row seeded abstraction tax, same executor family), #1709 (polars rows-binding NIE). Evidence:
plans/gfql-benchmark-numbers/native-vs-competitor-sf{01,1}.md.