---
name: "Reads: aura_client_id, aura_client_secret, aura_project_id (optional)"
repo: https://github.com/neo4j-contrib/neo4j-skills
source: https://github.com/neo4j-contrib/neo4j-skills/blob/HEAD/neo4j-aura-graph-analytics-skill/SKILL.md
license: "MIT"
install: "npx skills add neo4j-contrib/neo4j-skills --skill neo4j-aura-graph-analytics-skill"
page: https://100xlab.com/resources/agent-skills/neo4j-contrib-neo4j-skills--neo4j-aura-graph-analytics-skill--1kbt49j
---

## When to Use
- Running GDS algorithms in Aura Graph Analytics GDS Sessions
- Creating `GdsSessions` or using `AuraGraphDataScience`
- Remote projecting connected Neo4j data with `gds.graph.project.remote(...)`
- Using AuraDB Cypher API projection with `{ memory: ... }` or `{ sessionId: ... }`
- Processing graph data from non-Neo4j sources (Pandas, Spark, CSV)
- On-demand / pipeline workloads — ephemeral sessions, pay per session-minute
- Full isolation from the live database during analytics

## When NOT to Use
- **Aura Pro with embedded GDS plugin** → `neo4j-gds-skill`
- **Self-managed Neo4j with embedded GDS plugin** → `neo4j-gds-skill`
- **Writing Cypher queries** → `neo4j-cypher-skill`
- **Snowflake Graph Analytics** → `neo4j-snowflake-graph-analytics-skill`

---

## Deployment Decision Table

| Deployment | Use |
|---|---|
| AuraDB Free | **this skill** — max `m_2GB`, 1 concurrent session, unbilled |
| Aura Pro + Graph Analytics plugin enabled (lightweight exploration, shared resources) | `neo4j-gds-skill` |
| Aura Pro / Pro Trial + session (isolated compute) | **this skill** — up to 128 GB (Pro) / 8 GB (Pro Trial), 100 / 3 concurrent sessions |
| AuraDB + Python client sessions | **this skill** |
| AuraDB + Cypher API | **this skill** for AGA-specific projection/session notes; `neo4j-cypher-skill` for query authoring |
| Self-managed Neo4j + AGA session | **this skill** |
| Self-managed Neo4j + embedded plugin | `neo4j-gds-skill` |
| Non-Neo4j data (Pandas, Spark) | **this skill** (standalone mode) |

---

## Defaults

- `graphdatascience >= 1.15` required; `>= 1.18` for Spark
- Prefer v2 endpoints: `gds.v2.graph.project(...)`, `gds.v2.page_rank.*`, `gds.v2.graph.node_properties.*`
- Use snake_case parameters end-to-end; never mix v2 with camelCase params
- Use v1 if v2 endpoint missing/incompatible; label fallback
- Call `gds.v2.verify_session_connectivity()` after session creation
- Connected sessions: call `gds.v2.verify_db_connectivity()` when source DB access required
- Estimate memory before large sessions
- Set TTL; default 1h idle, max 7d
- Close session when done: `gds.delete()` or `sessions.delete(name)` stops billing
- Use `AuraAPICredentials.from_env()` — never hardcode credentials

---

## Installation

```bash
pip install "graphdatascience>=1.15,<2"    # 1.22 is the current stable release
```

### graphdatascience 2.0 (alpha)

`2.0aN` is pre-release — pin `<2` for production. Rename map for when 2.0 ships:

| 1.x | 2.0 |
|---|---|
| `gds.v2.<endpoint>` | `gds.<endpoint>` — `gds.v2` prefix gone; untyped 1.x endpoints removed |
| `gds.graph.project(...)` (AGA) | `gds.graph.project.cypher(...)` |
| `gds.graph.project_native(...)` (AGA) | `gds.graph.project.native(...)` |
| `GraphV2` / `ModelV2` | `Graph` / `Model` — `from graphdatascience import Graph` |
| `Graph.drop(failIfMissing=)` / `Model.drop(failIfMissing=)` | `fail_if_missing=` |
| `run_cypher(..., retryable=)` | removed — always retries |
| `ArrowEndpointVersion.from_arrow_info` | `check_version_compatibility` |
| `ServerVersion`, `SemanticVersion` from top level | `graphdatascience.versions` |
| `gds.graph.node_labels.mutate(write_concurrency=, job_id=)` | parameters removed |

