> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cognee.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Building the Global Context Index

> See how improve(build_global_context_index=True) builds a dataset-wide summary hierarchy, and how it extends that hierarchy incrementally as new data arrives

This guide shows you how to build a global context index over a dataset, inspect the summary hierarchy it produces, and then add more data and rebuild to see the index update incrementally instead of starting over.

## Before You Start

* Complete [Quickstart](/getting-started/quickstart) to understand basic operations
* Ensure you have [LLM Providers](/setup-configuration/llm-providers) configured
* Read [Global Context Index](/core-concepts/further-concepts/global-context-index) for the conceptual overview — this guide focuses on the runnable example, not the full parameter surface
* Be familiar with [`improve()`](/core-concepts/main-operations/improve)

## Code in Action

```python theme={null}
import asyncio

import cognee
from cognee.infrastructure.databases.graph import get_graph_engine

DATASET = "global_context_index_demo"

INITIAL_FACTS = [
    "Alice hikes in the Alps every summer.",
    "Bob sails along the Adriatic coast every summer.",
    "Alice says hiking helps her disconnect from work.",
    "Bob says sailing is the best way to unwind after a busy winter.",
    "Last year Alice hiked a new trail near Lake Como.",
    "Last year Bob sailed to a small island he had never visited.",
]

ADDITIONAL_FACT = "This year, Bob decided to join Alice's hiking trip to the Alps instead of sailing."


async def print_index_structure(label):
    graph_engine = await get_graph_engine()
    nodes_data, _edges_data = await graph_engine.get_graph_data()

    root = None
    buckets = []
    text_summary_count = 0

    for node_id, properties in nodes_data:
        node_type = properties.get("type")
        if node_type == "TextSummary":
            text_summary_count += 1
        elif node_type == "GlobalContextSummary":
            if properties.get("is_root"):
                root = (node_id, properties.get("text", ""))
            else:
                buckets.append((node_id, properties.get("text", "")))

    print(f"\n{label}")
    print(f"Source summaries: {text_summary_count} TextSummary nodes")
    print(f"Buckets: {len(buckets)}")
    for bucket_id, text in buckets:
        print(f"  - [{bucket_id}] {text[:60]}...")
    if root:
        print(f"Root [{root[0]}]: {root[1][:100]}...")


async def main():
    await cognee.remember(
        INITIAL_FACTS,
        dataset_name=DATASET,
        self_improvement=False,
    )
    await cognee.improve(dataset=DATASET, build_global_context_index=True)
    await print_index_structure("Index structure after the initial build:")

    await cognee.remember(
        ADDITIONAL_FACT,
        dataset_name=DATASET,
        self_improvement=False,
    )
    await cognee.improve(dataset=DATASET, build_global_context_index=True)
    await print_index_structure("Index structure after adding one more fact:")


if __name__ == "__main__":
    asyncio.run(main())
```

## What Just Happened

### Step 1: Ingest the Initial Facts

```python theme={null}
INITIAL_FACTS = [
    "Alice hikes in the Alps every summer.",
    "Bob sails along the Adriatic coast every summer.",
    "Alice says hiking helps her disconnect from work.",
    "Bob says sailing is the best way to unwind after a busy winter.",
    "Last year Alice hiked a new trail near Lake Como.",
    "Last year Bob sailed to a small island he had never visited.",
]

await cognee.remember(
    INITIAL_FACTS,
    dataset_name=DATASET,
    self_improvement=False,
)
```

Six short facts describe two people, the trips they take, and how they each feel about their favorite way to spend free time.

### Step 2: Build the Index

```python theme={null}
await cognee.improve(dataset=DATASET, build_global_context_index=True)
```

`improve()` runs its normal enrichment pass first, then builds the global context index on top: it groups the dataset's `TextSummary` nodes into **buckets**, and buckets into higher buckets, until everything fits under one **root** summary — see [Global Context Index](/core-concepts/further-concepts/global-context-index#how-it-works) for exactly what a bucket and a root are.

### Step 3: Inspect the Initial Structure

