What is index rebuilding and vector freshness?

Short answer: It is keeping the search index current as memories are added, updated, or deleted, often with a short lag.

HNSW graphs cannot cheaply rewrite every neighbor link on each change. Systems batch or defer updates so writes stay fast while search may briefly see a slightly stale view. Memory stores churn far more than static document corpora, so freshness machinery matters more. Engram depends on prompt index catch-up so superseded facts stop surfacing after resolution.

Approximate and exact search were both discussed as if the underlying collection sat still while a query ran. Real memory stores never actually hold still. New memories get added constantly, existing ones get updated or superseded, and some get deleted outright, and keeping a search index actually reflect that ongoing churn, without either going stale or grinding to a halt trying to stay current, is its own genuine engineering problem.

Why Can’t an Index Like HNSW Simply Be Updated in Place the Moment Something Changes?

The graph structure covered earlier in this Part connects each vector to a set of carefully chosen neighbors, decided when that vector was first inserted based on everything else already in the index at that moment. Deleting a vector outright would mean carefully re-threading every connection that used to run through it, a genuinely expensive operation if done immediately and individually for every single deletion as it happens. Updating a vector’s content usually means its new embedding belongs somewhere different in the space entirely, effectively requiring the old version to be removed and a new one inserted fresh, rather than simply overwriting a value in place.

How Do Well-Built Systems Avoid Paying This Cost Immediately for Every Single Change?

A common pattern marks a deleted or superseded vector as removed without immediately doing the expensive work of repairing the graph around it, a technique often called tombstoning. The tombstoned entry gets hidden from search results right away, so nothing stale is ever actually returned to a query, but the more expensive work of actually repairing the graph’s connections gets deferred, handled later by a background cleanup process that runs periodically rather than on every single change as it happens. This separates two genuinely different concerns: making sure stale content never gets returned, which has to happen immediately, and actually reclaiming the space and repairing the graph’s internal structure, which can reasonably wait and be batched more efficiently.

What Happens Between the Moment Something Changes and the Moment the Index Actually Catches Up?

Depending on how a specific system is built, there can be a brief window where a newly added or updated memory hasn’t yet been fully incorporated into the searchable index, even though it’s already been safely recorded elsewhere. Systems that process indexing asynchronously, queuing updates and applying them to the search structure slightly after the fact rather than instantly in lockstep with every single write, trade a small, usually brief delay in searchability for meaningfully better write throughput, especially valuable when a large amount of new content arrives at once. This tradeoff is deliberate: instant search availability on every single write, if forced synchronously, would slow down the exact writes it’s trying to make instantly searchable, while a small, well-managed delay in the other direction rarely causes real problems for how memory actually gets used in practice.

Does This Freshness Concern Apply Differently to Memory Compared to Static, Rarely-Changing Documents?

It applies with considerably more force. A static knowledge base of reference documents might genuinely change only occasionally, making index freshness a comparatively minor, infrequent concern. A memory store, by its very nature as covered throughout the earlier Parts of this knowledge base, is expected to change constantly: new facts extracted continuously, old facts reconciled and superseded as circumstances change, entries actively forgotten once they’ve outlived their usefulness. This means the freshness machinery covered in this chapter isn’t a peripheral concern for a genuinely active memory system, it’s load-bearing infrastructure that has to work correctly and continuously for memory to actually behave the way earlier Parts of this knowledge base described it should.

How Does Weaviate Engram Rely on This Underlying Freshness Machinery to Keep Memory Search Trustworthy?

Weaviate Engram’s reconciliation step, which supersedes outdated facts as new information arrives, depends directly on the underlying index actually reflecting those changes promptly and correctly, since a reconciliation that updates a stored fact accomplishes nothing if a stale, superseded version keeps surfacing in search results anyway. Consider a professional sports team’s roster and scouting assistant, where player status changes constantly, trades, injuries, and performance updates arriving continuously throughout a season:

from engram import EngramClient

client = EngramClient(api_key=os.environ["ENGRAM_API_KEY"])

client.memories.add(
    "Starting shortstop currently listed as day-to-day with a minor hamstring strain, expected back within a week based on the athletic trainer's latest assessment.",
    properties={"team_id": "roster-central-division"},
)

Two days later, an updated assessment supersedes this exact status:

client.memories.add(
    "Updated assessment: the shortstop's hamstring strain has fully resolved, cleared for full contact practice as of this morning, expected to start tomorrow's game.",
    properties={"team_id": "roster-central-division"},
)

results = client.memories.search(
    query="What's the current status on the shortstop's injury?",
    properties={"team_id": "roster-central-division"},
)

A coaching staff member relying on this search needs the current, cleared status returned reliably, not the outdated day-to-day assessment from two days earlier still lingering somewhere in a stale index. This is exactly why the freshness machinery covered throughout this chapter matters so directly for memory specifically: reconciliation resolving a contradiction correctly at the data layer only matters if the underlying search index actually reflects that resolution promptly, rather than continuing to surface the outdated version simply because the index’s internal structure hadn’t yet caught up with what had already changed.

Keeping an index fresh as its underlying content changes is a structural, mechanical concern. A related but subtler problem persists even when an index is perfectly, promptly up to date: the embedding model itself, and the sense of meaning it encodes, can quietly drift over time in ways that have nothing to do with how current the index’s data actually is. Our next chapter, What is embedding drift?, takes up exactly that subtler problem.