Skip to content

Create Pregel and Neo4j Ingeration tutorials and add Pregel API to user guide - #578

Closed
rjurney wants to merge 107 commits into
graphframes:mainfrom
rjurney:rjurney/pregel-tutorial
Closed

rjurney wants to merge 107 commits into
graphframes:mainfrom
rjurney:rjurney/pregel-tutorial

Conversation

@rjurney

@rjurney rjurney commented Apr 15, 2025

Copy link
Copy Markdown
Collaborator

What changes were proposed in this pull request?

Why are the changes needed?

…s.txt and split out requirements-dev.txt. Version bumps.
@rjurney rjurney changed the title Create a Pregel tutorial and add Pregel API to user guide Create Pregel and Neo4j Ingeration tutorials and add Pregel API to user guide Dec 25, 2025
rjurney added 11 commits July 23, 2026 14:15
…ake sure it all works. Update codespell for Sergey Brin.
… problem with pandas/numpy version 2.5.1 being required by Python >= 3.10
…ontext lessons

Present the original broken LPA code as a teaching device: explain why
Pregel.src() fails outside message expressions, why aggMsgs forbids nested
aggregates (mode(collect_list()) -> F.mode(Pregel.msg())), and why
withVertexColumn must own the label column. Add verified corrected
implementation with real Stack Exchange output and a log2-bucketed text
histogram of community sizes with log10-scaled bars.
…-weighted PageRank

Replace simulated Id % 3 node types with the graph's real Type column and
fix the type weight to use Pregel.src("Type") in the message expression
(triplet context). Add human-readable names via coalesce over DisplayName/
Title/TagName/Body, verified output tables, and a new subsection explaining
the User teleport-floor result: edges point from users, so rank never flows
to them - edge direction determines which node types accumulate importance.

Add "suppor" to codespell ignore list: it appears in verbatim truncated
Spark output quoted in the tutorial.
…y/pyproject-numpy

# Conflicts:
#	python/poetry.lock
#	python/pyproject.toml
@rjurney rjurney mentioned this pull request Jul 28, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds end-to-end tutorial material for GraphFrames’ Pregel API and a Neo4j ↔ GraphFrames integration workflow, including new Python tutorial scripts/CLI commands and new documentation pages to guide users through data preparation, loading into Neo4j, running GraphFrames algorithms, and writing results back.

Changes:

  • Add a new Neo4j integration tutorial (docs + Python tutorial scripts + graphframes neo4j ... CLI).
  • Add a new Pregel tutorial to the docs and update spellcheck configuration accordingly.
  • Update Python packaging (Poetry) to include runtime/tutorial dependencies needed by the new tutorial code.

Reviewed changes

Copilot reviewed 13 out of 18 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
python/tests/test_neo4j_tutorial.py Adds a Neo4j tutorial “validation” script (currently placed under tests).
python/pyproject.toml Adds/updates Python dependencies for runtime and tutorial/dev groups.
python/poetry.lock Updates locked Python dependency set to match pyproject changes.
python/graphframes/tutorials/stackexchange.py Adjusts data path resolution and writes additional Parquet outputs for Neo4j loading.
python/graphframes/tutorials/neo4j/loaders.py Adds APOC Parquet loading helpers and loader registry for node/edge types.
python/graphframes/tutorials/neo4j/load.py Adds a Spark-based Neo4j loading script (connector-based alternative).
python/graphframes/tutorials/neo4j/docker.py Adds helpers to start/stop/manage a Neo4j Docker container configured for APOC.
python/graphframes/tutorials/neo4j/connected_components.py Adds a script to read from Neo4j, run Connected Components, and write results back.
python/graphframes/tutorials/neo4j/cli.py Adds graphframes neo4j CLI group for container management, loading, and status.
python/graphframes/tutorials/neo4j/init.py Exposes the Neo4j CLI entry point from the tutorials package.
python/graphframes/console.py Registers the new Neo4j CLI command in the main graphframes CLI.
docs/src/03-tutorials/04-neo4j-integration.md Adds detailed Neo4j integration tutorial documentation.
docs/src/03-tutorials/03-pregel-tutorial.md Adds a comprehensive Pregel tutorial page.
.codespellrc Updates codespell ignore list to accommodate tutorial text.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 1 to 15
@@ -10,6 +11,7 @@ def cli():


cli.add_command(download.stackexchange)
cli.add_command(neo4j)

Comment on lines +18 to +37
# Compute the default data directory relative to this package
_PACKAGE_DIR = Path(__file__).parent.parent # tutorials/
DEFAULT_DATA_DIR = str(_PACKAGE_DIR / "data")

from graphframes.tutorials.neo4j.docker import (
CONTAINER_NAME,
DEFAULT_PASSWORD,
check_docker,
container_exists,
remove_container,
start_container,
wait_for_ready,
)
from graphframes.tutorials.neo4j.loaders import (
EDGE_LOADERS,
NODE_LOADERS,
clear_database,
create_indexes,
get_parquet_file_uris,
)
Comment on lines +1 to +12
"""
Test script for Neo4j integration tutorial.
Tests the data processing logic without requiring Neo4j.
"""
import pyspark.sql.functions as F
from graphframes import GraphFrame
from pyspark.sql import SparkSession, DataFrame

