प्रतिनिधि इंटरव्यू विषय

डेटा इंजीनियरिंग इंटरव्यू: आप एक विश्वसनीय dbt इंक्रीमेंटल मॉडल कैसे डिज़ाइन करेंगे?

डेटाकठिन
Offer.cc संपादकीय टीमप्रकाशित अपडेट किया गया

प्रश्न

जब कोई डेटासेट लगातार बढ़ रहा हो और दैनिक फ़ुल पुनः गणना बहुत महंगी हो, तो आप एक विश्वसनीय dbt इंक्रीमेंटल मॉडल कैसे डिज़ाइन करेंगे?

प्रॉम्प्ट और दायरा

इंटरव्यूअर आपको एक इवेंट टेबल देता है जिसमें लगातार राइट्स (writes) होते हैं और आपसे एक दैनिक फ़ैक्ट टेबल बनाने के लिए कहता है। पहला रन इतिहास को स्कैन कर सकता है, लेकिन बाद के रन केवल बदले हुए डेटा को प्रोसेस करने चाहिए। इवेंट्स देर से आ सकते हैं, अपडेट हो सकते हैं, या डुप्लिकेट हो सकते हैं, और मॉडल कॉलम बदल सकते हैं। फ़िल्टर बाउंड्री, यूनिक की, इंक्रीमेंटल रणनीति, बैकफ़िल योजना और विफलता के बाद रिकवरी की व्याख्या करें।

मान लें कि वेयरहाउस SQL का समर्थन करता है, टारगेट date_day द्वारा एग्रीगेट किया गया है, और प्रत्येक इवेंट में event_at, updated_at, और एक स्थिर event_id है। शुरुआत में ही इन मान्यताओं को स्पष्ट करें। एक स्थिर कुंजी के बिना, अपडेट सिमेंटिक्स और डिडुप्लिकेशन बदल जाते हैं।

इंटरव्यूअर क्या मूल्यांकन करता है

इंटरव्यूअर यह देखना चाहता है कि क्या आप शुद्धता का त्याग किए बिना स्कैन किए गए डेटा को कम कर सकते हैं। एक बुनियादी उत्तर में is_incremental() और एक टाइमस्टैम्प फ़िल्टर का उल्लेख होता है। एक मजबूत उत्तर यह बताता है कि फ़िल्टर को देर से आने वाले डेटा को क्यों कवर करना चाहिए, एग्रीगेट को इसके ग्रेन से मेल खाने वाले unique_key की आवश्यकता क्यों है, और --full-refresh कब अनिवार्य है।

वे यह भी परीक्षण कर रहे हैं कि क्या आप तीन जोखिमों को अलग करते हैं: देर से आने वाले इवेंट्स का छूटना, व्यावसायिक ग्रेन पर डुप्लिकेट पंक्तियाँ लिखना, और ऐतिहासिक रूपांतरण बदलने के बाद पुराने और नए तर्क का मिश्रण होना। वर्तमान डेटा-इंजीनियरिंग इंटरव्यू सामग्री इंक्रीमेंटल मॉडल, स्नैपशॉट और डिपेंडेंसी ग्राफ़ को व्यावहारिक तैयारी विषयों के रूप में मानती है; यह प्रश्न SQL, डेटा मॉडलिंग और रन गवर्नेंस को जोड़ता है।

उत्तर देने से पहले स्पष्टीकरण प्रश्न

व्यावसायिक ग्रेन (Business Grain) क्या है?

यदि एक पंक्ति एक दिन का प्रतिनिधित्व करती है, तो date_day यूनिक की हो सकती है। यदि एक पंक्ति एक उपयोगकर्ता और एक दिन का प्रतिनिधित्व करती है, तो कुंजी (user_id, date_day) होनी चाहिए। ग्रेन मर्ज की स्थिति, डुप्लिकेट चेक और बैकफ़िल लागत को बदल देता है।

डेटा कितनी देर से आ सकता है?

यदि इवेंट्स सामान्यतः दो दिनों से अधिक देर से नहीं आते हैं, तो नवीनतम तीन दिनों की पुनः गणना करें। यदि कोई उपयोगी ऊपरी सीमा नहीं है, तो एक निश्चित विंडो अपर्याप्त है; वॉटरमार्क, पार्टीशन रिपेयर, या आवधिक फ़ुल समाधान (periodic full reconciliation) का उपयोग करें। एक विंडो को स्वीकृत देरी वितरण को कवर करना चाहिए।

