بازگشت به وبلاگ

تحلیل تحویل FCM با BigQuery؛ از لاگ پیام تا عیب‌یابی

تحلیل تحویل FCM با BigQuery؛ از لاگ پیام تا عیب‌یابی

سرور می‌گوید پیام ارسال شده، اما کاربر اعلان را دریافت نکرده است. خروجی FCM در BigQuery کمک می‌کند مرحله آخر قابل مشاهده را پیدا کنید. این راهنما برای تیمی است که به پروژه Firebase دسترسی دارد و می‌خواهد اختلاف گزارش تحویل را با SQL بررسی کند.

برای تعریف شاخص‌های کسب‌وکار، ابتدا راهنمای نرخ تحویل، کلیک و تبدیل را بخوانید. در اینجا تمرکز روی لاگ فنی پیام، کیفیت داده و تصمیمی است که بعد از دیدن اختلاف آمار باید گرفت.

۱. پیش از نوشتن SQL، دسترسی و خروجی داده را بررسی کنید

اتصال Firebase به BigQuery از بخش تنظیمات و Integrations انجام می‌شود و به مجوزهای مناسب پروژه نیاز دارد. لینک‌کردن پروژه با مجوز مشاهده یک گزارش یکسان نیست؛ مدیر پروژه باید نقش لازم را تعیین کند. راهنمای رسمی خروجی داده Firebase این دسترسی‌ها و انتخاب برنامه‌های مشمول خروجی را توضیح می‌دهد.

در سرویس مدیریت‌شده، پنل ارسال پوش لزوماً دسترسی به پروژه Firebase یا BigQuery نمی‌دهد. مالک پروژه و اختیار فعال‌سازی خروجی را مشخص کنید. این راهنما اتصال آماده‌ای را در پنل پوشفا فرض نمی‌کند.

طبق مستند تحویل FCM، این خروجی به فعال‌بودن Google Analytics نیاز دارد؛ خروجی تحویل در وب نیز Firebase Web SDK نسخه 12.14.0 یا بالاتر می‌خواهد. تنظیم جمع‌آوری سمت کلاینت و تصمیم کاربر را جدا از اتصال پروژه بررسی کنید.

۲. هر رویداد چه چیزی را ثابت می‌کند؟

در لاگ FCM، MESSAGE_ACCEPTED پذیرش درخواست معتبر در سرور FCM و MESSAGE_DELIVERED رسیدن پیام به SDK دستگاه را نشان می‌دهد. رویداد دوم به‌تنهایی اثبات نمایش اعلان، مشاهده کاربر یا خواندن متن نیست. تعریف رسمی رویدادها مرز این دو مرحله را مشخص می‌کند.

«دریافت در SDK: ۸۰۰» را جای «۸۰۰ نفر پیام را دیدند» بنویسید. اگر نمایش یا کلیک را جدا ثبت می‌کنید، شناسه پیام داخلی را برای اتصال گزارش‌ها نگه دارید. تعریف رویداد و جمعیت دو گزارش باید یکسان باشد.

۳. ابتدا معلوم کنید چه کسانی در داده دیده می‌شوند

به چند دستگاه کنترل‌شده پیام بفرستید و نسخه برنامه، تصمیم جمع‌آوری داده، زمان و رفتار مشاهده‌شده را ثبت کنید. سپس ظهور رویدادها در خروجی را بررسی کنید؛ دریافت پیام و ثبت گزارش آن دو مسیر جدا هستند.

  • تعداد مخاطبان هدف را از تعداد مخاطبانی که داده قابل اتصال دارند جدا نگه دارید.
  • رکوردهای بدون شناسه نمونه برنامه را در یک شمارنده مستقل گزارش کنید؛ حذف خاموش آن‌ها مخرج را مبهم می‌کند.
  • دوره قبل و بعد از فعال‌سازی جمع‌آوری را در یک نمودار هم‌سطح مقایسه نکنید.
  • نسخه‌های جدید و قدیمی برنامه را جدا بررسی کنید؛ تغییر پوشش اندازه‌گیری می‌تواند شبیه تغییر کیفیت تحویل دیده شود.

FCM Data API نیز همان جدول خام BigQuery نیست؛ اطلاعات آن درباره انتقال پیام در اندروید به‌صورت تجمیعی ارائه می‌شود. از اختلاف این دو خروجی، بدون بررسی دامنه و پوشش داده، خرابی سامانه را نتیجه نگیرید. توضیح تفاوت دو مجموعه داده را مبنای مقایسه قرار دهید.

