انتقل إلى المحتوى الرئيسي

الوحدة 4 — تعريف المتغيّرات وإصدارها

المتغيّر ليس عمودًا في جدول. هو عقد بين مُهندسة بيانات تُنتِج قيمة، ومُهندسي تعلّم آليّ يُدرّبون نماذج عليها، ومُخدَم استدلال يستهلكها في الإنتاج. إن تغيّر العقد بلا اتّفاق، انهار كلّ ما فوقه. هذه الوحدة تُبيّن كيف يُكتَب العقد أوّلًا، ثمّ كيف يتطوّر.

التصريح لا الأمر

النقلة الجوهريّة بين شفرة pandas تقليديّة ووصفة متغيّر هي أنّ الأخيرة تصريحيّة: نقول ما هو المتغيّر، لا كيف يُحسَب في كلّ سياق. المخزن يعرف كيف يُنفّذه على المخزن غير المتّصل (SQL, Spark) وعلى المخزن المتّصل (اشتراك تدفّق).

مثال: عوضًا عن دفتر يكتب مباشرة عمودًا في DataFrame، نصرّح:

customer_avg_amount_7d = FeatureView(
name="customer_avg_amount_7d",
entities=[customer],
ttl=timedelta(days=8),
schema=[Field(name="avg_amount_7d", dtype=Float32)],
source=transactions_source,
aggregations=[
Aggregation(
column="amount",
function="mean",
time_window=timedelta(days=7),
),
],
owner="fraud-team@example.com",
tags={"pii": "false", "domain": "payments"},
)

كلّ حقل من هذا التصريح مقصود:

  • name فريد داخل السجلّ.
  • entities يفرض معرّف البحث؛ لا يستقبل النموذج بلا customer_id.
  • ttl يُحدّد متى تصبح القيمة قديمة (هنا 8 أيّام لترك هامش بعد 7).
  • schema يُثبّت الأنواع؛ تغيير Float32 إلى Int64 لا يمرّ بلا نسخة جديدة.
  • aggregations يُعطي الحساب للمحرّك ليُنفّذه على الاثنين.
  • owner و**tags** يوصّلان الحوكمة.

الأنواع: مسألة ليست جماليّة

فرق الأنواع تُنتج فجوات مؤلمة. مثالان شائعان:

  • عدّاد يُخزَّن Int64 في المخزن غير المتّصل ويُقرأ String في المخزن المتّصل: النموذج يستقبل "12" بدل 12، وشجرة القرار تنهار.
  • طابع زمنيّ يُخزَّن UTC في المخزن غير المتّصل وبتوقيت محلّيّ في مصدر التدفّق: كلّ الحسابات على النافذة تُصبح خاطئة بمقدار ساعة.

الأنواع في وصفة المتغيّر تُلزم الطرفين، ويرفض مخزن جيّد الكتابة إذا اختلف النوع. لا يكون الاختبار «هل الأرقام قريبة»، بل «هل التوقيع متطابق حرفيًّا».

مدّة الصلاحيّة، أو TTL

قيمة عدّاد count_1h تصبح بلا معنى بعد ساعتين. TTL في وصفة المتغيّر يقول للمخزن: لا تُقدّم قيمة أقدم من هذا العمر. بدلًا من إعطاء عدّاد بائد، يُرجع المخزن قيمة مفقودة، فيرى النموذج ذلك ويتّخذ القرار المناسب (رفض، إرسال إلى مراجعة يدويّة).

قواعد عمليّة لضبط TTL:

  • نافذة تجميع + هامش أمان تجسيد. عدّاد 1h مع تجسيد كلّ 5 دقائق، اجعل TTL بـ90 دقيقة على الأكثر.
  • متغيّرات مستقرّة (متوسّط شهريّ) TTL يبلغ 7 أو 14 يومًا.
  • متغيّر بلا TTL محدّد ينتج قيمًا بائدة صامتة — أشيع سبب لانهيار الأداء بعد أسابيع.

