Skip to content

fix(gfql): semi-join filter on OPTIONAL MATCH arm before left-outer-join (#1052) - #1067

Merged
lmeyerov merged 5 commits into
masterfrom
fix/issue-1052-optional-match-semijoin
Apr 6, 2026
Merged

lmeyerov merged 5 commits into
masterfrom
fix/issue-1052-optional-match-semijoin

Conversation

@lmeyerov

@lmeyerov lmeyerov commented Apr 6, 2026

Copy link
Copy Markdown
Contributor

Closes #1052

Summary

  • Before the left-outer-join in _apply_connected_optional_match, filter the optional arm's binding-row result to only join-key values present in the base MATCH result (semi-join).
  • Single join-col path: .isin() filter.
  • Multi-col path: drop_duplicates() + inner merge on join keys.

Problem

_apply_connected_optional_match (gfql_unified.py) ran each OPTIONAL MATCH arm against the full graph, materializing ALL matching paths before joining. For IS7 on LDBC SNB sf1:

  • Base MATCH yields a small number of rows (filtered by m.id = $messageId)
  • OPTIONAL MATCH materializes all (a:Person)-[r:KNOWS]-(p) paths (millions on sf1)
  • Left-join produces N_base × N_opt intermediate → ~120 GB RSS → SIGKILL

Fix location

graphistry/compute/gfql_unified.py lines 327–337 (_apply_connected_optional_match)

Tests

Added test_issue_1052_optional_match_semijoin_filters_opt_arm — IS7 shape with scoped base query (m.id = $mid) and disjoint m2 subgraph that would bleed through without the semi-join filter.

All 706 lowering tests pass. Full suite (1931 passed, 457 skipped) green.

Related

  • pyg-bench#1 (private benchmark tracker)

🤖 Generated with Claude Code

…oin (#1052)

Restrict the OPTIONAL MATCH binding-row result to join-key values present
in the base MATCH result before materializing the left-outer-join. Prevents
the full cross-product blowup (N_opt_rows × N_base_rows) that caused ~120 GB
RSS and SIGKILL on LDBC SNB sf1 IS7.

Single join-col path: .isin() filter on opt_rows_df.
Multi-col path: drop_duplicates() inner merge on join keys.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
lmeyerov and others added 4 commits April 5, 2026 21:20
Add 5 targeted tests for OPTIONAL MATCH semi-join fix:
- multi-col path with 2 shared aliases (duplicate-column guard)
- multi-arm: arm-2 joins on arm-1-added column
- multi-arm: arm-2 null-fills when arm-1 misses
- edge-alias synthesis intact after semi-join filter
- 5-message parameterized graph: no bleed from unscoped opt rows

Fix graph topology in edge-alias test (distinct a1/a2 nodes so
semi-join by a.id correctly scopes m1's opt rows).

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
@lmeyerov
lmeyerov merged commit f1b6b19 into master Apr 6, 2026
101 checks passed
@lmeyerov
lmeyerov deleted the fix/issue-1052-optional-match-semijoin branch April 6, 2026 08:08
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.

GFQL OPTIONAL MATCH join materializes full cross-product before outer-scope filter (IS7 execution kill)

1 participant