0Pricing
Coding Interview Prep · درس

الأحداث المرتبة والنوافذ الزمنية

ضمان حدوث الخطوات بالتسلسل وضمن حد زمني باستخدام دوال النوافذ

الأحداث المرتبة والنوافذ الزمنية درس مجاني في Coding Interview Prep على CoddyKit. هذا هو الدرس 2 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Coding Interview Prep، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Coding Interview Prep 4 دروس في المجموع.

لماذا يهم الترتيب والوقت

يتحقق مسار التحويل الأساسي من الدرس السابق فقط من حدوث كل خطوة للمستخدم. لكن المحاور الأكثر دقة سيسأل: هل حدثت الخطوات بالترتيب الصحيح وخلال مدة معقولة؟

المستخدم الذي أجرى عملية شراء يوم الاثنين وزار صفحة التسويق يوم الجمعة لم يتحول عبر مسار التحويل لديك. ويحوّل التسلسل والتوقيت مسار التحويل الساذج القائم على المؤشرات إلى مسار موثوق.

فكرة الطابع الزمني الأول لكل مستخدم

للتفكير في الترتيب، التقط الوقت الأول لكل مستخدم عند كل خطوة: أول زيارة، وأول تسجيل، وأول عملية شراء.

بعد ذلك، يعني التحويل السليم أن تكون قيمة first_signup_time >= first_visit_time، وهكذا نزولًا عبر السلسلة. ويمنحك MIN(event_time) المجمّع لكل خطوة نقاط الارتكاز هذه.

SELECT
  user_id,
  MIN(CASE WHEN event_name = 'visit'    THEN event_time END) AS first_visit,
  MIN(CASE WHEN event_name = 'signup'   THEN event_time END) AS first_signup,
  MIN(CASE WHEN event_name = 'purchase' THEN event_time END) AS first_purchase
FROM events
GROUP BY user_id;

اشتراط الخطوات بالتسلسل

مع توفر الطوابع الزمنية الأولى لكل خطوة، يصبح فرض الترتيب مسألة مقارنة. لا يكون المستخدم قد حوّل فعليًا إلى الخطوة 3 إلا إذا كانت كل الطوابع الزمنية غير فارغة ومتزايدة رتيبًا.

لاحظ أن الطابع الزمني NULL (أي أن الخطوة لم تحدث قط) يفشل المقارنة تلقائيًا، وهذا هو المطلوب تمامًا.

WITH t AS (
  SELECT user_id,
    MIN(CASE WHEN event_name='visit'    THEN event_time END) AS visit_t,
    MIN(CASE WHEN event_name='signup'   THEN event_time END) AS signup_t,
    MIN(CASE WHEN event_name='purchase' THEN event_time END) AS purchase_t
  FROM events GROUP BY user_id
)
SELECT COUNT(*) AS converted_in_order
FROM t
WHERE visit_t IS NOT NULL
  AND signup_t  >= visit_t
  AND purchase_t >= signup_t;

إضافة إطار زمني

تتضمن معظم مسارات التحويل مهلة نهائية: "أكمل التحويل خلال 7 أيام من أول زيارة". أضف حدًا زمنيًا بين الخطوة الأولى والخطوة النهائية.

تختلف العمليات الحسابية على التواريخ حسب اللهجة. ففي Postgres يمكنك كتابة visit_t + INTERVAL '7 days'، وفي MySQL استخدم DATE_ADD(visit_t, INTERVAL 7 DAY). اذكر دائمًا اللهجة التي تستخدمها.

WITH t AS (
  SELECT user_id,
    MIN(CASE WHEN event_name='visit'    THEN event_time END) AS visit_t,
    MIN(CASE WHEN event_name='purchase' THEN event_time END) AS purchase_t
  FROM events GROUP BY user_id
)
SELECT COUNT(*) AS purchased_within_7d
FROM t
WHERE purchase_t >= visit_t
  AND purchase_t <  visit_t + INTERVAL '7 days';