۴. نمونه SQL: دریافت‌های مرتبط با یک گروه ارسال

صورت‌مسئله این نمونه چنین است: پیام‌هایی که در یک روز پذیرفته شده‌اند، تا پایان مهلت مشاهده چند دریافت ثبت‌شده دارند؟ صورت و مخرج هر دو به همان گروه ارسال تعلق دارند؛ دریافت‌های روز بعد با ارسال‌های روز بعد مخلوط نمی‌شوند.

YOUR_PROJECT.YOUR_DATASET.YOUR_TABLE را با مسیر واقعی جدول جایگزین کنید؛ مسیر رایج خروجی PROJECT_ID.firebase_messaging.data است. نام برنامه و مقدار پلتفرم را از داده واقعی بردارید. تاریخ‌ها صرفاً مثال‌اند و برحسب UTC تنظیم شده‌اند. بازه بارگذاری را برای تأخیر خروجی داده متناسب با پروژه خود انتخاب کنید.

DECLARE sent_from TIMESTAMP DEFAULT TIMESTAMP('2026-09-01 00:00:00+00');
DECLARE sent_until TIMESTAMP DEFAULT TIMESTAMP('2026-09-02 00:00:00+00');
DECLARE observed_until TIMESTAMP DEFAULT TIMESTAMP('2026-09-08 00:00:00+00');

WITH raw AS (
  SELECT project_number, app_name, sdk_platform,
         message_id, instance_id, event, event_timestamp
  FROM `YOUR_PROJECT.YOUR_DATASET.YOUR_TABLE`
  WHERE _PARTITIONTIME >= TIMESTAMP('2026-09-01')
    AND _PARTITIONTIME < TIMESTAMP('2026-09-12')
    AND event_timestamp >= sent_from
    AND event_timestamp < observed_until
    AND app_name = 'YOUR_APP_NAME'
    AND sdk_platform = 'YOUR_SDK_PLATFORM'
    AND message_id IS NOT NULL AND message_id != ''
    AND instance_id IS NOT NULL AND instance_id != ''
), accepted AS (
  SELECT project_number, app_name, sdk_platform, message_id, instance_id,
         MIN(event_timestamp) AS accepted_at
  FROM raw
  WHERE event = 'MESSAGE_ACCEPTED' AND event_timestamp < sent_until
  GROUP BY project_number, app_name, sdk_platform, message_id, instance_id
), paired AS (
  SELECT a.project_number, a.app_name, a.sdk_platform,
         a.message_id, a.instance_id, a.accepted_at,
         MIN(d.event_timestamp) AS delivered_at
  FROM accepted AS a
  LEFT JOIN raw AS d
    ON d.project_number = a.project_number AND d.app_name = a.app_name
    AND d.sdk_platform = a.sdk_platform AND d.message_id = a.message_id
    AND d.instance_id = a.instance_id AND d.event = 'MESSAGE_DELIVERED'
    AND d.event_timestamp >= a.accepted_at
  GROUP BY a.project_number, a.app_name, a.sdk_platform,
           a.message_id, a.instance_id, a.accepted_at
)
SELECT COUNT(*) AS accepted_pairs,
       COUNTIF(delivered_at IS NOT NULL) AS observed_delivered_pairs,
       SAFE_DIVIDE(COUNTIF(delivered_at IS NOT NULL), COUNT(*)) AS observed_ratio
FROM paired;

طبق طرح‌واره FCM، message_id همیشه در مقیاس جهانی یکتا نیست. این نمونه با پروژه، برنامه، پلتفرم و instance_id جفت می‌سازد و تکرارهای هر جفت را تجمیع می‌کند. این کلید یک انتخاب تحلیلی برای بازه محدود است؛ برخورد شناسه یا چند ارسال واقعی با همان کلید همچنان باید بررسی شود. رکوردهای بدون شناسه و ارسال‌های گروهی فاقد گیرنده قابل اتصال در این محاسبه نیستند.

توابع COUNTIF و MIN در مرجع توابع تجمیعی GoogleSQL مستند شده‌اند. خروجی این پرس‌وجو «نسبت دریافت ثبت‌شده در جمعیت قابل اتصال» است؛ آن را نرخ قطعی تحویل به همه مشترکان ننامید.

۵. اختلاف نتیجه را به یک تصمیم قابل اجرا تبدیل کنید

فرض کنید در یک مثال آموزشی، ۱۰۰۰ جفت پذیرفته‌شده و ۸۲۰ جفت دارای دریافت ثبت‌شده پیدا می‌کنید. عدد ۸۲ درصد، عملکرد واقعی پوشفا یا هیچ کسب‌وکاری نیست؛ فقط نتیجه فرضی نمونه است. درباره ۱۸۰ جفت باقی‌مانده هنوز نمی‌دانید مشکل دریافت بوده، ثبت داده ناقص است یا فرصت مشاهده کافی نیست.

  1. اگر ارسال در لاگ پذیرش دیده نمی‌شود: ابتدا لاگ خروجی سرور، شناسه درخواست، زمان و پروژه مقصد را تطبیق دهید. اشتباه در فیلتر نام برنامه می‌تواند کل گروه را پنهان کند.
  2. اگر پذیرش هست و دریافت ثبت نشده: تنظیمات جمع‌آوری و پوشش کلاینت را بررسی کنید؛ سپس عمر پیام و وضعیت دستگاه‌های کنترل‌شده را بسنجید. برای زمان اعتبار پیام، راهنمای TTL در حالت آفلاین مفید است.
  3. اگر دریافت هست و اعلان دیده نمی‌شود: از لایه انتقال عبور کرده‌اید؛ مسیر نمایش، مجوزها و وضعیت برنامه را بررسی کنید. افزایش تعداد ارسال، مشکل نمایش را حل نمی‌کند.
  4. اگر نمایش ثبت شده ولی وب‌هوک شما نرسیده: مسیر ثبت و دریافت گزارش را بررسی کنید. نبود گزارش را مجوز ارسال دوباره قرار ندهید؛ راهنمای وب‌هوک بومرنگ و جلوگیری از ارسال تکراری این بخش را توضیح می‌دهد.

۶. هزینه و حریم خصوصی را در طراحی گزارش لحاظ کنید

قبل از اجرای پرس‌وجو، برآورد حجم خواندن یا dry run را ببینید و در مدل پرداخت برحسب مصرف، سقف maximum bytes billed تعیین کنید. فقط گذاشتن LIMIT برای جدول بدون خوشه‌بندی، هزینه خواندن را محدود نمی‌کند. راهنمای کنترل هزینه BigQuery روش‌های مناسب را توضیح می‌دهد.

برای کار روزمره خروجی تجمیعی بدون شناسه دستگاه بسازید و دسترسی خام را محدود کنید. شناسه نصب را بی‌دلیل به اطلاعات شخصی وصل نکنید. هدف تحلیل، مدت نگهداری و تصمیم کاربر درباره جمع‌آوری را مشخص کنید؛ توکن یا اطلاعات شخصی را در تیکت عمومی ننویسید.

قطع اتصال خروجی، داده قبلی را خودکار پاک نمی‌کند؛ در صورت نیاز به حذف، سیاست نگهداری و داده‌های باقی‌مانده را جدا بررسی کنید. این رفتار در مستند قطع اتصال Firebase و BigQuery توضیح داده شده است.

۷. پرسش‌های رایج درباره گزارش تحویل FCM

آیا BigQuery برای هشدار لحظه‌ای مناسب است؟

خروجی معمول FCM روزانه است و راه‌اندازی اولیه می‌تواند تا ۴۸ ساعت زمان ببرد. برای تشخیص فوری، لاگ ارسال و رخدادهای عملیاتی خودتان را هم داشته باشید؛ غیبت رکورد در خروجی تازه، دلیل کافی برای شکست ارسال نیست. زمان‌بندی رسمی خروجی Firebase را بررسی کنید.

آیا با این داده می‌توان فهمید کاربر پیام را خوانده است؟

خیر. دریافت فنی، نمایش، کلیک و خواندن چهار ادعای متفاوت‌اند. هر کدام به شاهد متناسب نیاز دارد و حتی کلیک به معنی خواندن کامل صفحه نیست.

برای یک اختلاف آماری، از کجا شروع کنیم؟

از یک پیام و یک دستگاه شناخته‌شده شروع کنید، شناسه‌ها و زمان‌ها را تطبیق دهید و سپس بررسی را به یک نسخه برنامه یا گروه مخاطب گسترش دهید. بعد از روشن‌شدن پوشش اندازه‌گیری، تغییرات نرخ را تحلیل کنید. خروجی SQL باید مشخص کند درباره چه جمعیتی و تا چه زمانی حرف می‌زند.