---
title: "Spatial Graph RAG for the Physical World"
url: "https://wherobots.com/blog/spatial-graph-rag/"
description: "Graph RAG grounds LLMs in a knowledge graph of entities and relationships. Learn how Spatial Graph RAG builds that graph from physical-world data with spatial SQL."
published: "2026-06-09"
modified: "2026-10-19"
---

# Spatial Graph RAG for the Physical World

## Introduction

RAG (Retrieval Augmented Generation) has addressed one of AI’s biggest challenges for enterprise users: missing or hallucinating empirical business and real world context . Instead of generating answers from nothing, RAG retrieves relevant documents and feeds them to the model as context. It works. Ask an AI about your company’s Q4 revenue, and RAG pulls the earnings report before answering.

Key takeaways

- Standard Graph RAG builds knowledge graphs from text. Spatial Graph RAG builds them from the physical world: containment, proximity, adjacency, and intersection, using spatial SQL instead of NLP.
- The most consequential physical-world relationships are often not written down.
- The pipeline is two layers in one WherobotsDB session: distributed spatial SQL materializes node and edge tables into Apache Iceberg, then GraphFrames traverses them (connected components, motif finding, neighborhood expansion). No separate graph database is required.
- Microsoft Research's GraphRAG paper (Edge et al., 2024) reported 72–83% comprehensiveness win rates versus standard RAG on questions requiring synthesis across entire datasets. GeoLLM (Manvi et al., ICLR 2024) showed that querying an LLM with coordinates alone consistently fails unless structured, map-derived context is provided.
- You cannot load 2.6 billion Overture building geometries into Neo4j and compute containment with 1.2 billion places. Edge generation at that scale is what WherobotsDB and Apache Sedona are built for.
- The Overture Maps Foundation itself uses them for monthly global releases. Even in a dense urban area, a retrieved subgraph is typically 10–50 nodes.

But RAG has a blind spot. It retrieves *documents*, flat chunks of text ranked by semantic similarity. It doesn’t understand *relationships between assets*. It doesn’t know that your VP of Sales reports to the CRO, or that Product A competes with Product B, or that the supplier in Shenzhen feeds the factory in Guadalajara that ships to the warehouse in Memphis. You can leave the connections to be made by the LLM, but seeding control over simple facts to a nondeterministic process is not the best business decision.

Graph RAG fixes this by building a knowledge graph of entities and their relationships, then retrieving compact subgraphs, not just documents, as context for the model. It’s one of the fastest-growing concepts in AI infrastructure, and for good reason: it makes AI dramatically better at reasoning about connected information.