2.0 minimums: GDS server 2.13, `neo4j` driver 5.26, pandas 2.x–3.x, pyarrow 21–25, numpy <3.

2.0 additions: `GdsSessions.estimate(algorithms=[...])` for per-algorithm memory; `GdsSessions.get_or_create(show_progress=...)`; `gds.pipeline.get`; `overwrite=True` on `gds.graph.project` / `generate` / `construct` / `filter` / `sample` to drop a same-named graph first; `GdsSessions.delete(session_id=...)` returns `False` when nothing was deleted.

---

## Key Patterns

### Step 1 — Authenticate

```python
import os
from graphdatascience.session import AuraAPICredentials, GdsSessions

sessions = GdsSessions(api_credentials=AuraAPICredentials.from_env())
# Reads: AURA_CLIENT_ID, AURA_CLIENT_SECRET, AURA_PROJECT_ID (optional)
# Create API credentials in Aura Console → Account → API credentials
```

If member of multiple projects: set `AURA_PROJECT_ID` or pass `project_id=`.

### Step 2 — Estimate Memory

```python
from graphdatascience.session import AlgorithmCategory, SessionMemory

memory = sessions.estimate(
    node_count=1_000_000,
    relationship_count=5_000_000,
    algorithm_categories=[
        AlgorithmCategory.CENTRALITY,
        AlgorithmCategory.NODE_EMBEDDING,
        AlgorithmCategory.COMMUNITY_DETECTION,
    ],
)
# Returns SessionMemory tier, e.g. SessionMemory.m_8GB
# Fixed tiers: m_2GB … m_512GB — see references/limitations.md
```

### Step 3 — Create Session

**Mode A — AuraDB connected:**
```python
from graphdatascience.session import DbmsConnectionInfo, SessionMemory, CloudLocation
from datetime import timedelta

db_connection = DbmsConnectionInfo(
    username=os.environ["NEO4J_USERNAME"],
    password=os.environ["NEO4J_PASSWORD"],
    aura_instance_id=os.environ["AURA_INSTANCEID"],  # from Aura Console URL
)

gds = sessions.get_or_create(
    session_name="my-analysis",
    memory=memory,
    db_connection=db_connection,
    ttl=timedelta(hours=2),
)
gds.v2.verify_session_connectivity()
gds.v2.verify_db_connectivity()
```

**Mode B — Self-managed Neo4j:**
```python
db_connection = DbmsConnectionInfo(
    uri=os.environ["NEO4J_URI"],          # e.g. "bolt://my-server:7687"
    username=os.environ["NEO4J_USERNAME"],
    password=os.environ["NEO4J_PASSWORD"],
)
gds = sessions.get_or_create(
    session_name="my-analysis-sm",
    memory=SessionMemory.m_8GB,
    db_connection=db_connection,
    ttl=timedelta(hours=2),
    cloud_location=CloudLocation("gcp", "europe-west1"),
)
gds.v2.verify_session_connectivity()
gds.v2.verify_db_connectivity()
```

**Mode C — Standalone (no Neo4j DB):**
```python
gds = sessions.get_or_create(
    session_name="my-standalone",
    memory=SessionMemory.m_4GB,
    ttl=timedelta(hours=1),
    cloud_location=CloudLocation("gcp", "europe-west1"),
)
gds.v2.verify_session_connectivity()
```

`get_or_create()` is idempotent; reconnects to existing session by name.

### Step 4 — Project Graph

**From connected Neo4j (remote projection):**
```python
query = """
    CALL () {
        MATCH (p:Person)
        OPTIONAL MATCH (p)-[r:KNOWS]->(p2:Person)
        RETURN p AS source, r AS rel, p2 AS target,
               p {.age, .score} AS sourceNodeProperties,
               p2 {.age, .score} AS targetNodeProperties
    }
    RETURN gds.graph.project.remote(source, target, {
        sourceNodeLabels:     labels(source),
        targetNodeLabels:     labels(target),
        sourceNodeProperties: sourceNodeProperties,
        targetNodeProperties: targetNodeProperties,
        relationshipType:     type(rel)
    })
"""

G, result = gds.v2.graph.project(
    graph_name="my-graph",
    query=query,
    undirected_relationship_types=["KNOWS"],
)
print(f"Projected {G.node_count()} nodes, {G.relationship_count()} relationships")
```

`CALL () { ... }` required for multi-pattern MATCH. Use `UNION` inside `CALL` for multiple labels/rel types.
Remote query uses `gds.graph.project.remote(...)`; pass graph name to `gds.v2.graph.project(...)`, not query.
V1 fallback: `gds.graph.project(graph_name="my-graph", query=query, undirected_relationship_types=["KNOWS"])`.

**Native remote projection (no Cypher query) [graphdatascience 1.22]** — `gds.v2.graph.project_native(...)` projects from the attached DB by label/type filter:
```python
G, result = gds.v2.graph.project_native(
    "my-graph",
    ["Person"],                              # node_label_filter
    ["KNOWS"],                               # relationship_type_filter
    node_properties=["age", "score"],
    undirected_relationship_types=["KNOWS"],
)
```
Attached sessions only. Use `project_native` for label/type-filtered projections; use `project(query=...)` for transformations, computed properties, or `UNION` heterogeneous patterns.

**AuraDB Cypher API projection:**
```cypher
CYPHER runtime=parallel
MATCH (source)
OPTIONAL MATCH (source)-->(target)
RETURN gds.graph.project(
  'my-graph',
  source,
  target,
  {},
  { memory: '2GB' }
)
```

Existing explicit session:
```cypher
CYPHER runtime=parallel
MATCH (source)
OPTIONAL MATCH (source)-->(target)
RETURN gds.graph.project(
  'my-graph',
  source,
  target,
  {},
  { sessionId: '00000000-11111111' }
)
```

Cypher API uses `gds.graph.project(...)`, not `gds.graph.project.remote(...)`. Put `memory`, `ttl`, `sessionId`, `batchSize` in fifth config argument.

Session management via Cypher API:
```cypher
CALL gds.session.getOrCreate('test-session', '2GB', duration({minutes: 30}))
YIELD id, name, status
RETURN id, name, status

CALL gds.session.list()
YIELD id, name, status, memory
RETURN id, name, status, memory
```

Implicit Cypher API sessions delete when all projected graphs in session are dropped.

**From Pandas DataFrames (standalone mode):**
```python
import pandas as pd

nodes_df = pd.DataFrame([
    {"nodeId": 0, "labels": "Person", "age": 30},
    {"nodeId": 1, "labels": "Person", "age": 25},
])
rels_df = pd.DataFrame([
    {"sourceNodeId": 0, "targetNodeId": 1, "relationshipType": "KNOWS"},
])

G = gds.v2.graph.construct("my-graph", nodes_df, rels_df)
# Multiple DataFrames: gds.v2.graph.construct("g", [nodes1, nodes2], [rels1, rels2])
```

Required columns — nodes: `nodeId` (int), `labels` (str). Relationships: `sourceNodeId`, `targetNodeId`, `relationshipType`. Drop string node properties before `construct()`.

### Step 5 — Run Algorithms

```python
# Mutate — chain results without writing to DB
gds.v2.page_rank.mutate(G, mutate_property="pagerank", damping_factor=0.85)
gds.v2.fast_rp.mutate(G,
    mutate_property="embedding",
    embedding_dimension=128,
    feature_properties=["pagerank"],
    random_seed=42,
)

# Stream — inspect results as DataFrame
df = gds.v2.page_rank.stream(G)
print(df.sort_values("score", ascending=False).head(10))

# Write — persist to connected Neo4j DB (connected modes only)
gds.v2.louvain.write(G, write_property="community")
```

V1 fallback: `gds.pageRank.mutate(..., mutateProperty="pagerank")`. Plugin algorithm reference → `neo4j-gds-skill`; AGA limitations differ.

ML pipelines in sessions [graphdatascience 1.22]: use `gds.v2.pipeline.node_classification`, `gds.v2.pipeline.link_prediction`, `gds.v2.pipeline.node_regression`. `gds.pipeline.*` emits a deprecation warning inside a GDS Session — use `gds.v2.pipeline.*`.

### Step 6 — Async Job Polling

Long-running algorithms may return job handle. Poll until done:

```python
import time

job = gds.v2.page_rank.mutate(G, mutate_property="pagerank")

# If job object returned (async mode), poll explicitly:
if hasattr(job, "status"):
    while job.status() not in ("RUNNING_DONE", "FAILED", "CANCELLED"):
        time.sleep(5)
        print(f"Job status: {job.status()}")
    if job.status() != "RUNNING_DONE":
        raise RuntimeError(f"Algorithm job failed: {job.status()}")
```

