Conversation
…s.txt and split out requirements-dev.txt. Version bumps.
…ney/build-upgrades
…ney/build-upgrades
…mes into rjurney/pregel-tutorial
…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
…mes into rjurney/pregel-tutorial
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
…mes into rjurney/pregel-tutorial
There was a problem hiding this comment.
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.
| @@ -10,6 +11,7 @@ def cli(): | |||
|
|
|||
|
|
|||
| cli.add_command(download.stackexchange) | |||
| cli.add_command(neo4j) | |||
|
|
|||
| # 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, | ||
| ) |
| """ | ||
| 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) | ||
|
|
| 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 |
| 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| |
There was a problem hiding this comment.
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 atpython/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 ispython/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
| """ | ||
| 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}") |
| 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" | ||
|
|
|
Closed in favor of #809 |
What changes were proposed in this pull request?
Why are the changes needed?