There’s just one problem. Every Graph RAG implementation today builds knowledge graphs from text, semantics, and [ontologies](https://wherobots.com/discover/ontology/). Documents, wikis, databases, web pages. The relationships are extracted from language.

But the most consequential relationships in the physical world aren’t always written down. They’re spatial. Which building contains which addresses . Which buildings area accessible by which road. Which facilities sit inside which flood zone. Which agriculture fields are adjacent to which water sources and who owns those water rights. These relationships exist in geometry, not in sentences… No amount of document retrieval will surface them.

This is the case for Spatial Graph RAG: building knowledge graphs from the physical world, using spatial operations instead of NLP, and retrieving spatial relation-anchored subgraphs that ground AI in physical reality.

---

## What is Graph RAG?

Graph RAG (also written GraphRAG) is a retrieval-augmented generation method that retrieves connected entities and relationships from a knowledge graph and passes them to a large language model as context. It extends standard RAG by adding a knowledge graph layer (nodes and edges) between the raw data and the language model.

**Standard RAG**:

1. User asks a question
2. System searches a vector database for semantically similar text chunks
3. Top-K chunks are injected into the LLM prompt as context
4. LLM generates an answer grounded in those chunks

**Graph RAG**

1. User asks a question
2. System identifies relevant *entities (nodes)* in a knowledge graph
3. System traverses the graph’s edges and nodes to retrieve a compact *subgraph* of connected entities, relationships, and provenance
4. Subgraph (entities (the nodes) + relationships (the edges) + evidence (relationship provenance) is injected into the LLM prompt
5. LLM generates an answer grounded in structured, relational context

The difference matters. Standard RAG might retrieve three paragraphs that each mention a company name. Graph RAG retrieves the company node, its relationships to subsidiaries, suppliers, competitors, and executives, and the evidence supporting each relationship. The model doesn’t just get text fragments, it gets structured understanding.

Microsoft Research’s GraphRAG paper ([Edge et al., 2024](https://arxiv.org/abs/2404.16130)) demonstrated this dramatically: on questions requiring synthesis across entire datasets, Graph RAG achieved 72-83% comprehensiveness win rates versus standard RAG.

**Reference:** [From Local to Global: A Graph RAG Approach to Query-Focused Summarization](https://arxiv.org/abs/2404.16130) — Microsoft Research, 2024

---

## The Problem: Why AI Gets Spatial Relationships Wrong

Ask a language model “What’s at this address?” or “Is this restaurant inside that building?” or “Which of these two locations is closer to the highway?” and you’ll often get confident, specific, wrong answers.

This isn’t a model intelligence problem. It’s a context problem. The model has no spatial context, no understanding of physical relationships between real-world entities.

Research bears this out directly. GeoLLM (Manvi et al., ICLR 2024) demonstrated that **querying an LLM with geographic coordinates alone consistently fails**, even when the model contains relevant geographic knowledge internally. Performance improves substantially only when [structured, map-derived context](https://wherobots.com/discover/context-engineering/) is provided alongside the query. In other words: the problem isn’t that LLMs don’t know about geography , it’s that they can’t use that knowledge **without grounded relational structure to anchor it**.

The root cause goes deeper than missing map data. Place understanding is fundamentally relational:

- A **business** is inside a **building**, which is on a **street**, which connects to a **road network**, which is in an **administrative boundary**
- An **address** might match multiple **buildings**, and the correct assignment depends on **access points** and **proximity** to road segments
- Two **[POI records](https://wherobots.com/discover/poi-data/)** might be duplicates, a brand and a venue, or distinct businesses in the same building, and the evidence for each interpretation is spatial
- A business is accessible via a building that is accessible via a the transportation network who’s navigation is weighted by current traffic load

These relationships can be ambiguous, inconsistent across data sources, and impossible to resolve from text alone. This is exactly the problem knowledge graphs solve in the document world and it’s exactly the problem spatial knowledge graphs solve for the physical world.

---

## From Graph RAG to Spatial Graph RAG

Spatial Graph RAG applies the Graph RAG architecture to physical-world data, using spatial operations instead of NLP to construct the knowledge graph, and location-anchored queries instead of text queries to retrieve subgraphs.

The pipeline has three stages. The first two are distinct engineering layers that work in sequence: distributed, transformations, aggregations, data generation, and [spatial joins](https://wherobots.com/discover/spatial-join/) *generate* the nodes and edges, then graph operations *traverse* them.

### Step 1: Generate graph edges with spatial SQL

Spark and Spatial SQL comprise the graph creation factory. Using [WherobotsDB](https://wherobots.com/products/compute/)‘s spatial functions on Overture Maps data, we materialize node and edge tables into Apache Iceberg. Each edge carries provenance whether it was asserted by a source dataset, derived by a spatial join, or scored based on multiple signals .

**Containment edges** (place → in building):

```
containment_edges = sedona.sql("""
    SELECT
        p.id          AS src,
        b.id          AS dst,
        'CONTAINED_IN' AS relationship,
        ST_Area(ST_Intersection(p.geometry, b.geometry))
            / ST_Area(p.geometry) AS overlap_pct,
        'spatial_join' AS provenance
    FROM wherobots_open_data.overture_maps_foundation.places_place p
    JOIN wherobots_open_data.overture_maps_foundation.buildings_building b
      ON ST_Contains(b.geometry, p.geometry)
""")
```

**Proximity edges** (place → near road access point), using WherobotsDB’s native `ST_KNN` for nearest-neighbor joins at scale:

```
# ST_KNN is WherobotsDB's distributed k-nearest-neighbor join
# (available in WherobotsDB and Apache Sedona 1.7+)
access_edges = sedona.sql("""
    SELECT
        p.id            AS src,
        s.id            AS dst,
        'ACCESSED_VIA'  AS relationship,
        ST_Distance(p.geometry, s.geometry) AS distance,
        'knn_join'      AS provenance
    FROM wherobots_open_data.overture_maps_foundation.places_place p
    INNER JOIN wherobots_open_data.overture_maps_foundation.transportation_segment s
      ON ST_KNN(p.geometry, s.geometry, 1, false)
""")
```

**Admin containment edges** (building → in administrative boundary):

```
admin_edges = sedona.sql("""
    SELECT
        b.id        AS src,
        d.id        AS dst,
        'IN_BOUNDARY' AS relationship,
        d.subtype   AS boundary_type,
        'spatial_join' AS provenance
    FROM wherobots_open_data.overture_maps_foundation.buildings_building b
    JOIN wherobots_open_data.overture_maps_foundation.divisions_division_area d
      ON ST_Within(b.geometry, d.geometry)
    WHERE d.subtype IN ('locality', 'county', 'region')
""")
```

All edge tables are unioned and written to Iceberg for durability and incremental updates:

```
unified_edges = (
    containment_edges.withColumn("edge_type", lit("contained_in"))
    .union(access_edges.withColumn("edge_type", lit("accessed_via")))
    .union(conflation_edges.withColumn("edge_type", lit("likely_same_as")))
    .union(admin_edges.withColumn("edge_type", lit("in_boundary")))
)

unified_edges.writeTo("my_catalog.spatial_graph.edges").createOrReplace()
```

### Step 2: Run graph operations with GraphFrames

Node and Edge tables are not a graph, they’re raw material. GraphFrames, the DataFrame-native graph library for Apache Spark, turns those tables into a traversable graph inside the same WherobotsDB session. No separate graph database required.

**Construct the GraphFrame:**

```
from graphframes import GraphFrame
from pyspark.sql import functions as F

# Vertex table: union all entity types with a common schema
nodes = sedona.sql("""
    SELECT *
    FROM wherobots_open_data.overture_maps_foundation.nodes
""")

# Edge table: union all relationship types
edges = sedona.sql("""
    SELECT *
    FROM my_catalog.spatial_graph.edges
""")

g = GraphFrame(vertices, edges)
```

**Connected components for conflation clustering:**

```
# Find clusters of likely-same-entity candidates — each component
# represents a set of records that may refer to the same real-world place
sc.setCheckpointDir("/tmp/graphframes-checkpoints")
components = g.connectedComponents()

# Records sharing a component_id are conflation candidates
components.filter(F.col("entity_type") == "place") \\
          .groupBy("component") \\
          .count() \\
          .filter("count > 1") \\
          .show()
```

**Motif finding for multi-hop subgraph extraction:**

GraphFrames’ motif syntax lets you query for structural patterns — the same way you’d write a path query in a graph database, but natively in Spark:

```
# Find: place → contained_in → building → in_boundary → admin_area
# This is the "what's here?" retrieval pattern for LLM context
place_context = g.find("(place)-[e1]->(building); (building)-[e2]->(admin)") \\
    .filter("e1.relationship = 'CONTAINED_IN' AND e2.relationship = 'IN_BOUNDARY'") \\
    .select("place", "e1", "building", "e2", "admin")
```

**Subgraph extraction anchored to a location (the RAG retrieval step):**

```
def retrieve_subgraph(anchor_id: str, hop_depth: int = 2):
    """
    Given an entity ID (building, place, or address), retrieve the
    connected subgraph up to hop_depth hops — this is the context
    bundle that gets passed to the LLM.
    """
    # Breadth-first expansion from the anchor node
    frontier = {anchor_id}
    subgraph_edges = []

    for _ in range(hop_depth):
        neighbors = g.edges.filter(
            F.col("src").isin(frontier) | F.col("dst").isin(frontier)
        )
        subgraph_edges.append(neighbors)
        new_nodes = neighbors.select("src").union(
            neighbors.select(F.col("dst").alias("src"))
        ).distinct()
        frontier = {row["src"] for row in new_nodes.collect()}

    from functools import reduce
    all_edges = reduce(lambda a, b: a.union(b), subgraph_edges).distinct()
    subgraph_vertices = g.vertices.filter(F.col("id").isin(frontier))

    return GraphFrame(subgraph_vertices, all_edges)

# Usage: retrieve context for a specific building
context_graph = retrieve_subgraph("building_id_4821", hop_depth=2)
```

Even in a dense urban area with thousands of entities, the relevant subgraph is small, typically 10–50 nodes with their connecting edges.

### Step 3: Ground the LLM in spatial evidence

The extracted subgraph replaces the flat text chunks that standard RAG provides. Instead of a paragraph about a restaurant, the model receives structured spatial evidence:

```
Entity: Joe's Pizza (place, confidence: 0.95)
→ CONTAINED_IN: Building #4821 (overlap: 99.2%, provenance: spatial_join)
→ ACCESSED_VIA: Carmine St segment (distance: 4.1m, provenance: knn_join)
→ LIKELY_SAME_AS: Joe's Pizza [OSM] (name_score: 0.94, distance: 3.2m)
→ IN_BOUNDARY: Greenwich Village → Manhattan → New York County
```

Now the model can answer “Is Joe’s Pizza inside that building?” with evidence, not guessing.

---

## Standard Graph RAG vs. Spatial Graph RAG

| Dimension | Standard Graph RAG | Spatial Graph RAG |
| --- | --- | --- |
| **Data source** | Documents, wikis, databases | Physical-world datasets (map data, imagery, sensor data) |
| **Entity extraction** | NLP (named entity recognition) | Spatial data themes (buildings, places, addresses, roads) |
| **Relationship extraction** | Text parsing, co-occurrence | Spatial operations (containment, proximity, adjacency, intersection) |
| **Edge generation** | NLP pipelines (spaCy, OpenIE) | Distributed spatial joins (Apache Sedona / WherobotsDB) |
| **Graph operations** | Graph databases (Neo4j, Neptune) | GraphFrames on Spark — same cluster, no separate DB |
| **Query anchor** | Text query, entity name | Coordinate, building ID, place, address |
| **Subgraph retrieval** | Entity traversal, community detection | Spatial neighborhood + motif queries (GraphFrames) |
| **Provenance** | Source document, page, paragraph | Source dataset, spatial operation, confidence score |
| **Hallucination reduced** | Factual claims about documents | Place claims, spatial relationships, address assignments |
| **Scale challenge** | Millions of documents | Billions of spatial features (planetary scale) |

---

## Inside the Stack: Why Spatial Graph RAG Needs Two Layers

The compute layer runs on [WherobotsDB](https://wherobots.com/blog/wherobotsdb-is-3x-faster-with-up-to-45-better-price-performance/), built for native spatial execution at scale. Standard graph databases (Neo4j, Amazon Neptune, TigerGraph) are built for entity-relationship traversal on pre-loaded graphs. They have no native ability to perform the distributed spatial joins needed to *construct* edges at planetary scale. You can’t load 2.6 billion Overture building geometries into Neo4j and ask it to compute containment relationships with 1.2 billion places.

Spatial Graph RAG needs two distinct capabilities in the same session:

1. **Edge and Node generatio**n: distributed spatial joins across billions of features stored as different geometry types. This is what [WherobotsDB](https://wherobots.com/products/compute/) and Apache Sedona are built for. The Overture Maps Foundation itself uses Wherobots and Apache Sedona to generate its monthly global data releases at scale.
2. **Graph operations**: connected components, shortest paths, motif queries, iterative traversal. This is what GraphFrames provides, natively on the same Spark session, treating graphs as DataFrames.

Running both inside WherobotsDB means the edge tables generated in Step 1 are immediately available to GraphFrames in Step 2 — no data movement, no format conversion, no separate system to operate.

### Why GraphFrames for Spatial Graph RAG

GraphFrames extends Spark DataFrames with graph-parallel primitives: connected components, PageRank, triangle count, shortest paths, and motif finding. For Spatial Graph RAG, the most important capabilities are:

- **Connected components** : for identifying conflation clusters (which records likely refer to the same real-world entity)
- **Motif finding**: for multi-hop structural queries like `(place)→(building)→(admin_area)` that power context retrieval
- **BFS/neighborhood expansion**: for bounded subgraph extraction anchored to a query location

The “graphs as tables” design (vertices and edges as DataFrames) maps directly onto the Iceberg edge tables generated by spatial SQL, which is why the two layers compose cleanly.

---

## Spatial Graph RAG Use Cases

### Place Q&A for AI Assistants

“What’s at this location?” “Is this business still open?”, questions AI handles poorly today. A spatial knowledge graph provides evidence-bearing subgraphs that make answers accurate and traceable.

### Conflation and Data Quality

Determining whether two records from different sources represent the same real-world entity. Spatial Graph RAG turns conflation from an irreversible merge into an inspectable, evidence-driven process, connected components expose the clusters, motif queries explain the evidence.

### Insurance Risk Assessment

Which properties are in flood zones, which are adjacent to wildfire-prone vegetation, which are accessed by roads that become impassable in storms.

### Autonomous Systems and HD Maps

Which lane connects to which intersection, which signs apply to which road segment. Graph-structured map data provides the relational context.

### Supply Chain Risk Intelligence

Facilities → nearby hazard zones, suppliers → upstream of disruption, routes → through chokepoints.

---

## Building Spatial Graph RAG From Overture Maps Data

The [Overture Maps Foundation](https://overturemaps.org/) provides the ideal source data, available directly in [The Wherobots Hub](https://wherobots.com/products/discover/). The pipeline:

1. **Load** Overture themes from the Wherobots Open Data Catalog (`wherobots_open_data.overture_maps_foundation.*`)
2. **Generate edges** via distributed spatial joins (WherobotsDB spatial SQL)
3. **Store** vertex and edge tables in Apache Iceberg (Havasu format)
4. **Construct graph** with GraphFrames — same Spark session, no separate DB
5. **Run graph operations** — connected components for conflation, motifs for context retrieval
6. **Serve subgraphs** as LLM context through the [Spatial AI Assistant](https://wherobots.com/blog/ai-agents-spatial-analytics-15-minute-train-ride/) or MCP integration

Every build enriches [The Global Hub](https://wherobots.com/products/discover/).

## Graph RAG FAQ

### What is Graph RAG?

Graph RAG, also written GraphRAG, is a retrieval-augmented generation method that retrieves connected entities and relationships from a knowledge graph and passes them to a large language model as context. The model receives the entities, the edges between them, and the evidence for each edge, so it can answer questions that depend on how facts connect.

### What is the difference between RAG and Graph RAG?

Standard RAG retrieves text chunks from a vector database, ranked by semantic similarity to the question. Graph RAG retrieves a subgraph: entities, their relationships, and the provenance of each relationship. Graph RAG suits multi-hop questions, such as which facilities depend on a supplier located inside a flood zone.

### What is Microsoft GraphRAG?

GraphRAG is an open-source library from Microsoft Research. It uses a language model to extract entities and relationships from text, groups them into communities, and summarizes each community. The 2024 paper by Edge et al. reported 72 to 83 percent comprehensiveness win rates over standard RAG on questions that span an entire dataset.

### What is Spatial Graph RAG?

Spatial Graph RAG builds the knowledge graph from physical-world data such as buildings, places, addresses, and roads. Spatial SQL generates the edges through containment, proximity, adjacency, and intersection joins. The language model then receives a subgraph that describes where things are and how they connect.

### Do you need a graph database for Graph RAG?

A graph database such as Neo4j or Amazon Neptune works for graphs that fit on one system. For graphs built from billions of spatial features, WherobotsDB generates node and edge tables with distributed spatial joins, and GraphFrames runs graph operations in the same Spark session.

### When should you use Graph RAG?

Use Graph RAG when answers depend on relationships across entities: supply chains, ownership, network topology, or physical containment and proximity. Standard RAG costs less for lookups that a single passage answers.

The next section summarizes the pipeline and the research behind it.

---

## Spatial Graph RAG: Key Points

- **Graph RAG** adds knowledge graph context to LLM reasoning
- **Standard Graph RAG** builds knowledge graphs from text. **Spatial Graph RAG** builds them from the physical world
- **AI gets spatial relationships wrong** because it has no structured spatial context — even when the model contains relevant geographic knowledge (GeoLLM, 2024)
- **The pipeline is two layers**: distributed spatial SQL generates edges; GraphFrames traverses them — both in the same WherobotsDB session
- **Provenance makes it auditable** — every edge carries evidence, every conflation candidate is inspectable
- The physical world is fundamentally relational. **Spatial Graph RAG gives AI the relationships it needs to reason about place.**

---

## References

- [From Local to Global: A Graph RAG Approach to Query-Focused Summarization](https://arxiv.org/abs/2404.16130) — Edge et al., Microsoft Research, 2024
- [GeoLLM: Extracting Geospatial Knowledge from Large Language Models](https://arxiv.org/abs/2310.06992) — Manvi et al., ICLR 2024
- [An Integrated API for Mixing Graph and Relational Queries](https://dl.acm.org/doi/10.1145/2960414.2960416) — Dave et al., GraphFrames / GRADES 2016
- [A Semantic-Spatial Aware Data Conflation Approach for Place Knowledge Graphs](https://doi.org/10.3390/ijgi13010030) — He et al., IJGI 2024
- [Overture Maps Foundation](https://overturemaps.org/)
- [Apache Sedona](https://sedona.apache.org/) — 80M+ downloads
- [GraphFrames GitHub](https://github.com/graphframes/graphframes)

Start Building with WherobotsDB

[Get Started](https://login.cloud.wherobots.com/sign-up)