Large graphs: check `.status()` before reading results.

Non-blocking API [graphdatascience 1.22]: `*_async` projection variants (e.g. `gds.v2.graph.project_native_async`) return a `ProjectionJobHandle`; `compute()` returns a `JobHandle`, write-back returns a `WriteJobHandle`. Handle methods: `.job_id()`, `.status()`, `.done()`, `.wait()`, `.result(wait=False)`. List/recover jobs:

```python
gds.v2.jobs.list()              # JobInfo per job: job_id, name
handle = gds.v2.jobs.get(G, job_id)   # concrete handle type for the job
```

### Step 7 — Retrieve Results

```python
# Stream node properties
result_df = gds.v2.graph.node_properties.stream(
    G,
    node_properties=["pagerank", "embedding"],
    db_node_properties=["name"],   # connected modes only
)
result_df.head(10)
```

Standalone mode: no `db_node_properties`; join source DataFrame:
```python
result_df = gds.v2.graph.node_properties.stream(G, ["pagerank"])
result_df.merge(nodes_df[["nodeId", "name"]], how="left")
```

### Step 8 — Write Back and Clean Up

```python
# Write node properties to connected Neo4j
gds.v2.graph.node_properties.write(G, ["pagerank", "embedding"])

# Write relationship properties
gds.v2.graph.relationships.write(G, "SIMILAR", ["score"])

# Query connected DB from session
gds.run_cypher("MATCH (n:Person) RETURN count(n)")

# Drop projected graph
gds.v2.graph.drop(G)

# Delete session
sessions.delete(session_name="my-analysis")
# or: gds.delete()
```

Write before delete; unwritten results lost when session closes.

### Session Management

```python
# List active sessions
from pandas import DataFrame
DataFrame(sessions.list())

# Reconnect to existing session
gds = sessions.get_or_create(session_name="my-analysis", memory=..., db_connection=...)
```

---

## Common Errors

| Error | Cause | Fix |
|---|---|---|
| `AuthenticationError` / 401 | Wrong `CLIENT_ID`/`CLIENT_SECRET` | Regenerate in Aura Console → Account → API credentials |
| `SessionNotFoundError` | Session expired (TTL exceeded) or name typo | `sessions.list()` to check; recreate session |
| `GraphNotFoundError` | Projection dropped or session reconnected without re-projecting | Re-run `gds.v2.graph.project()` or `gds.v2.graph.construct()` |
| Algorithm job `FAILED` | Memory limit exceeded or unsupported algorithm | Increase `SessionMemory`; check topological link prediction not used |
| `MemoryEstimationExceeded` | Graph larger than estimated | Re-estimate with actual counts; pick next tier up |
| Results empty after session reconnect | Results not written before session was closed | Always write/stream before `gds.delete()` |
| `String node properties not supported` | String column in nodes DataFrame | Drop string columns before `gds.v2.graph.construct()` |
| `AGA not enabled for project` | AGA feature not activated | Enable in Aura Console → project settings |

---

## References

Load on demand:
- [references/workflows.md](references/workflows.md) — full AuraDB and standalone workflow examples, Spark integration
- [references/limitations.md](references/limitations.md) — AGA vs embedded GDS feature table, SessionMemory tiers, cloud locations

## WebFetch

| Need | URL |
|---|---|
| AGA Python client docs | `https://neo4j.com/docs/graph-data-science-client/current/aura-graph-analytics/` |
| AGA Cypher API docs | `https://neo4j.com/docs/graph-data-science/current/aura-graph-analytics/cypher/` |
| Python client v2 docs | `https://neo4j.com/docs/graph-data-science-client/current/v2_endpoints/` |
| AuraDB tutorial notebook | `https://github.com/neo4j/graph-data-science-client/blob/main/examples/graph-analytics-serverless.ipynb` |
| GDS algorithm reference | `https://neo4j.com/docs/graph-data-science/current/algorithms/` |

---

