Skip to content

benchmarks/gfql: q1-q9 runner uses dataframe shortcuts (bypasses GFQL engine) + untimed lowercase precompute — unfair vs competitor DBs #1710

Description

@lmeyerov

Summary (benchmark integrity — must fix before publishing "official" numbers)

benchmarks/gfql/graph_benchmark_q1_q9.py (GFQL vs Kuzu/Ladybug/Neo4j/Memgraph on the prrao87 graph-benchmark suite) gives GFQL two unfair advantages vs the competitor databases, which all run their own real Cypher:

1. Dataframe shortcuts bypass the GFQL engine entirely

For q1, q3, q4, q5, q6, q7 (query_variant="standard", the default — _uses_dataframe_shortcut, line 238-243), GFQL does not run its query engine. It runs hand-written pandas/cuDF groupby/merge code (_query{1,3,4,5,6,7}_dataframe_shortcut, plus _query5_polars_shortcut, _query6_cudf_shortcut, etc.). That measures hand-tuned dataframe code, not GFQL — while Kuzu/Neo4j/Memgraph parse+plan+execute real Cypher. Not apples-to-apples.

  • Fix: run real GFQL (g.gfql(<cypher>, engine=...)) for all queries. On pandas/cuDF this works for q1-q9 once the count(<other-alias>) lowering routing is fixed (see the lowering issue; q1 also works today via the count(*) form). On polars, traversal queries NIE (see the polars binding_ops issue) and count(*) is currently wrong (see the P0 count-broadcast issue).

2. Untimed lowercase precompute (both GFQL and the Memgraph runner)

  • graph_benchmark_q1_q9.py precomputes gender_lc/interest_lc at load (untimed) for the toLower() filters in q5/q6/q7. Measured impact when moved inside the timed region: <1ms (negligible) — but for symmetry it should be timed or removed.
  • graph_benchmark_memgraph_q1_q9.py similarly precomputes lowercased columns. The competitors (Kuzu/Ladybug/Neo4j) run raw tolower() inline. For official numbers, no side gets untimed precompute — everyone runs the raw query.

Data-scale caveat (already caught)

/tmp/graph-benchmark-gfql-memgraph = TINY (1k persons/10k edges). Full data (100k/2.42M) = /tmp/graph-benchmark-gfql-memgraph-full (repo data/ symlinks to it; the Docker mount does NOT follow the symlink — mount the target dir directly). An earlier Memgraph q1-q9 run on the tiny set produced invalid ~100× fast numbers.

Acceptance

  • GFQL runs its real engine (no dataframe shortcuts) for every query it reports.
  • No untimed precompute for any system.
  • Every system runs the identical canonical query from the prrao87 repo (neo4j/query.py etc.).
  • Where GFQL can't yet run a query as real GFQL on an engine, the cell is marked honestly (NIE / in-progress), NOT shortcut-faked.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions