Storing and searching
In Qdrant, data is stored as Points. Each Point has three parts: an ID (unique identifier), a Vector (the embedding), and a Payload (metadata like the original text, category, or any other data you want to attach).
Upsert is a combination of "update" and "insert." If a point with that ID already exists, it gets updated with the new data. If it does not exist, it gets inserted as a new point. This makes it safe to re-run your ingestion pipeline without creating duplicates.
from qdrant_client.models import PointStruct
# Each policy gets a category in its payload for filtering later
policies = [
{"text": "All orders can be refunded within 30 minutes of purchase.", "category": "billing"},
{"text": "Gift cards are available in denominations of $25, $50, and $100.", "category": "gift-cards"},
{"text": "We offer 10% discount for orders above $50.", "category": "billing"},
{"text": "Our restaurant is open Monday to Saturday, 11 AM to 10 PM.", "category": "hours"},
{"text": "We are closed on Sundays and public holidays.", "category": "hours"},
]
# Embed all policy texts
resp = litellm.embedding(
model=EMBEDDING_MODEL,
input=[p["text"] for p in policies]
)
# Create points with ID, vector, and payload
points = []
for i, p in enumerate(policies):
points.append(PointStruct(
id=i,
vector=resp.data[i]["embedding"],
payload=p
))
# Upsert (insert or update) into Qdrant
client.upsert(
collection_name="green_bites_policies",
points=points
)
print(f"Uploaded {len(points)} points to Qdrant!")Embed and store restaurant policies in Qdrant
Now that our policies are stored as vectors in Qdrant, we can search them using natural language. The query gets embedded into a vector, and Qdrant finds the stored points closest to it, all in milliseconds.
# Search with a natural language question
query = "Can I get a gift card for my friend?"
query_resp = litellm.embedding(model=EMBEDDING_MODEL, input=[query])
results = client.query_points(
collection_name="green_bites_policies",
query=query_resp.data[0]["embedding"],
limit=2
)
for point in results.points:
print(f"Score: {point.score:.4f} | {point.payload['text']}")
# Score: 0.7102 | Gift cards are available in $25, $50, $100.Search for relevant policies using a natural language query
An LLM cannot read 768 floating-point numbers and understand them as text. The vector is only used for searching and finding which documents are most relevant. The payload carries the actual human-readable text that gets injected into the prompt. Think of it like a library: the catalog (vectors) helps you find the right book, but you still need to read the book (payload) itself.
Quiz: Quiz
Loading practice…
Matching exercise: Match Qdrant concepts
Loading practice…
Ordering exercise: Vector store workflow
Loading practice…