print("=" * 80)
print("NEO4J TUTORIAL - CODE VALIDATION")
print("=" * 80)

Comment on lines +6 to +10
spark-submit \\
--packages org.neo4j:neo4j-connector-apache-spark_2.12:5.3.1_for_spark_3 \\
--driver-memory 4g \\
--executor-memory 4g \\
python/graphframes/tutorials/neo4j_load.py
Comment on lines +5 to +9
spark-submit \\
--packages org.neo4j:neo4j-connector-apache-spark_2.12:5.3.1_for_spark_3 \\
--driver-memory 4g \\
--executor-memory 4g \\
python/graphframes/tutorials/neo4j_connected_components.py
| name| pagerank|
+--------------------------------------------------+--------------------+
| TeX processing for Stats| 0.1450891970426848|
|What typographic support is available to suppor...| 0.14112968883288293|
Comment thread .codespellrc

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 18 changed files in this pull request and generated 3 comments.

Suppressed comments (6)

Previously missed (5) — in code that hasn't changed since the last review.

python/graphframes/tutorials/neo4j/loaders.py:35

  • get_container_path() uses relpath() without verifying that host_path is under data_dir. If a caller passes a path outside the mounted directory, the resulting file:// URI can include ".." segments and potentially reference paths outside Neo4j’s import mount. Validate host_path is within data_dir before constructing the container URI.
    # Get the path relative to the data_dir
    abs_data_dir = os.path.abspath(data_dir)
    abs_host_path = os.path.abspath(host_path)

    # Calculate relative path from data_dir
    rel_path = os.path.relpath(abs_host_path, abs_data_dir)

python/graphframes/tutorials/neo4j/load.py:10

  • The usage example points to python/graphframes/tutorials/neo4j_load.py, but the script lives at python/graphframes/tutorials/neo4j/load.py. This makes the example command fail if copied verbatim.
    spark-submit \\
      --packages org.neo4j:neo4j-connector-apache-spark_2.12:5.3.1_for_spark_3 \\
      --driver-memory 4g \\
      --executor-memory 4g \\
      python/graphframes/tutorials/neo4j_load.py

python/graphframes/tutorials/neo4j/connected_components.py:54

  • The Neo4j read query selects properties using capitalized keys (e.g. n.DisplayName, n.Title), but the APOC loaders in this PR write properties using lower camelCase (e.g. displayName, title). With the current query, these fields will always be null when data is loaded via the CLI/APOC path; use coalesce() to support both schemas.
        MATCH (n)
        RETURN
            n.id as id,
            labels(n)[0] as Type,
            n.Id as Id,

python/graphframes/tutorials/neo4j/connected_components.py:166

  • Writing back to Neo4j uses .mode("Overwrite"). The tutorial text/examples in this PR use append semantics for updates, and overwrite mode can be interpreted by connectors as destructive depending on configuration. Use Append here to avoid any chance of dropping existing data while running the tutorial.
    component_results.write
    .format("org.neo4j.spark.DataSource")
    .mode("Overwrite")
    .option("query", """
        UNWIND $rows AS row

python/graphframes/tutorials/neo4j/connected_components.py:9

  • The usage example points to python/graphframes/tutorials/neo4j_connected_components.py, but the script is python/graphframes/tutorials/neo4j/connected_components.py. This makes the example command fail if copied verbatim.
    spark-submit \\
      --packages org.neo4j:neo4j-connector-apache-spark_2.12:5.3.1_for_spark_3 \\
      --driver-memory 4g \\
      --executor-memory 4g \\
      python/graphframes/tutorials/neo4j_connected_components.py

python/graphframes/console.py:5

  • graphframes.console imports the Neo4j CLI unconditionally, but the neo4j Python driver is not declared in python/pyproject.toml (and isn’t present in python/poetry.lock). As a result, importing graphframes.console / running the graphframes CLI will raise ModuleNotFoundError in environments that don’t have the optional Neo4j dependency installed.
import click

from graphframes.tutorials import download
from graphframes.tutorials.neo4j import neo4j

Comment on lines +1 to +8
"""
Test script for Neo4j integration tutorial.
Tests the data processing logic without requiring Neo4j.
"""
import pyspark.sql.functions as F
from graphframes import GraphFrame
from pyspark.sql import SparkSession, DataFrame

type_nodes.write
.format("org.neo4j.spark.DataSource")
.mode("Overwrite" if node_type == node_types[0] else "Append")
.option("labels", f":{node_type}")
Comment thread python/pyproject.toml
Comment on lines 64 to 70
black = "^23.12.1"
flake8 = "^7.1.1"
isort = "^6.0.0"
pre-commit = "^4.6.1"
pyspark = { version = ">=3.5, <4.2", extras = ["connect"] }
pytest = "^9.0.3"

@rjurney

rjurney commented Aug 29, 2026

Copy link
Copy Markdown
Collaborator Author

Closed in favor of #809

@rjurney rjurney closed this Aug 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants