05 - Use the change feed to trigger embedding refresh
Use the change feed to trigger embedding refresh.
Use the change feed to trigger embedding refresh
This is one of the most critical concepts for taking an AI application from "it works on my machine" to "it works perfectly in production."
When a document's text changes, its old vector embedding becomes useless. If you don't update the embedding, your search results will be inaccurate. Here is how we fix that automatically, without writing complex polling scripts.
1. The Core Problem & The Solution
The Problem: An engineer edits a Troubleshooting Guide in your support portal. The text is new, but the vector numbers in the database are still mathematically pointing to the old text. The Solution: Cosmos DB has a built-in feature called the Change Feed. It is a persistent, ordered log of every Insert and Update in your database.
- Why it's awesome: It's enabled by default. If your app goes offline for an hour, the Change Feed remembers everything. When you come back online, it hands you the exact list of documents that changed.
How to Consume Changes: Push vs. Pull
- The Push Model (Recommended): The database automatically pushes changes to your code the moment they happen. This is usually built using Azure Functions. It's fully automated and handles scaling for you.
- The Pull Model: Your code manually "polls" the database asking, "Anything new?" You'd use this only if you want to run a batch job once a night.
2. The Lease Container Concept
For an Azure Function to listen to the Change Feed, it requires a second, separate Cosmos DB container called a Lease Container.
Think of it as a coordinator. If you have 5 instances of your Azure Function running, the Lease container acts as a "bookmark" to ensure Instance A reads Partition 1, Instance B reads Partition 2, and no two instances process the exact same document at the exact same time. It also remembers where you left off if a server crashes (Checkpointing).
3. Saving Money: Selective Embedding Refresh
Calling the OpenAI API costs money and compute time. If a user updates the "status" of a document from Draft to Published, the actual meaning of the text didn't change. You shouldn't waste money regenerating the vector.
The Fix: We use a contentHash pattern. Create a SHA256 Hash of the text content and save it in the document. When a change happens, hash the new text. If the new hash equals the old hash, skip the OpenAI call!
The Optimized Document Structure
Here is exactly how you would structure the JSON document inside Azure Cosmos DB to support this Selective Embedding Refresh pattern:
{
"id": "doc_user101_item456",
"userId": "user101",
"title": "Cosmos DB Architecture Guide",
"content": "Azure Cosmos DB handles horizontal scaling via partition keys...",
"status": "Published",
"lastUpdated": "2026-09-17T23:50:00Z",
"contentHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"embedding": [
0.00231,
-0.01452,
0.08912,
-0.00567
]
}status: Changing this value triggers an update in Cosmos DB, but your backend code will immediately see that thecontentHashremains unchanged.contentHash: A computed SHA-256 string generated only from the text properties that matter (title + content).embedding: The heavy, expensive array of vector numbers generated by OpenAI.
4. The Complete Real-Time Architecture
When dealing with high volumes of updates, directly calling OpenAI from the Change Feed trigger can cause rate-limiting issues. A brilliant architectural pattern is to use the Change Feed to drop a "ticket" into an Azure Storage Queue, and have a separate background worker safely process that queue at a controlled speed.
Here is the exact step-by-step flow showing how Cosmos DB, the Queue, and OpenAI work together when a document is updated:
Walkthrough of the Data Transformation
-
At the start (Cosmos DB): The user saves a document containing text content.
{ "id": "doc-123", "content": "Cosmos DB scales horizontally." } -
In the Queue: A temporary line item is created to act as a reminder.
"Please generate embedding for doc-123" -
The Background Worker steps in: It reads the queue ticket, looks up "doc-123" in Cosmos DB, extracts the text string, and sends only that text string to OpenAI.
-
Inside OpenAI: OpenAI's sole job is to act as a translator. The model processes the string and returns a vector array.
[0.0123, -0.4567, 0.8912] -
Back to Cosmos DB: The worker updates the original document, safely packing the OpenAI numbers into it.
{ "id": "doc-123", "content": "Cosmos DB scales horizontally.", "embedding": [0.0123, -0.4567, 0.8912] }
5. Python Implementation Example
Here is a clean Python snippet using the standard hashlib library to demonstrate exactly how to generate and compare this contentHash before making an expensive API call.
import hashlib
def compute_content_hash(title, content):
"""Compute SHA-256 hash of the content used for embedding generation."""
text_content = f"{title} {content}"
return hashlib.sha256(text_content.encode('utf-8')).hexdigest()
def process_change(new_document, old_document):
# 1. Calculate the hash of the incoming text
new_hash = compute_content_hash(new_document.get('title', ''), new_document.get('content', ''))
# 2. Check the Guard Condition
old_hash = old_document.get('contentHash') if old_document else None
if new_hash == old_hash:
print("Hash matches! Skipping OpenAI call. Metadata-only update.")
# Just update status/metadata in DB and keep existing embedding
return
print("Content changed. Calling OpenAI for new embedding...")
# 3. Call OpenAI API here
# new_embedding = call_openai(...)
# 4. Save the new hash and embedding to the document
new_document['contentHash'] = new_hash
# new_document['embedding'] = new_embedding
# container.upsert_item(new_document)6. Error Handling & Idempotency
Idempotency means "if this code accidentally runs twice, it won't break anything."
- Change Feeds can sometimes deliver the same change twice during failovers. Fortunately, generating an embedding from the same text twice just gives you the same math numbers, so it's perfectly safe.
- Watch out for Deletes: The Change Feed might say "Doc 123 updated!" but by the time your worker reads the queue ticket, the user might have deleted Doc 123. You must write a
try/exceptblock to catchCosmosResourceNotFoundErrorso your code doesn't crash.
04 - Combine vector similarity results with metadata filtering
Combine vector similarity results with metadata filtering.
06 - Exercise - Build a semantic search application with Azure Cosmos DB for NoSQL
Master the AI-200 and DP-420 exam concepts for Vector Embeddings, diskANN indexing, and Semantic Search in Azure Cosmos DB.