कौन सा फ़ील्ड अपस्ट्रीम अपडेट का प्रतिनिधित्व करता है?

event_at व्यावसायिक समय है, जबकि updated_at अंतिम संशोधन का समय है। केवल event_at द्वारा फ़िल्टर करने से एक पुराना इवेंट छूट जाता है जिसे बाद में ठीक किया गया था। एक विश्वसनीय updated_at या परिवर्तन अनुक्रम को प्राथमिकता दें और सत्यापित करें कि स्रोत इसे पीछे नहीं ले जाता है।

मॉडल या कॉलम परिवर्तन कैसे रिलीज़ किए जाते हैं?

कॉलम जोड़ना, कॉलम हटाना और गणना तर्क बदलना—इनके लिए अलग-अलग व्यवहार की आवश्यकता होती है। पुष्टि करें कि क्या on_schema_change संरचना को सिंक्रनाइज़ कर सकता है, क्या पुरानी पंक्तियों को बैकफ़िल किया जाना चाहिए, और क्या फ़ुल रिफ्रेश शेड्यूल किया जा सकता है।

30-सेकंड उत्तर फ़्रेमवर्क

"मैं पहले टारगेट ग्रेन और लेटेंसी बाउंड की पुष्टि करूँगा। पहला रन पूरे इतिहास से मॉडल बनाता है। बाद के रन updated_at द्वारा फ़िल्टर करने और लेटेंसी विंडो में पीछे देखने के लिए is_incremental() का उपयोग करते हैं। टारगेट एक unique_key घोषित करता है जो इसके ग्रेन से मेल खाता है, ताकि हाल के दिन डुप्लिकेट के रूप में जुड़ने के बजाय अपडेट हो जाएँ। मैं एग्रीगेट करने से पहले इवेंट संस्करण द्वारा विंडो को डिडुप्लिकेट करता हूँ, फिर merge या वेयरहाउस समकक्ष के साथ राइट करता हूँ। मैं विंडो, कुंजी और स्कीमा-परिवर्तन व्यवहार का परीक्षण करता हूँ। यदि लॉजिक परिवर्तन ऐतिहासिक परिणामों को असंगत बनाते हैं, तो मैं एक नियंत्रित --full-refresh चलाता हूँ और प्रभावित डाउनस्ट्रीम मॉडल का पुनर्निर्माण करता हूँ। अंत में, मैं प्रोसेस की गई पंक्तियों, अधिकतम अपडेट समय, डुप्लिकेट कुंजियों और इंक्रीमेंटल-बनाम-फ़ुल अंतरों की निगरानी करता हूँ।"

चरण-दर-चरण गहन विश्लेषण

1. फ़ुल-रिफ्रेश शुद्धता बेसलाइन को परिभाषित करें

पहले पूरी क्वेरी लिखें: सभी इवेंट्स पढ़ें और टारगेट ग्रेन पर एग्रीगेट करें। यह शुद्धता की बेसलाइन है। इंक्रीमेंटल आउटपुट को उसी समय सीमा में पूर्ण गणना के साथ मेल खाना चाहिए। इस बेसलाइन को स्थापित करने से पहले अनुकूलन करने से छूटे हुए रिकॉर्ड का पता लगाना कठिन हो जाता है।

2. इंक्रीमेंटल फ़िल्टर बाउंड्री चुनें

एक इंक्रीमेंटल शाखा केवल तभी लागू होती है जब टारगेट टेबल मौजूद हो, --full-refresh अनुपस्थित हो, और मॉडल को इंक्रीमेंटल के रूप में कॉन्फ़िगर किया गया हो। एक विकल्प टारगेट के अधिकतम अपडेट समय से लेटेंसी विंडो को घटाना है:

sql
{{
  config(
    materialized = 'incremental',
    unique_key = ['date_day'],
    incremental_strategy = 'merge'
  )
}}

with source_events as (
  select *
  from {{ ref('app_events') }}
  {% if is_incremental() %}
    where updated_at >= (
      select coalesce(max(updated_at), '1900-01-01') from {{ this }}
    ) - interval '3 day'
  {% endif %}
)
select
  cast(event_at as date) as date_day,
  count(distinct event_id) as events,
  max(updated_at) as max_updated_at
from source_events
group by 1