```python theme={null}
async def print_index_structure(label):
    graph_engine = await get_graph_engine()
    nodes_data, _edges_data = await graph_engine.get_graph_data()

    root = None
    buckets = []
    text_summary_count = 0

    for node_id, properties in nodes_data:
        node_type = properties.get("type")
        if node_type == "TextSummary":
            text_summary_count += 1
        elif node_type == "GlobalContextSummary":
            if properties.get("is_root"):
                root = (node_id, properties.get("text", ""))
            else:
                buckets.append((node_id, properties.get("text", "")))

    print(f"\n{label}")
    print(f"Source summaries: {text_summary_count} TextSummary nodes")
    print(f"Buckets: {len(buckets)}")
    for bucket_id, text in buckets:
        print(f"  - [{bucket_id}] {text[:60]}...")
    if root:
        print(f"Root [{root[0]}]: {root[1][:100]}...")


await print_index_structure("Index structure after the initial build:")
```

`print_index_structure()` reads the graph directly through `get_graph_engine().get_graph_data()` — see the **"Inspect extracted graph schema"** accordion (its "Python SDK" subsection) on the [Cognify](/core-concepts/main-operations/legacy-operations/cognify) page for exactly what it returns — a `(node_id, properties)` pair per node. The loop classifies each node by its `type`: a `TextSummary` just increments a counter, while a `GlobalContextSummary` is split into the single **root** (`is_root=True`) or a **bucket** (everything else), keeping each bucket's id alongside its text so you can compare it against the next build.

### Step 4: Add a Fact and Rebuild

```python theme={null}
await cognee.remember(
    ADDITIONAL_FACT,
    dataset_name=DATASET,
    self_improvement=False,
)
await cognee.improve(dataset=DATASET, build_global_context_index=True)
```

The new fact mentions Bob, hiking, and the Alps — entities already grouped together in Alice's bucket from the first build. Running `improve(build_global_context_index=True)` again does not start over — it only places this one new `TextSummary` node.

### Step 5: Inspect the Updated Structure

```python theme={null}
await print_index_structure("Index structure after adding one more fact:")
```

Compare the two printouts: `Source summaries` goes up by one, but the bucket that already covered Alice's hiking trips keeps the **exact same id** it had after Step 3 — proof that fact was added to that bucket rather than triggering a full rebuild. The root also keeps the same id (it's derived only from the dataset, never from its children), though its text is regenerated to reflect the new fact.

## Under the Hood

<Accordion title="How the Index Is Actually Built and Updated">
  * **How groupings are actually formed**: at level 0, `TextSummary` nodes land in the same bucket based on entity overlap — the more entities two summaries share, the more likely they're grouped together — weighted so entities that show up in almost every summary don't dominate the grouping. Every level above level 0 (bucket into higher bucket, up to the root) groups by **vector distance** between embeddings instead.
  * **Bucket capacity**: `improve()` hardcodes `max_bucket_size=4`, not exposed as a configurable option.
  * **Why ids stay stable**: a bucket's id is determined by the dataset, level, and its child ids *at the moment the bucket is created*. Adding a new child later mutates that bucket's contents in place — the id is never recomputed. The root's id depends only on the dataset id, never on its children, so it's stable for the life of the dataset even though its text gets regenerated whenever something changes underneath it.
  * **Higher levels**: buckets group up to `max_bucket_size` buckets each. If that still leaves more than `max_bucket_size` buckets, another level is built on top, repeating until the topmost level fits under a single root.
</Accordion>

<Columns cols={3}>
  <Card title="Global Context Index" icon="globe" href="/core-concepts/further-concepts/global-context-index">
    The full concept, configuration options, and when to use it
  </Card>

  <Card title="Improve" icon="sparkles" href="/core-concepts/main-operations/improve">
    Understand improve()'s other enrichment passes
  </Card>

  <Card title="Reading the Global Context Index" icon="search" href="/guides/global-context-index-recall">
    See how include\_global\_context\_index changes retrieval, once the index above exists
  </Card>
</Columns>
