पाठ 13 / 28

Filtered-Search की समस्या

देखें कि चयनात्मक filter बहुत कम या शून्य rows क्यों लौटा सकता है।

Index पहले पड़ोसी खोजता है, filter बाद में हटाता है

मान लें HNSW index 40 निकटतम उम्मीदवार लौटाता है (ef_search = 40), और query WHERE tenant = 7 जोड़ती है जहाँ tenant 7 के पास सिर्फ़ 1% rows हैं। उन 40 उम्मीदवारों में से लगभग 0.4 tenant 7 के होंगे, इसलिए filter के बाद आपको LIMIT से कम rows, या एक भी नहीं मिल सकती है, भले मेल खाती बहुत rows मौजूद हों। यह post-filtering है और approximate खोज का क्लासिक जाल है। सुधार: (1) iterative scans (pgvector 0.8+): index तब तक और उम्मीदवार लाता रहता है जब तक पर्याप्त rows filter पास न करें; (2) प्रति tenant partial indexes या partitions, ताकि index में सिर्फ़ मेल खा सकने वाली rows हों; (3) filter-जागरूक engine जो payload शर्तें जाँचते हुए graph पार करता है; (4) ज़्यादा लाकर फिर filter करना; (5) जब filter इतना चयनात्मक हो कि कुछ ही rows बचें तब सटीक scan (PostgreSQL का planner यह ख़ुद चुन सकता है)।

कठिन हिस्सा: filters और ANN का मिलन

चयनात्मक filters सीधी approximate खोज तोड़ सकते हैं; engines इसे iterative scans या filter-जागरूक graphs से हल करते हैं, और hybrid search keyword संकेत जोड़ता है।

चार विचार: pre, post, iterate, blend।
चित्र 4.1 — Pre, post, iterate और blend।

चयनात्मक filter कुछ नहीं लौटाता, फिर iterative scan ठीक करता है, चलाकर

मैंने यह SQL Docker container में pgvector extension संस्करण 0.8.6 के साथ PostgreSQL 16 पर चलाया। 100 tenants (प्रत्येक की लगभग 200 rows) के साथ, WHERE tenant = 7 ... LIMIT 10 वाली सादी HNSW query 0 rows लौटाती है, क्योंकि निकटतम उम्मीदवारों में कोई भी tenant 7 का नहीं। SET hnsw.iterative_scan = relaxed_order के बाद वही query 10 rows लौटाती है। सटीक संख्याएँ डेटा और settings पर निर्भर हैं।

SET client_min_messages = warning;
ALTER TABLE big ADD COLUMN IF NOT EXISTS tenant int;
UPDATE big SET tenant = id % 100;                                   -- 100 tenants, about 200 rows each
ANALYZE big;
SELECT embedding AS qv FROM big WHERE id = 1 \gset

SELECT 'plain HNSW + WHERE tenant = 7' AS setting, count(*) AS rows_returned
FROM (SELECT id FROM big WHERE tenant = 7 ORDER BY embedding <-> :'qv' LIMIT 10) x;

SET hnsw.iterative_scan = relaxed_order;                            -- keep scanning until enough rows pass the filter
SELECT 'iterative scan' AS setting, count(*) AS rows_returned
FROM (SELECT id FROM big WHERE tenant = 7 ORDER BY embedding <-> :'qv' LIMIT 10) x;

Output:

            setting            | rows_returned 
-------------------------------+---------------
 plain HNSW + WHERE tenant = 7 |             0
(1 row)

    setting     | rows_returned 
----------------+---------------
 iterative scan |            10
(1 row)

हमेशा सबसे चयनात्मक filter से परखें

सबसे छोटे tenant और सबसे दुर्लभ filter मान को परखें। ख़ाली परिणाम वहीं छिपे होते हैं।

त्वरित जाँच: HNSW index के साथ बहुत चयनात्मक filter बहुत कम rows क्यों लौटा सकता है?

  • Filters की अनुमति नहीं है
  • Index निकटतम उम्मीदवारों की निश्चित संख्या लौटाता है और filter फिर अधिकांश हटा देता है
  • Table ख़ाली है
  • Vectors के tenants नहीं हो सकते
Answer

Index निकटतम उम्मीदवारों की निश्चित संख्या लौटाता है और filter फिर अधिकांश हटा देता है — छोटे उम्मीदवार समूह का post-filtering कुछ नहीं छोड़ सकता; iterative scans या filter-जागरूक खोज उपयोग करें।