तीन दिन का मान एक इंटरव्यू की धारणा है, कोई सार्वभौमिक स्थिरांक नहीं। देरी, SLA और पुनः गणना लागत से विंडो चुनें। वेयरहाउस के अनुसार दिनांक अभिव्यक्ति को अनुकूलित करें।

3. यूनिक की को मॉडल ग्रेन से मिलाएँ

दैनिक टेबल के लिए, date_day कुंजी है। उपयोगकर्ता-दिन टेबल के लिए, ['user_id', 'date_day'] का उपयोग करें। कुंजी कॉलम में नल (nulls) नहीं होने चाहिए, अन्यथा मर्ज मिलान करने में विफल हो सकता है और डुप्लिकेट बना सकता है। बिना किसी कुंजी के, कई एडेप्टर अपेंड-ओनली के रूप में व्यवहार करते हैं, इसलिए एक विंडो की पुनः गणना करने से एक ग्रेन के लिए कई पंक्तियाँ लिखी जा सकती हैं।

4. एग्रीगेशन से पहले विंडो के अंदर डिडुप्लिकेट करें

रीप्ले या CDC अपडेट एक इवेंट के कई संस्करण उत्पन्न कर सकते हैं। event_id और अपडेट समय के अनुसार सॉर्ट करें, नवीनतम संस्करण बनाए रखें, फिर एग्रीगेट करें:

sql
with ranked_events as (
  select
    *,
    row_number() over (
      partition by event_id
      order by updated_at desc, ingest_seq desc
    ) as rn
  from source_events
),
deduped_events as (
  select * from ranked_events where rn = 1
)
select
  cast(event_at as date) as date_day,
  count(*) as events,
  max(updated_at) as max_updated_at
from deduped_events
group by 1

ingest_seq का उपयोग केवल तभी करें जब यह समान टाइमस्टैम्प के लिए एक स्थिर टाई-ब्रेकर हो। अन्यथा टाई नियम को एक अनसुलझा स्रोत अनुबंध कहें। डिडुप्लिकेशन एग्रीगेशन से पहले होना चाहिए, अन्यथा एक इवेंट के दोनों संस्करण गिने जाएँगे।

5. मर्ज, पार्टीशन ओवरराइट, या अपेंड चुनें

merge ग्रेन द्वारा कुंजीकृत अपडेट-एंड-इंसर्ट सिमेंटिक्स के अनुकूल है। एक पार्टीशन-रीकंप्यूट वर्कलोड insert_overwrite का उपयोग कर सकता है, जो पंक्ति कुंजियों के बजाय पार्टीशन पर निर्भर करता है। शुद्ध अपेंड तब सरल होता है जब अपस्ट्रीम इवेंट कभी नहीं बदलते हैं। किसी एक रणनीति को सार्वभौमिक मानने के बजाय अपडेट सिमेंटिक्स, स्कैन लागत और एडेप्टर समर्थन में से चुनें।

6. स्कीमा और लॉजिक परिवर्तनों को संभालें

एक कॉलम जोड़ने से पुरानी पंक्तियाँ अपने आप बैकफ़िल नहीं होती हैं; हटाए गए कॉलम और प्रकार परिवर्तन केवल रन टाइम पर सामने आ सकते हैं। on_schema_change ignore, fail, append_new_columns, या sync_all_columns हो सकता है, लेकिन यह केवल शीर्ष-स्तरीय कॉलम को ट्रैक करता है और ऐतिहासिक बैकफ़िल को प्रतिस्थापित नहीं करता है। यदि गणना तर्क बदलता है, तो पुराना और नया इतिहास अलग-अलग नियमों का पालन कर सकता है, इसलिए --full-refresh चलाएँ और प्रभावित डाउनस्ट्रीम इंक्रीमेंटल मॉडल का पुनर्निर्माण करें।

7. बैकफ़िल और विफलता रिकवरी डिज़ाइन करें

रन मेटाडेटा में लेटेंसी विंडो, टारगेट अधिकतम अपडेट समय और स्रोत वॉटरमार्क रिकॉर्ड करें। विफल विंडो रन के बाद, अंतिम कमिट किए गए टारगेट वॉटरमार्क से पुनः गणना करें; इन-मेमोरी "प्रोसेस्ड थ्रू" मान को सत्य न मानें। व्यापक मरम्मत के लिए, सीमित समवर्तीता (concurrency) के साथ दिनांक पार्टीशन को प्रोसेस करें, फिर पूर्ण क्वेरी के विरुद्ध नमूनों का मिलान करें ताकि एक रिफ्रेश वेयरहाउस पर अत्यधिक भार न डाले।

