पाठ 16 / 28

समर्पित Engine में Filtering: Qdrant

उन्हें केंद्र में रखकर बने engine में payload filters देखें।

Payload filters प्रमुख सुविधा हैं

Qdrant Rust में लिखा open-source vector database है। इसका मॉडल: points की collection, हर एक की ID, एक या अधिक vectors और JSON payload। आप vector आकार और दूरी metric के साथ collection बनाते हैं, points upsert करते हैं, और vector के साथ वैकल्पिक filter से query करते हैं जो payload fields पर must, should और must_not शर्तों (match, range, geo आदि) से बनता है। Qdrant की HNSW खोज filter-जागरूक है: वह graph पार करते हुए payload शर्तें जाँचती है (और जिन fields पर filter करते हैं उन पर payload indexes बनाने चाहिए), जो सीधे post-filtering के ख़ाली-परिणाम जाल से बचाता है। Python client में स्थानीय in-memory mode भी है, जो यहाँ उपयोग हुआ, बिना server चलाए वही API देता है, जो tests के लिए उत्कृष्ट है।

Qdrant: upsert, खोज, filter, delete, चलाकर

मैंने यह Python virtual environment में qdrant-client 1.19.1 (स्थानीय in-memory mode) और chromadb 1.5.9 (in-memory client) के साथ चलाया। Collection में चार points हैं। सादी query points 1, 4 और 2 लौटाती है (4 दूसरे tenant का है)। Tenant acme और वर्ष 2025 के filter के साथ सिर्फ़ points 1 और 3 योग्य हैं। Point 4 हटाने के बाद गिनती 4 से 3 हो जाती है। Local mode उपयोग हुआ है, इसलिए कोई server शामिल नहीं।

from qdrant_client import QdrantClient, models

client = QdrantClient(":memory:")              # local mode: same API as a server, nothing to install or run
client.create_collection("docs", vectors_config=models.VectorParams(size=3, distance=models.Distance.COSINE))
client.upsert("docs", points=[
    models.PointStruct(id=1, vector=[0.9, 0.1, 0.0], payload={"tenant": "acme", "year": 2025, "text": "leave policy 2025"}),
    models.PointStruct(id=2, vector=[0.8, 0.2, 0.1], payload={"tenant": "acme", "year": 2022, "text": "old leave policy"}),
    models.PointStruct(id=3, vector=[0.1, 0.9, 0.1], payload={"tenant": "acme", "year": 2025, "text": "travel and hotels"}),
    models.PointStruct(id=4, vector=[0.9, 0.0, 0.2], payload={"tenant": "beta", "year": 2025, "text": "beta confidential memo"}),
])
print("points:", client.count("docs").count)

hits = client.query_points("docs", query=[1, 0, 0], limit=3).points
print("no filter :", [(h.id, round(h.score, 3)) for h in hits])

only_acme_2025 = models.Filter(must=[
    models.FieldCondition(key="tenant", match=models.MatchValue(value="acme")),
    models.FieldCondition(key="year", match=models.MatchValue(value=2025)),
])
hits = client.query_points("docs", query=[1, 0, 0], query_filter=only_acme_2025, limit=3).points
print("with filter:", [(h.id, h.payload["text"]) for h in hits])

client.delete("docs", points_selector=models.PointIdsList(points=[4]))
print("after delete:", client.count("docs").count)

Output:

points: 4
no filter : [(1, 0.994), (4, 0.976), (2, 0.963)]
with filter: [(1, 'leave policy 2025'), (3, 'travel and hotels')]
after delete: 3

Payload indexes बनाएँ

समर्पित engine में हर उस payload field को index करें जिस पर filter करते हैं, वरना filtered खोज धीमे रास्तों पर लौट सकती है।

त्वरित जाँच: Qdrant की filtered खोज को मज़बूत क्या बनाता है?

  • वह सिर्फ़ सटीक खोज समर्थित करता है
  • वह filters अनदेखे करता है
  • Payload शर्तें graph traversal के दौरान जाँची जाती हैं, payload indexes के साथ
  • Filters browser में चलते हैं
Answer

Payload शर्तें graph traversal के दौरान जाँची जाती हैं, payload indexes के साथ — Filter-जागरूक traversal बहुत कम परिणाम लौटाने से बचाता है।