2025, Oct 18 09:31
Milvus में dynamic fields के लिए iterator-आधारित डेटा एक्सपोर्ट और माइग्रेशन
Milvus में dynamic fields सक्षम करने के लिए डेटा माइग्रेशन का तरीका जानें: iterator से बैच एक्सपोर्ट कर 16384 क्वेरी लिमिट से बचें, VTS और 2.6 भी देखें.
Milvus से डेटा एक्सपोर्ट करना तब जरूरी हो जाता है, जब किसी कलेक्शन की संरचना बदलनी पड़े — मसलन, dynamic fields सक्षम करने के लिए। सीधा रास्ता है: पूरा डेटा एक्सपोर्ट करें और उसे नए बनाए गए कलेक्शन में इंसर्ट कर दें। लेकिन यहीं कई लोग अटकते हैं — query-आधारित एक्सपोर्ट पर एक कड़ा लिमिट लगता है: 16384 की सीमा, जो प्रक्रिया को बीच में रोक देती है। अगर आपका primary key string है, तो interval के आधार पर range-slicing संभव नहीं होता। नीचे एक व्यावहारिक तरीका दिया है, जिससे माइग्रेशन उस दीवार से टकराए बिना हो सके।
समस्या का अवलोकन
Milvus डिफ़ॉल्ट रूप से नए फील्ड जोड़ने का समर्थन नहीं करता, इसलिए डेटा को dynamic fields से कॉन्फ़िगर किए गए एक नए कलेक्शन में ले जाना पड़ता है। क्वेरी के जरिए सरल एक्सपोर्ट 16384 लिमिट पर आकर ठिठक जाता है। और जब प्राथमिक कुंजी string हो, तो interval-आधारित pagination विकल्प ही नहीं रहता।
वह साधारण तरीका जो लिमिट को ट्रिगर करता है
सबसे सीधा तरीका है एक ही क्वेरी चलाकर सारे रिकॉर्ड एक साथ निकालने की कोशिश करना। आम तौर पर यही 16384 लिमिट को सामने ले आता है।
def dump_all_via_query(store, coll_name, filter_expr):
    records = store.query(collection=coll_name, where=filter_expr)
    return records
यह पैटर्न पूरे डेटासेट को एक ही बार में वापस लाने की कोशिश करता है। डेटासेट बड़ा हुआ तो प्रक्रिया 16384 की छत से टकराकर रुक जाती है और एक्सपोर्ट अधूरा रह जाता है।
यह सीमा यहां क्यों रोकती है
क्वेरी-पथ पर कैप लगा हुआ है, इसलिए एक कॉल में बड़े एक्सपोर्ट 16384 एंट्री लौटते ही ब्लॉक हो जाते हैं। चूंकि primary key string है, आप numeric ranges के जरिए interval slicing पर लौटकर इस सीमा के चारों ओर pagination नहीं कर सकते। नतीजा—साधारण क्वेरी के माध्यम से फुल एक्सपोर्ट के लिए बंद गली।
व्यावहारिक रास्ता
तीन व्यावहारिक दिशा-निर्देश हैं। पहला, 2.6 पर add field एक्सपोर्टेड है। दूसरा, आप iterator का उपयोग करके डेटा एक्सपोर्ट कर सकते हैं—यह बैचों में स्ट्रीम करके single-shot क्वेरी की कैप से बचाता है। तीसरा, आप VTS tool का उपयोग भी कर सकते हैं, जो इसमें मदद करता है। अगर आप सब कुछ कोड में ही रखना चाहते हैं और चलते-चलते नए कलेक्शन में पुश करना चाहते हैं, तो iterator वाला तरीका सबसे सीधा है।
पैटर्न सरल है: सोर्स कलेक्शन के लिए एक iterator बनाएं, जब तक डेटा खत्म न हो बैच निकालते रहें, और उन्हें टारगेट में लिखते जाएं। यह 16384 लिमिट को दरकिनार कर देता है, क्योंकि आप एक ही क्वेरी-रिस्पॉन्स पर निर्भर नहीं रहते।
def export_with_iterator(src_handle, src_coll, cond):
    it = src_handle.iterator(collection=src_coll, where=cond)
    while True:
        batch = it.next()
        if not batch:
            break
        for row in batch:
            yield row
def migrate_to_target(dst_handle, dst_coll, rows_iterable):
    buffer = []
    for row in rows_iterable:
        buffer.append(row)
        if len(buffer) >= 1000:
            dst_handle.insert(collection=dst_coll, data=buffer)
            buffer.clear()
    if buffer:
        dst_handle.insert(collection=dst_coll, data=buffer)
यह संरचना मेमोरी उपयोग को अनुमानयोग्य रखती है और डेटा को हिस्सों (chunks) में आगे बढ़ाती है। बैच का आकार आप अपनी आवश्यकता के अनुसार बदल सकते हैं; मूल बात है स्ट्रीम करना, न कि सब कुछ एक ही विशाल रिस्पॉन्स में इकट्ठा करना।
वर्ज़न और टूलिंग की भूमिका
अगर आप 2.6 पर हैं, ध्यान दें कि 2.6 पर add field एक्सपोर्टेड है। अगर आप एक्सपोर्ट लॉजिक लिखना नहीं चाहते, तो VTS tool भी इसमें आपकी मदद कर सकता है। Iterator वाला रास्ता code-first है और तब बेहतर बैठता है जब आपके पास dynamic fields से कॉन्फ़िगर किए गए नए कलेक्शन में insert करने के लिए पहले से कोई पाइपलाइन हो।
यह क्यों मायने रखता है
स्कीमा बदलते रहते हैं, इसलिए डेटा माइग्रेशन आम हैं। माइग्रेशन के बीच में सख्त क्वेरी-सीमा से टकराना रिलीज़ को अटका सकता है। यह जानना कि iterator-आधारित एक्सपोर्ट 16384 की छत से बचा लेता है, और VTS उपलब्ध है, आगे का रास्ता साफ कर देता है—भले ही primary key string हो और interval pagination संभव न हो।
निष्कर्ष
जब डेटा को dynamic fields वाले कलेक्शन में ले जा रहे हों, तो single-shot क्वेरी एक्सपोर्ट से बचें जो 16384 लिमिट से टकरा जाता है। इसके बजाय डेटासेट को स्ट्रीम करें: iterator से डेटा एक्सपोर्ट करें और उसे टारगेट कलेक्शन में बैचों में फिर से इंसर्ट करें। यदि आप 2.6 पर हैं, याद रखें कि 2.6 पर add field एक्सपोर्टेड है, और अगर आप कोड नहीं लिखना चाहते, तो VTS इस प्रक्रिया में मदद कर सकता है। एक्सपोर्ट को एक स्ट्रीम्ड ऑपरेशन के रूप में प्लान करें—माइग्रेशन अनुमानयोग्य और टिकाऊ बन जाएगा।
यह लेख StackOverflow के प्रश्न (लेखक: Jade Roy) और James Luan के उत्तर पर आधारित है।