Skip to content

Build graph adjacency in DuckDB instead of Elixir MapSets - #36

Merged
cigrainger merged 1 commit into
mainfrom
perf/graph-betweenness-duckdb
Mar 25, 2026
Merged

cigrainger merged 1 commit into
mainfrom
perf/graph-betweenness-duckdb

Conversation

@cigrainger

Copy link
Copy Markdown
Contributor

Summary

Replace Elixir-side adjacency construction for betweenness centrality with DuckDB LIST(DISTINCT ...) aggregation.

Before: Materialize all edge columns → Enum.zip both directions → Enum.reduce building %{node => MapSet.new(neighbors)} → MapSet.to_list each entry.

After: Single SQL query: WITH bidir AS (... UNION ALL ...) SELECT node, LIST(DISTINCT neighbor) FROM bidir GROUP BY node → table_to_columns → Enum.zip |> Map.new.

DuckDB handles bidirectional expansion, deduplication, and grouping in one pass. Simpler code, same correctness.

Also adds bench/graph_bench.exs for betweenness centrality benchmarking.

Benchmark (10K vertices, ~80K edges, sample=10)

Before After
Median 806ms 726ms

Performance neutral — BFS iterations dominate (~95% of time). The adjacency build improvement is masked by the algorithmic cost. The value is in code clarity and delegating deduplication to DuckDB.

Test plan

  • 26 graph tests pass (0 failures)
  • Credo strict clean
  • Benchmarks before and after at multiple scales

🤖 Generated with Claude Code

Replace Elixir-side adjacency construction (materialize edge columns →
Enum.zip → Enum.reduce with MapSet) with DuckDB LIST aggregation.
DuckDB handles bidirectional edge expansion, deduplication, and grouping
in a single SQL pass.

Also fixes get_vertex_ids to use table_to_rows instead of
table_to_columns for consistency.

Adds bench/graph_bench.exs for betweenness centrality benchmarking.

Performance is neutral — BFS iterations dominate at all tested scales.
The adjacency build is ~5% of total time. The change simplifies code
and delegates deduplication to DuckDB.

Benchmark (10K vertices, ~80K edges, sample=10):
  Before: 806ms median
  After:  726ms median (~10% faster, within noise)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@cigrainger
cigrainger merged commit 327f1ce into main Mar 25, 2026
5 checks passed
@cigrainger
cigrainger deleted the perf/graph-betweenness-duckdb branch March 25, 2026 02:17
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