Skip to content

Direct Cypher row lowering rejects scalar multi-alias projections from a single MATCH #981

Description

@lmeyerov

Summary

Direct Cypher currently rejects scalar projections that need values from more than one alias in the matched pattern, even when the final projection only returns scalars.

This showed up immediately while trying to map the first LDBC SNB Interactive reads into pyg-bench.

Environment used for repro:

  • repo: graphistry/pygraphistry
  • sha: ebe7d0ae827d724a8779e123c3965ec723581015
  • host runtime: uv run python ...

Minimal repro

import pandas as pd
from graphistry.tests.test_compute import CGFull

g = CGFull().nodes(
    pd.DataFrame({
        'id': ['a', 'b'],
        'label__A': [True, False],
        'label__B': [False, True],
    }),
    'id',
).edges(
    pd.DataFrame({
        's': ['a'],
        'd': ['b'],
        'type': ['R'],
    }),
    's',
    'd',
)

queries = [
    "MATCH (a:A)-[:R]->(b:B) RETURN a.id AS a_id, b.id AS b_id",
    "MATCH (a:A)-[:R]->(b:B) WITH a.id AS a_id, b.id AS b_id RETURN a_id, b_id",
]

for query in queries:
    print(query)
    print(g.gfql(query)._nodes)

Observed behavior

Both queries fail with:

GFQLValidationError [unsupported-cypher-query] Cypher row lowering currently supports one MATCH source alias at a time | field: return | value: ['a', 'b']

Expected behavior

These should return a single row with both scalar values:

[{'a_id': 'a', 'b_id': 'b'}]

Why this matters

This blocks straightforward scalarized projections for official benchmark queries, for example:

  • SNB IS1: person fields plus p.id AS cityId
  • SNB IS3: friend fields plus r.creationDate AS friendshipCreationDate

Likely relation

This may share an underlying fix with #880, but this is the narrower direct-Cypher user-visible failure mode that is easy to reproduce.

Activity

  1. lmeyerov commented on Mar 31, 2026

    @lmeyerov
    ContributorAuthor

    Additional measured benchmark manifestation from pyg-bench on March 31, 2026:

    interactive-complex-8 / Q8. Recent replies no longer hard-fails, but direct Cypher row lowering still misbinds projected aliases.

    Observed shape:

    MATCH (start:Person {id: $personId})<-[:HAS_CREATOR]-(:Message)<-[:REPLY_OF]-(comment:Comment)-[:HAS_CREATOR]->(person:Person)
    RETURN
        person.id AS personId,
        person.firstName AS personFirstName,
        person.lastName AS personLastName,
        comment.creationDate AS commentCreationDate,
        comment.id AS commentId,
        comment.content AS commentContent
    ORDER BY commentCreationDate DESC, commentId ASC
    LIMIT 20

    Actual mismatch pattern on current master / v0.53.10 (7095102df492feed0ce7a83240ee406c779c5f81):

    • personId is populated with commentId
    • personFirstName / personLastName come back as None

    So #981 is still the right umbrella for measured multi-binding projection problems, but the current failure mode is sometimes silent semantic corruption, not only a validation/planner rejection.

  2. lmeyerov commented on Mar 31, 2026

    @lmeyerov
    ContributorAuthor

    New measured SNB benchmark manifestations from pyg-bench against explicit master snapshot 7095102df:

    • interactive-complex-4 / new-topics: direct Cypher fails before execution with [unsupported-cypher-query] Cypher row lowering currently supports one MATCH source alias at a time | field: return | value: ['post', 'tag']. GFQL workaround matches the staged fixture via friend traversal + local post-tag aggregation.\n- interactive-complex-11 / job-referral: direct Cypher fails before execution with [unsupported-cypher-query] Cypher row lowering currently supports one MATCH source alias at a time | field: where | value: 'not(person=friend)'. GFQL workaround matches the staged fixture via 1..2-hop friend expansion + local employment/company join.\n\nCurrent measured SNB floor is now 12/29 official queries, and #981 remains the largest Cypher unlock by affected-query count.
  3. lmeyerov commented on Apr 1, 2026

    @lmeyerov
    ContributorAuthor

    Benchmark follow-up from pyg-bench after rerunning against isolated ambient graphistry v0.53.11:

    Artifact:

    • results/runs/local-snb-interactive-v05311-rerun/

    interactive-complex-9 / recent-network-messages now gets past the earlier #1000 WITH collect(distinct friend) -> UNWIND -> MATCH blocker and lands here instead.

    Current residual message:

    • [unsupported-cypher-query] Cypher row lowering currently supports one MATCH source alias at a time | field: where | value: 'NOT friend = root'

    So for benchmarks, Q9 has moved from the #1000 bucket into the broader multi-binding row-lowering family tracked here.

  4. lmeyerov commented on Apr 1, 2026

    @lmeyerov
    ContributorAuthor

    Fresh follow-on investigation from #1005 / #1006 adds another concrete acceptance case for this issue family.

    New exact direct repro on current master:

    • MATCH (:A {id: $seed})-[:R]->(b:B) WITH b, b.id AS bid MATCH (b)-[:S]->(c:C), (c)-[:T]->(d:D) RETURN bid, d.id AS did
    • current error: Cypher MATCH after WITH currently supports a single trailing MATCH pattern

    Important finding: when that guard is relaxed experimentally, the query does not become correct. Instead it exposes the older multi-alias bindings/projection corruption underneath. Plain non-reentry controls on the same connected multi-pattern path are already wrong too, e.g.:

    • MATCH (b:B)-[:S]->(c:C), (c)-[:T]->(d:D) RETURN c.id AS cid, d.id AS did
    • observed corrupted rows where cid / did collapse onto the wrong aliases

    The immediate culprit is the existing rows(alias_endpoints=...) shortcut, which only knows src / dst and cannot represent distinct aliases across a longer connected path. That makes #1006 look like another symptom of the broader bindings-table / multi-alias row-projection gap already described here and in #880.

    So #1006 should likely be treated as an acceptance case / benchmark-facing symptom under #981 rather than a separate narrow implementation lane.

  5. lmeyerov commented on Apr 1, 2026

    @lmeyerov
    ContributorAuthor

    Draft implementation is up in #1008. This lane now has the connected multi-alias row-binding path, local broad validation, and targeted DGX cudf proof for the admitted slice.

  6. lmeyerov commented on Apr 2, 2026

    @lmeyerov
    ContributorAuthor

    Benchmark clarification from the latest current-master dgx-spark sweep on 14dafaf6b951954d8de840f9236f3e874249ebac:\n\n- interactive-complex-8 / recent-replies no longer belongs in the #981 bucket on current master. Direct Cypher now returns the expected staged-fixture rows.\n - artifact: results/runs/dgx-spark-snb-interactive-ic8-origin-master-14dafaf6b9-fresh-r1/\n- the current-master benchmark lanes still reproducing #981 are:\n - interactive-complex-2 / recent-friend-messages\n - interactive-complex-4 / new-topics\n - interactive-complex-9 / recent-network-messages\n - interactive-complex-11 / job-referral\n\nSo #981 is still live for benchmark coverage, but the old recent-replies example is now stale on current master.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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