Metadata Filters

Meaning Plus Rules

Real searches combine similarity with hard rules: "running shoes" but only in stock, under ₹3,000, category = footwear; or policy chunks only for the customer's country. Store these as metadata (payload) next to each vector and filter on them. Never rely on the embedding to respect a price limit.

Filter, Then Rank

Example

Similarity scores are sample values for the query "comfortable running shoes":

products = [
    {"id": "P1", "name": "Stride Pro running shoe",  "price": 2499, "in_stock": True,  "score": 0.88},
    {"id": "P2", "name": "AirMax trail runner",      "price": 7999, "in_stock": True,  "score": 0.86},
    {"id": "P3", "name": "Stride Lite running shoe", "price": 1799, "in_stock": False, "score": 0.84},
    {"id": "P4", "name": "Walkeasy sports sandal",   "price": 999,  "in_stock": True,  "score": 0.52},
    {"id": "P5", "name": "Cushion jogger",           "price": 2999, "in_stock": True,  "score": 0.79},
]

def search(items, k=3, **filters):
    ok = [p for p in items
          if p["price"] <= filters.get("max_price", float("inf"))
          and (p["in_stock"] or not filters.get("in_stock_only"))]
    return [(p["id"], p["name"], p["price"]) for p in sorted(ok, key=lambda p: -p["score"])[:k]]

print("no filter      :", search(products))
print("<= 3000, stock :", search(products, max_price=3000, in_stock_only=True))

Output

no filter      : [('P1', 'Stride Pro running shoe', 2499), ('P2', 'AirMax trail runner', 7999), ('P3', 'Stride Lite running shoe', 1799)]
<= 3000, stock : [('P1', 'Stride Pro running shoe', 2499), ('P5', 'Cushion jogger', 2999), ('P4', 'Walkeasy sports sandal', 999)]

Note: Pre-filtering (filter, then search) is exact but can be slow with very selective filters; post-filtering (search top 100, then filter) is fast but may return fewer than k results. Vector databases like Qdrant and Pinecone handle this inside the index.