Skip to content

perf(gfql): route engine=auto to native polars for polars-frame graphs#1743

Draft
lmeyerov wants to merge 3 commits into
masterfrom
fix/gfql-auto-engine-polars-native
Draft

perf(gfql): route engine=auto to native polars for polars-frame graphs#1743
lmeyerov wants to merge 3 commits into
masterfrom
fix/gfql-auto-engine-polars-native

Conversation

@lmeyerov

Copy link
Copy Markdown
Contributor

Summary

resolve_engine(AUTO) maps polars frames to Engine.PANDAS (that branch predates Engine.POLARS), so g.gfql(query) on a polars-frame graph silently bridges to the generic pandas path — measured ~3× on a small seeded cypher query and ~13× on the q5 graph-benchmark shape (see plans/gfql-benchmark-numbers), with pandas frames coming back out.

This routes engine='auto' (the default) to the native polars engine when both bound frames are polars, with an honest-NotImplementedError fallback to the legacy AUTO path — the fallback is permitted here because the user did not pin an engine (the no-silent-fallback contract applies to explicit engine=).

  • Scope is deliberately gfql-only (one guard in gfql()): changing resolve_engine itself would ripple into plotting/util paths that only handle pandas/cudf.
  • Behavior change: AUTO results on polars graphs are now polars frames (frames in = frames out) and previously-bridged queries now run natively; polars-NIE shapes (e.g. shortestPath) still answer via the fallback (test-pinned).

Measurements (2k-node polars graph, seeded 1-hop cypher, warm)

engine before after
'polars' (explicit) 8.5ms / polars out 8.8ms / polars out
default (auto) 25.0ms / pandas out 9.3ms / polars out

Tests

  • TestAutoEngineRoutesPolarsNative: auto == explicit-polars result (frame-equal, native frames); shortestPath NIEs when pinned but answers via auto fallback.
  • Full polars lanes: 1224 passed (1 pre-existing dask env failure, fails on master too).

🤖 Generated with Claude Code

https://claude.ai/code/session_01Y6dQEcjdazEnzuvuwf73ZL

lmeyerov and others added 3 commits July 19, 2026 23:47
resolve_engine(AUTO) maps polars frames to PANDAS (it predates
Engine.POLARS), so g.gfql(query) on a polars-frame graph silently
bridged to the generic pandas path: ~3-13x slower on cypher point
queries and pandas frames out. Route AUTO to the native polars engine;
an honest NotImplementedError (unsupported shape) falls back to the
legacy AUTO path — allowed because the user did not pin an engine.
Frames in = frames out: AUTO results on polars graphs are now polars.

Repro: 2k-node polars graph, seeded 1-hop cypher — AUTO 25.0ms/pandas
out before, 9.3ms/polars out after (engine='polars' = 8.8ms); polars-NIE
shapes (shortestPath) still answer via the pandas fallback.

Fixes the q5 finding in plans/gfql-benchmark-numbers (inferred-engine
13x penalty).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y6dQEcjdazEnzuvuwf73ZL
…c records

The dual-path guards checked hasattr(out, 'to_dict') first, but polars
DataFrame HAS to_dict (without orient) — so the polars branch was
unreachable and these tests only ever ran because auto silently returned
pandas. With auto routing polars-frame graphs natively they now receive
polars frames; probe to_dicts first. Assertions (record values) unchanged
and still pass on both engines.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y6dQEcjdazEnzuvuwf73ZL
@lmeyerov

Copy link
Copy Markdown
Contributor Author

Too early to enable by default

lmeyerov added a commit that referenced this pull request Jul 22, 2026
…rialize-first

Review findings (plans/review-pr-1767/review.md): B1 edges-only polars
graph crashed in the NODE_ID build (materialize under AUTO synthesizes
pandas; polars gathers ran on a pandas frame) — gfql_index_all now
materializes + engine-aligns BEFORE any build so all indexes land valid,
and create_index re-aligns for direct calls. M1 LazyFrame frames under
AUTO crashed — the gate now requires EAGER polars DataFrames on ALL
present frames (LazyFrame/mixed keep the legacy pandas path). Spy test
asserts the index SERVED (non-None), not merely was called. AUTO-query
trade-off documented in CHANGELOG (deferred to #1743 by policy hold).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y6dQEcjdazEnzuvuwf73ZL
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant