2025, Oct 01 11:34
LlamaIndex में None/null मेटाडेटा फ़िल्टर क्यों नहीं चलते और समाधान
जानें LlamaIndex में None/null मेटाडेटा पर फ़िल्टर क्यों नहीं चलते। छोटा Python कोड उदाहरण और दो विश्वसनीय उपाय: 'None' स्ट्रिंग या खाली स्ट्रिंग पर फ़िल्टर।
null-जैसी वैल्यू वाले मेटाडेटा पर फ़िल्टर लगाते समय रिट्रीवल पाइपलाइनों में गलती होना आसान है। यदि आप LlamaIndex पर काम कर रहे हैं और मानते हैं कि value None वाला फ़िल्टर उन डॉक्यूमेंट्स से मेल खाएगा जिनके मेटाडेटा में None स्पष्ट रूप से स्टोर है, तो परिणाम खाली मिलेगा। नीचे इस व्यवहार का संक्षिप्त वॉकथ्रू, न्यूनतम कोड उदाहरण, और दो सीधे तरीके दिए हैं जिनसे ऐसी क्वेरीज़ भरोसेमंद रूप से काम करें।
समस्या को दुहराना
नीचे दिए उदाहरण में एक TextNode से VectorStoreIndex बनाया गया है, जिसके मेटाडेटा में start_date का मान None है। FilterOperator.EQ और value=None वाला मेटाडेटा फ़िल्टर कोई भी नोड वापस नहीं करता।
from llama_index.core import VectorStoreIndex
from llama_index.core.schema import TextNode
from llama_index.core.vector_stores import (
MetadataFilter,
MetadataFilters,
FilterOperator,
)
sample_node = TextNode(
text="This document has None in the metadata",
id_="node_01",
metadata={"start_date": None},
)
idx = VectorStoreIndex([sample_node])
print("Index nodes:", [n.metadata for n in idx.docstore.docs.values()])
null_date_rule = MetadataFilter(key="start_date", operator=FilterOperator.EQ, value=None)
rule_set = MetadataFilters(filters=[null_date_rule])
fetcher = idx.as_retriever(filters=rule_set, similarity_top_k=1)
results = fetcher.retrieve("this")
print("Retrieved nodes:", [(n.node_id, n.metadata) for n in results])
आउटपुट से स्पष्ट है कि मेटाडेटा सचमुच None के साथ स्टोर है, फिर भी फ़िल्टर कुछ भी रिट्रीव नहीं करता।
Index nodes:
[{'start_date': None}]
Retrieved nodes:
[]
ऐसा क्यों हो रहा है
यह LlamaIndex का अपेक्षित व्यवहार है: None पर फ़िल्टर नहीं लगाया जा सकता। मेटाडेटा में कोई फ़ील्ड स्पष्ट रूप से None हो, तब भी value को None देने पर फ़िल्टर उससे मेल नहीं करेगा। यदि आपको “null” जैसी अवधारणा पर क्वेरी करनी है, तो एक ठोस और फ़िल्टर करने योग्य मान स्टोर करना होगा।
व्यवहार में इसे कैसे काम में लाएँ
दो व्यावहारिक तरीके हैं। पहला, null-जैसी वैल्यू को स्ट्रिंग के रूप में सहेजें और उसी स्ट्रिंग पर क्वेरी करें। दूसरा, खाली स्ट्रिंग रखें और उसी खाली स्ट्रिंग पर फ़िल्टर लगाएँ। दोनों ही रणनीतियाँ बिना अन्यत्र रिट्रीवल लॉजिक बदले फ़ील्ड को फ़िल्टर करने योग्य बना देती हैं।
यदि आपको अपने वातावरण में Ollama के साथ एंबेडिंग्स और LLM भी कॉन्फ़िगर करने हैं, तो इंडेक्स बनाने से पहले नीचे दी गई सेटअप का उपयोग कर सकते हैं।
from llama_index.core import VectorStoreIndex, Settings
from llama_index.embeddings.ollama import OllamaEmbedding
from llama_index.llms.ollama import Ollama
emb_backend = OllamaEmbedding(
model_name="llama3.2",
base_url="http://localhost:11434",
)
Settings.embed_model = emb_backend
पहला विकल्प "None" नाम की सेंटिनल स्ट्रिंग स्टोर करता है और str(None) के साथ फ़िल्टर करता है।
from llama_index.core.schema import TextNode
from llama_index.core.vector_stores import (
MetadataFilter,
MetadataFilters,
FilterOperator,
)
from llama_index.core import VectorStoreIndex
DocA = TextNode(
text="This document has None in the metadata",
id_="node_01",
metadata={"start_date": "None"},
)
DocB = TextNode(
text="This document has start date in the metadata",
id_="node_02",
metadata={"start_date": "20/03/2023"},
)
idx = VectorStoreIndex([DocA, DocB])
print("Index nodes:", [d.metadata for d in idx.docstore.docs.values()])
null_date_rule = MetadataFilter(key="start_date", operator=FilterOperator.EQ, value=str(None))
rule_set = MetadataFilters(filters=[null_date_rule])
fetcher = idx.as_retriever(filters=rule_set, similarity_top_k=1)
results = fetcher.retrieve("this")
print("Retrieved nodes:", [(x.node_id, x.metadata) for x in results])
अपेक्षित आउटपुट दिखाता है कि सेंटिनल स्ट्रिंग वाला नोड फ़िल्टर से मेल खा रहा है।
Index nodes:
[{'start_date': 'None'}, {'start_date': '20/03/2023'}]
Retrieved nodes:
[('node_01', {'start_date': 'None'})]
दूसरे विकल्प में खाली स्ट्रिंग स्टोर की जाती है और उसी खाली स्ट्रिंग पर फ़िल्टर लगाया जाता है।
from llama_index.core.schema import TextNode
from llama_index.core.vector_stores import (
MetadataFilter,
MetadataFilters,
FilterOperator,
)
from llama_index.core import VectorStoreIndex
DocA = TextNode(
text="This document has None in the metadata",
id_="node_01",
metadata={"start_date": ""},
)
DocB = TextNode(
text="This document has start date in the metadata",
id_="node_02",
metadata={"start_date": "20/03/2023"},
)
idx = VectorStoreIndex([DocA, DocB])
print("Index nodes:", [d.metadata for d in idx.docstore.docs.values()])
null_date_rule = MetadataFilter(key="start_date", operator=FilterOperator.EQ, value="")
rule_set = MetadataFilters(filters=[null_date_rule])
fetcher = idx.as_retriever(filters=rule_set, similarity_top_k=1)
results = fetcher.retrieve("this")
print("Retrieved nodes:", [(x.node_id, x.metadata) for x in results])
अपेक्षित आउटपुट पुष्टि करता है कि खाली स्ट्रिंग पर फ़िल्टर लगाने से इच्छित नोड वापस मिलता है।
Index nodes:
[{'start_date': ''}, {'start_date': '20/03/2023'}]
Retrieved nodes:
[('node_01', {'start_date': ''})]
यह क्यों अहम है
जब आप ऐसे रिट्रीवल सिस्टम बनाते हैं जो रूटिंग या पोस्ट-फ़िल्टरिंग के लिए मेटाडेटा फ़िल्टर पर निर्भर हों, तो दस्तावेज़ों का चुपचाप छूट जाना महँगा साबित हो सकता है। यह समझ कि LlamaIndex में None फ़िल्टर करने योग्य नहीं है, आपको इनजेशन के समय “null” डेटा को सामान्य रूप देने में मदद करती है और क्वेरी के व्यवहार को अनुमानित रखती है।
मुख्य बातें
यदि कोई फ़ील्ड अवधारणात्मक रूप से null हो सकता है, तो उसका स्पष्ट और फ़िल्टर करने योग्य रूप स्टोर करें। या तो "None" स्ट्रिंग रखें और str(None) पर क्वेरी करें, या खाली स्ट्रिंग रखें और उसी पर क्वेरी करें। इंडेक्सिंग और फ़िल्टरिंग—दोनों में प्रतिनिधित्व समान रखें ताकि आपके VectorStoreIndex रिट्रीवर अपेक्षित नोड्स लौटाएँ।