لماذا نستخدم الطابع الزمني الأول لا أي طابع زمني

هناك نقطة دقيقة في المقابلات: هل يجب أن تبدأ المهلة من أول زيارة للمستخدم أم من زيارته الأحدث التي سبقت التسجيل؟ يعتمد ذلك على سؤال المنتج.

  • تقيس نوافذ التفاعل الأول المدة من الاهتمام الأولي حتى التحويل.
  • تقيس نوافذ التفاعل الأخير مدة التحويل بعد الزيارة الأخيرة.

اسأل المحاور أي معنى يقصده؛ فاختيارك الواعي يشير إلى مستوى متقدم من الخبرة.

الأحداث المرتبة باستخدام LEAD

تتألق دوال النافذة في المسارات المعقدة متعددة الخطوات. رتّب أحداث كل مستخدم حسب الوقت، ثم استخدم LEAD للنظر في الحدث التالي والتأكد من أنه الخطوة التالية المتوقعة.

يتعامل هذا الأسلوب مع المسارات التي تتداخل فيها الخطوات مع أحداث غير مرتبطة.

SELECT
  user_id,
  event_name,
  event_time,
  LEAD(event_name) OVER (PARTITION BY user_id ORDER BY event_time) AS next_event,
  LEAD(event_time) OVER (PARTITION BY user_id ORDER BY event_time) AS next_time
FROM events;

مطابقة الخطوة التالية المتوقعة

طوّر الحل باستخدام LEAD: احتفظ بالصفوف التي يتبع فيها 'visit' مباشرةً 'signup'. فهذا يعثر على الانتقالات المتسلسلة الحقيقية، لا مجرد التواجد المشترك.

يمكنك ربط فحوصات الانتقال هذه للتحقق من مسار مرتب كامل خطوةً تلو الأخرى.

WITH seq AS (
  SELECT user_id, event_name, event_time,
    LEAD(event_name) OVER (PARTITION BY user_id ORDER BY event_time) AS next_event
  FROM events
)
SELECT COUNT(DISTINCT user_id) AS visit_then_signup
FROM seq
WHERE event_name = 'visit' AND next_event = 'signup';

الوقت بين الخطوات المتتالية

يحب المحاورون سؤال "كم تستغرق كل خطوة؟". استخدم LEAD مع الطابع الزمني ثم اطرح القيمتين. ويمثل الفرق بين الأحداث المتتالية مدة بقاء المستخدم في تلك المرحلة.

احسب الوسيط أو المتوسط لكل انتقال للعثور على أبطأ مرحلة في مسار التحويل.

WITH seq AS (
  SELECT user_id, event_name, event_time,
    LEAD(event_time) OVER (PARTITION BY user_id ORDER BY event_time) AS next_time
  FROM events
)
SELECT
  event_name,
  AVG(EXTRACT(EPOCH FROM (next_time - event_time)) / 3600.0) AS avg_hours_to_next
FROM seq
WHERE next_time IS NOT NULL
GROUP BY event_name;

حالة تساوي الطوابع الزمنية

ماذا يحدث إذا اشترك حدثان في قيمة event_time نفسها تمامًا؟ عندها تكون signup_t >= visit_t صحيحة حتى لو حدثا في الوقت نفسه، ويصبح الترتيب حسب الوقت وحده غامضًا.

  • استخدم >= أو > عن قصد، واذكر السبب.
  • أضف عامل كسر تعادل مثل معرّف تسلسل الحدث إلى ORDER BY حتى تكون النوافذ حتمية.

الإشارة إلى هذه النقطة من تلقاء نفسك تترك انطباعًا جيدًا لدى المحاورين.

SELECT user_id, event_name,
  ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY event_time, event_id) AS step_seq
FROM events;

دمج الترتيب والإطار الزمني في استعلام واحد

إليك مسار التحويل الكامل المرتب وضمن الإطار الزمني. فهو يعتمد على أول زيارة، ويشترط أن يحدث أول ظهور لكل خطوة لاحقة بعد الخطوة السابقة، ويقيّد المسار بأكمله بمدة 7 أيام.

هذه هي الإجابة التي تميّز المرشح الذي يفهم مسارات التحويل عن المرشح الذي يكتفي بعدّ المؤشرات.

WITH t AS (
  SELECT user_id,
    MIN(CASE WHEN event_name='visit'    THEN event_time END) AS v,
    MIN(CASE WHEN event_name='signup'   THEN event_time END) AS s,
    MIN(CASE WHEN event_name='purchase' THEN event_time END) AS p
  FROM events GROUP BY user_id
)
SELECT
  COUNT(*) FILTER (WHERE v IS NOT NULL)                                   AS visited,
  COUNT(*) FILTER (WHERE s >= v AND s < v + INTERVAL '7 days')            AS signed_up,
  COUNT(*) FILTER (WHERE s >= v AND p >= s AND p < v + INTERVAL '7 days') AS purchased
FROM t;

ملاحظات حول اللهجات المختلفة

تذكيران بشأن قابلية النقل عند كتابة التعليمات البرمجية مباشرةً:

  • تُعدّ FILTER (WHERE ...) على دوال التجميع جزءًا من SQL القياسي وتعمل في Postgres؛ أما في MySQL أو المحركات الأقدم، فاستخدم البديل SUM(CASE WHEN ... THEN 1 ELSE 0 END).
  • تختلف صيغة الفواصل الزمنية: في Postgres استخدم + INTERVAL '7 days'، وفي MySQL استخدم DATE_ADD(d, INTERVAL 7 DAY)، وفي SQL Server استخدم DATEADD(day, 7, d).

اذكر افتراضك، ونادرًا ما يهتم المحاور باللهجة التي اخترتها؛ ما يهمه هو أن تعرف أنها تختلف.

تحقق سريع

يجب أن تحسب المستخدمين الذين أكملوا المسار زيارة ← تسجيل ← شراء بالترتيب، خلال 7 أيام من الزيارة الأولى. أي نهج هو الصحيح؟

مراجعة: الأحداث المرتبة والنوافذ الزمنية

أهم النقاط:

  • التقط الطابع الزمني الأول لكل خطوة لكل مستخدم باستخدام MIN(CASE ...).
  • افرض التسلسل باشتراط أن يكون وقت كل خطوة في وقت الخطوة السابقة أو بعدها.
  • قيّد المسار باستخدام فترة زمنية، مع توضيح الصيغة الخاصة بلهجتك.
  • استخدم LEAD/LAG لفحص الانتقالات وحساب المدة بين الخطوات.
  • عالج حالات التعادل ذات الطابع الزمني نفسه باستخدام معيار لكسر التعادل في ORDER BY.

التالي: الانتقال من مسارات التحويل إلى التجارب وحساب المقاييس لكل متغير.

الأسئلة الشائعة

هل درس «الأحداث المرتبة والنوافذ الزمنية» مجاني؟

نعم — نص درس «الأحداث المرتبة والنوافذ الزمنية» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Coding Interview Prep، انتقل إلى CoddyKit PRO. تتضمن دورة Coding Interview Prep 4 دروس في المجموع.

ماذا ستتعلم في «الأحداث المرتبة والنوافذ الزمنية»؟

ضمان حدوث الخطوات بالتسلسل وضمن حد زمني باستخدام دوال النوافذ تتمرن على Coding Interview Prep مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Coding Interview Prep؟

لا تُشترط خبرة سابقة. Coding Interview Prep على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 4.

كم من الوقت يستغرق درس «الأحداث المرتبة والنوافذ الزمنية»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Coding Interview Prep هذا؟

نعم. كل درس في Coding Interview Prep يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. إنشاء مسار تحويل متعدد الخطوات
  2. الأحداث المرتبة والنوافذ الزمنية
  3. إسناد اختبارات A/B ومقاييسها
  4. التحسن والدلالة والضوابط في SQL
← العودة إلى Coding Interview Prep