8. सत्यापन लूप बंद करें

कम से कम चार संकेतों को सत्यापित करें: प्रत्येक event_id विंडो में अधिकतम एक बार दिखाई देता है; टारगेट कुंजियाँ अद्वितीय हैं; हालिया इंक्रीमेंटल आउटपुट पूर्ण पुनः गणना से अनुमत अंतर के भीतर रहता है; और प्रोसेस की गई पंक्तियाँ और अधिकतम updated_at अप्रत्याशित रूप से नहीं बढ़ते हैं। खाली इनपुट, डुप्लिकेट इवेंट्स, पुराने इवेंट्स के अपडेट, देर से आने वाले डेटा, सीमा के बराबर टाइमस्टैम्प और फ़ुल रिफ्रेश के बाद एक इंक्रीमेंटल रन का परीक्षण करें।

उच्च-गुणवत्ता वाला नमूना उत्तर

"मैं पहले मॉडल ग्रेन, लेटेंसी बाउंड और स्रोत अपडेट फ़ील्ड की पुष्टि करूँगा। मान लें कि टारगेट में प्रति दिन एक पंक्ति है और इवेंट्स में स्थिर event_id और updated_at हैं। पहला रन इतिहास से बनता है; बाद के रन is_incremental() का उपयोग करते हैं और टारगेट के अधिकतम अपडेट समय से तीन दिन पीछे देखते हैं। वह विंडो लेटेंसी से तय होती है, किसी निश्चित नियम से नहीं।

विंडो के भीतर मैं इवेंट आईडी और संस्करण द्वारा डिडुप्लिकेट करता हूँ, फिर दिन के अनुसार एग्रीगेट करता हूँ। टारगेट date_day को अपने unique_key के रूप में घोषित करता है और मर्ज का उपयोग करता है ताकि हाल के दिनों को डुप्लिकेट करने के बजाय बदल दिया जाए। उपयोगकर्ता-दिन ग्रेन के लिए मैं एक समग्र कुंजी (composite key) का उपयोग करूँगा। केवल इवेंट समय द्वारा फ़िल्टर करने से पुराने इवेंट्स में बाद के सुधार छूट जाएँगे, इसलिए मैं एक विश्वसनीय अपडेट टाइमस्टैम्प या परिवर्तन अनुक्रम को प्राथमिकता दूँगा।

मैं विंडो आकार, वॉटरमार्क, प्रोसेस की गई पंक्तियों, डुप्लिकेट कुंजियों और इंक्रीमेंटल-बनाम-फ़ुल समाधान की निगरानी करूँगा। एक स्कीमा-परिवर्तन सेटिंग संरचनात्मक विकास को संभाल सकती है, लेकिन यह ऐतिहासिक मानों को पॉप्युलेट नहीं करती है। यदि तर्क बदलता है या इतिहास को मरम्मत की आवश्यकता है, तो मैं एक नियंत्रित फ़ुल रिफ्रेश या पार्टीशन बैकफ़िल चलाऊँगा और प्रभावित डाउनस्ट्रीम मॉडल का पुनर्निर्माण करूँगा। मॉडल को विश्वसनीय कहने से पहले मैं खाली इनपुट, देर से और डुप्लिकेट इवेंट्स, सीमा टाइमस्टैम्प और पुनः प्रयास व्यवहार का परीक्षण करूँगा।"

सामान्य गलतियाँ

केवल event_at द्वारा फ़िल्टर करना → पुराने अपडेट छूट जाते हैं → updated_at या एक स्पष्ट CDC वॉटरमार्क का उपयोग करें

पुराने इवेंट को ठीक किए जाने पर व्यावसायिक समय नहीं बदलता है। यदि अपडेट की अनुमति है, तो अपडेट समय या परिवर्तन अनुक्रम द्वारा फ़िल्टर करें और इसके अनुबंध को सत्यापित करें।

बिना किसी कुंजी के मर्ज करना → पंक्तियों का विश्वसनीय रूप से मिलान नहीं किया जा सकता → पहले ग्रेन और गैर-शून्य कुंजियों को परिभाषित करें