من هو المالك؟

كلّ وصفة متغيّر يجب أن يكون لها مالك مُحدَّد بالاسم أو بالفريق. المخزن يحمل هذه المعلومة، ولوحة الاكتشاف تعرضها. عمليًّا، هذا يُغيّر السلوكيّات:

  • عندما ينخفض عدد الاستعمالات، يعرف المالك أنّ متغيّره أصبح ميتًا وأنّه يستطيع إزالته.
  • عندما يظهر خلل، يعرف المستهلك بمن يتّصل مباشرة.
  • عندما يُقترَح تغيير، يعرف المالك من عليه استشارتُه.

بلا مالك، تنتهي المتغيّرات إمّا مُهملة إلى الأبد أو مُغيَّرة من دون تنسيق.

التطوّر بلا كسر: قاعدة نسخيّة

المتغيّر يتطوّر: تغيّر النافذة، تغيّر معالجة القيم الشاذّة، أُضيف مصفٍّ جديد. لا يمكن الإحلال المكانيّ لأنّه سيُغيّر ما يستقبله النموذج في الإنتاج، مع أنّ اسم المتغيّر لم يتغيّر.

الحلّ الذي تتبّناه الفرق الناضجة: قاعدة النسخة في الاسم.

customer_counters_v1 = FeatureView(name="customer_counters_v1", ...)
customer_counters_v2 = FeatureView(name="customer_counters_v2", ...)

النموذج القائم يبقى يستهلك v1؛ النموذج الجديد يبدأ باستهلاك v2. حين يهاجر جميع المستهلكين إلى v2، ترحل v1. لا مفاجآت، ولا رجوع خلفيّ يُطبّق «على الجميع فورًا».

هذه القاعدة تكسر الرغبة في «تنظيف» المتغيّرات القديمة فورًا، وهي واحدة من أهمّ الدروس العمليّة: الاستقرار عقد أهمّ من النظافة الجماليّة.

المخطّط والتوثيق

في ملفّ التعريف نفسه، أضِف وصفًا للحقول:

schema=[
Field(
name="count_1h",
dtype=Int64,
description="عدد المعاملات الناجحة للعميل في الساعة السابقة، بتوقيت UTC، نافذة منزلقة تُحدَّث كلّ 5 دقائق"
),
]

هذا الوصف يظهر في لوحة الاكتشاف (الوحدة 8) ويجعل المستهلك يفهم معنى المتغيّر لا شكله فقط. الغياب هنا أعلى تكلفة ممّا يبدو: مستعمل جديد يسأل زملاءه، والزملاء ينسون، ويضيع أسبوع أحدهم.

اختبار الاستيعاب في دقيقتين

عند مراجعة تعريف متغيّر جديد، اقرأه وحاول شرحه بجملة لشخص لم يعمل عليه. إن احتجت إلى الرجوع إلى الكود لتذكّر الوحدة أو المنطقة الزمنيّة أو النافذة، فالتعريف ناقص. الحقول (name, description, ttl, owner, tags) موجودة لهذا السبب.

الخلاصة

  • الوصفة تصريحيّة: تقول ما هو المتغيّر لا كيف يُنفَّذ، ويتولّى المخزن الترجمة للتخزينَين.
  • الأنواع مُلزِمة، لأنّ فرقًا صغيرة تُنتج فجوات مؤلمة بين تنفيذَي التدريب والخدمة.
  • TTL يفرض حداثة القيمة؛ غيابه يُنتج قيمًا بائدة صامتة.
  • المالك حقل إلزاميّ عمليّ، وقاعدة النسخة في الاسم (v1, v2) تسمح بالتطوّر دون كسر النماذج القائمة.

الوحدة التالية: كيف نُخرج مجموعة تدريب متّسقة زمنيًّا من دون تسرّب المستقبل.