## Checklist
- [ ] Aura API credentials created and set in environment (`AURA_CLIENT_ID`, `AURA_CLIENT_SECRET`)
- [ ] AGA feature enabled for Aura project (Aura Console → project settings)
- [ ] Memory estimated before session creation (`sessions.estimate(...)`)
- [ ] Cloud location chosen near data source
- [ ] `gds.v2.verify_session_connectivity()` called after session creation
- [ ] Connected sessions call `gds.v2.verify_db_connectivity()` when source DB access required
- [ ] Remote projection uses `gds.v2.graph.project(..., query)` with `gds.graph.project.remote(...)` inside query
- [ ] Remote projection graph name passed to endpoint, not remote function
- [ ] AuraDB Cypher API projection uses fifth config map for `memory` or `sessionId`
- [ ] Explicit Cypher API sessions use `gds.session.getOrCreate(...)`; implicit sessions dropped with projected graph
- [ ] TTL set to avoid unexpected costs on idle sessions
- [ ] Async algorithm jobs polled until `RUNNING_DONE` before reading results
- [ ] Results written back (connected modes) or streamed and persisted (standalone) before deletion
- [ ] Session deleted when done (`sessions.delete(...)` or `gds.delete()`)

---

## Supporting file: README.md

# neo4j-aura-graph-analytics-skill

Guides agents through **Aura Graph Analytics (AGA)** — Neo4j's serverless, on-demand GDS compute environment. Algorithms run in isolated ephemeral sessions billed per minute; no embedded GDS plugin required.

## What this skill covers

- Authentication with Aura API credentials (`GdsSessions`, `AuraAPICredentials.from_env()`)
- Memory estimation and `SessionMemory` tier selection
- Session creation, reconnection, listing, and deletion (`get_or_create`, TTL)
- Three data source modes: AuraDB-connected, self-managed Neo4j, standalone (Pandas/Spark)
- Remote graph projection (`gds.v2.graph.project(..., query)` with `gds.graph.project.remote()`)
- Python client v2 endpoint shape (`gds.v2.*`) without mixing camelCase/snake_case; v1 fallback when needed
- AuraDB Cypher API projection with `memory` or `sessionId`
- Standalone graph construction from DataFrames (`gds.v2.graph.construct()`)
- Algorithm execution: mutate / stream / write modes
- Async job polling pattern
- Result retrieval (`gds.v2.graph.node_properties.stream()`, `db_node_properties`)
- Write-back to connected Neo4j; cleanup before session deletion
- Common errors and mitigations (session expired, graph not projected, memory exceeded)

## Compatibility

`graphdatascience >= 1.15, < 2` · AuraDB Free, Professional, Business Critical, and VDC tiers · Python >= 3.8

## Not covered

- **Embedded GDS plugin** (Aura Pro, self-managed Neo4j) → `neo4j-gds-skill`
- **Cypher query authoring** → `neo4j-cypher-skill`
- **Snowflake Graph Analytics** → `neo4j-snowflake-graph-analytics-skill`

## Install

```bash
npx skills add https://github.com/neo4j-contrib/neo4j-skills --skill neo4j-aura-graph-analytics-skill
```

---

## Supporting file: references/limitations.md

# AGA vs Embedded GDS — Feature Comparison

| Feature | AGA (serverless) | GDS plugin (embedded) |
|---|---|---|
| Topological link prediction | ❌ Not supported | ✅ |
| ML model persistence across sessions | ❌ Session-local only | ✅ Persistent in model catalog |
| Cypher API (`CALL gds.*`) | ✅ AuraDB attached sessions only; limited vs plugin | ✅ |
| Non-Neo4j data sources | ✅ Pandas, Spark, Arrow | ❌ |
| Aura BC / VDC | ✅ | ❌ |
| Aura Pro | ❌ | ✅ |
| AuraDB Free | ✅ max `m_2GB`, 1 concurrent session, unbilled | ❌ |
| Billing | Per session-minute (Free and Pro Trial unbilled) | Included in AuraDB |
| DB performance isolation | ✅ Full isolation | ❌ Shares DB resources |

## SessionMemory Tiers

`m_2GB`, `m_4GB`, `m_8GB`, `m_16GB`, `m_24GB`, `m_32GB`, `m_48GB`, `m_64GB`, `m_96GB`, `m_128GB`, `m_192GB`, `m_256GB`, `m_384GB`, `m_512GB` — `SessionMemory.all_values()` lists them

Caps per AuraDB tier:

| AuraDB tier | Max session memory | Max concurrent sessions |
|---|---|---|
| Free | 2 GB | 1 |
| Pro Trial | 8 GB | 3 |
| Professional / Business Critical | 128 GB | 100 |
| Virtual Dedicated Cloud | 512 GB | 100 |