एक कुंजी को बिल्कुल एक लक्षित पंक्ति की पहचान करनी चाहिए। यदि ग्रेन उपयोगकर्ता-दिन है, तो केवल तारीख का उपयोग करने से अलग-अलग उपयोगकर्ता एक पंक्ति में मर्ज हो जाते हैं।

यह मान लेना कि एक नया कॉलम स्वचालित रूप से बैकफ़िल हो गया है → ऐतिहासिक मान खाली रहते हैं → बैकफ़िल या फ़ुल रिफ्रेश की योजना बनाएँ

स्कीमा सिंक्रनाइज़ेशन और ऐतिहासिक डेटा पॉप्युलेशन अलग-अलग हैं। एक संरचनात्मक परिवर्तन हल्का हो सकता है, लेकिन पुरानी पंक्तियों में डेटा भरने के लिए एक स्पष्ट अपडेट या पुनर्निर्माण की आवश्यकता होती है।

एक निश्चित एक घंटे की विंडो चुनना → देर से आने वाला डेटा इससे बाहर हो जाता है → पर्सेंटाइल और समाधान के साथ कैलिब्रेट करें

देरी वितरण, SLA और लागत से विंडो चुनें। विंडो के बाहर आने वाले डेटा की निगरानी करें और वितरण बदलने पर इसका विस्तार या मरम्मत करें।

फ़ॉलो-अप प्रश्न और उत्तर

यदि 5% इवेंट दो दिन देर से आते हैं, तो आप विंडो कैसे चुनेंगे?

पहले स्वीकृत ताज़गी विलंब (freshness delay) की पुष्टि करें। यदि किसी दैनिक रिपोर्ट को अगले दिन ठीक किया जा सकता है, तो दो से तीन दिनों को कवर करें और देर से आने वाले इवेंट्स का मिलान करें। यदि पहले दिन के परिणाम स्थिर होने चाहिए, तो केवल एक बड़ी SQL विंडो के बजाय एक वॉटरमार्क और एक रिपेयर कतार का उपयोग करें। प्रतिशत की नकल करने के बजाय लेटेंसी और लागत वक्रों के विरुद्ध विकल्प को मान्य करें।

क्या होगा यदि unique_key स्रोत में डुप्लिकेट है?

इंक्रीमेंटल इनपुट या टारगेट में डुप्लिकेट कुंजियाँ किसी एडेप्टर को विफल कर सकती हैं या अपरिभाषित परिणाम उत्पन्न कर सकती हैं। दोनों स्थानों पर विशिष्टता की जाँच करें, डुप्लिकेट स्रोत की पहचान करें, इवेंट संस्करण द्वारा डिडुप्लिकेट करें, या एक समग्र कुंजी को फिर से परिभाषित करें जो वास्तविक ग्रेन का प्रतिनिधित्व करती है। एक यादृच्छिक आईडी को एक अस्थिर व्यावसायिक कुंजी को नहीं छिपाना चाहिए।

मॉडल SQL बदल गया है, लेकिन आप केवल सात दिनों की पुनः गणना करना चाहते हैं। क्या आप इंक्रीमेंटल रूप से चलाना जारी रख सकते हैं?

केवल तभी जब ऐतिहासिक परिणाम नए तर्क से अप्रभावित हों। यदि परिवर्तन पूरे इतिहास को प्रभावित करता है, तो सात-दिवसीय इंक्रीमेंटल रन मिश्रित नियमों वाली एक टेबल बनाता है। प्रभावित सीमा के लिए एक नियंत्रित फ़ुल रिफ्रेश या पार्टीशन रीकंप्यूट चलाएँ और डाउनस्ट्रीम मॉडल का पुनर्निर्माण करें।

अपस्ट्रीम टेबल को काट (truncate) दिया गया था। इंक्रीमेंटल मॉडल कैसे रिकवर होता है?

वॉटरमार्क को आगे बढ़ाना बंद करें, स्रोत पुनर्निर्माण की पुष्टि करें, और एक विश्वसनीय स्नैपशॉट या CDC बिंदु से रीप्ले करें। यदि स्रोत अब आवश्यक इतिहास को कवर नहीं करता है, तो एक इंक्रीमेंटल रन एक अपूर्ण स्रोत को एक पूर्ण बेसलाइन के रूप में मानेगा; स्नैपशॉट को पुनर्स्थापित करें या टारगेट को पूरी तरह से रीबिल्ड करें।

सार्वजनिक स्रोत

संबंधित प्रश्न