## AlgorithmCategory Values

`CENTRALITY`, `COMMUNITY_DETECTION`, `SIMILARITY`, `PATH_FINDING`, `NODE_EMBEDDING`

## Available Cloud Locations

```python
print(sessions.available_cloud_locations())
```

Common: `CloudLocation("gcp", "europe-west1")`, `CloudLocation("gcp", "us-east1")`, `CloudLocation("aws", "us-east-1")`

---

## Supporting file: references/workflows.md

# AGA Full Workflow Examples

## AuraDB — PageRank + FastRP → Write Back

```python
from graphdatascience.session import (
    AuraAPICredentials, GdsSessions, DbmsConnectionInfo,
    SessionMemory, AlgorithmCategory
)
from datetime import timedelta
import os

# 1. Auth
sessions = GdsSessions(api_credentials=AuraAPICredentials.from_env())

# 2. Size
memory = sessions.estimate(
    node_count=500_000,
    relationship_count=2_000_000,
    algorithm_categories=[AlgorithmCategory.CENTRALITY, AlgorithmCategory.NODE_EMBEDDING],
)

# 3. Session
gds = sessions.get_or_create(
    session_name="prod-analysis",
    memory=memory,
    db_connection=DbmsConnectionInfo.from_env(),
    ttl=timedelta(hours=4),
)
gds.v2.verify_session_connectivity()
gds.v2.verify_db_connectivity()

# 4. Project
query = """
    CALL () {
        MATCH (p:Person)
        OPTIONAL MATCH (p)-[r:KNOWS]->(p2:Person)
        RETURN p AS source, r AS rel, p2 AS target,
               p {.score} AS sourceNodeProperties,
               p2 {.score} AS targetNodeProperties
    }
    RETURN gds.graph.project.remote(source, target, {
        sourceNodeLabels: labels(source),
        targetNodeLabels: labels(target),
        sourceNodeProperties: sourceNodeProperties,
        targetNodeProperties: targetNodeProperties,
        relationshipType: type(rel)
    })
"""

G, _ = gds.v2.graph.project(
    graph_name="social",
    query=query,
    undirected_relationship_types=["KNOWS"],
)
# V1 fallback: gds.graph.project(graph_name="social", query=query, undirected_relationship_types=["KNOWS"])

# 5. Analyse
gds.v2.page_rank.mutate(G, mutate_property="pagerank")
gds.v2.fast_rp.mutate(G, embedding_dimension=128, mutate_property="embedding",
                      feature_properties=["pagerank"], random_seed=42)

# 6. Write back
gds.v2.graph.node_properties.write(G, ["pagerank", "embedding"])

# 7. Cleanup
sessions.delete(session_name="prod-analysis")
```

## Standalone — Pandas DataFrame → Community Detection

```python
import pandas as pd
from graphdatascience.session import AuraAPICredentials, GdsSessions, SessionMemory, CloudLocation
from datetime import timedelta

sessions = GdsSessions(api_credentials=AuraAPICredentials.from_env())

gds = sessions.get_or_create(
    session_name="csv-analysis",
    memory=SessionMemory.m_4GB,
    ttl=timedelta(hours=1),
    cloud_location=CloudLocation("gcp", "europe-west1"),
)

nodes = pd.read_csv("nodes.csv")   # nodeId (int), labels (str)
edges = pd.read_csv("edges.csv")   # sourceNodeId, targetNodeId, relationshipType

G = gds.v2.graph.construct("my-graph", nodes, edges)

gds.v2.louvain.mutate(G, mutate_property="community")

result = gds.v2.graph.node_properties.stream(G, ["community"])
output = result.merge(nodes[["nodeId", "name"]], how="left")
print(output.sort_values("community"))

gds.delete()
```

## Multiple Node/Relationship DataFrames

```python
G = gds.v2.graph.construct("multi-graph", [nodes1, nodes2], [rels1, rels2])
```

## Spark Integration

```python
pip install "graphdatascience>=1.18" pyspark

arrow_client = gds.arrow_client()
# Use arrow_client with mapInArrow for large Spark DataFrames
```

See [Spark Tutorial Notebook](https://github.com/neo4j/graph-data-science-client/blob/main/examples/graph-analytics-serverless-spark.ipynb).
