تحويل البيانات بدون خادم باستخدام Apache Spark في دفاتر ملاحظات BigQuery Studio

1- مقدمة

في هذا الدرس التطبيقي حول الترميز، ستتعرّف على كيفية الاستفادة من إمكانات Apache Spark لتحويل البيانات ضمن الواجهة المألوفة في BigQuery Studio. ستقرأ البيانات من BigQuery، وتجري عملية تنظيف البيانات وتحويلها باستخدام PySpark، وتكتب النتائج مرة أخرى في جدول BigQuery جديد، وكل ذلك من ورقة ملاحظات واحدة.

خلال الدرس التطبيقي حول الترميز، ستتّبع نهجًا تدريجيًا على النحو التالي:

  1. إعداد مشروع على السحابة الإلكترونية من Google Cloud وتفعيل جميع واجهات برمجة التطبيقات المطلوبة فيه
  2. إنشاء حزمة في Cloud Storage لمجلد مؤقت
  3. استيراد المكتبات المطلوبة لتشغيل Apache Spark
  4. تهيئة جلسة Spark باستخدام أداة الربط BigQuery
  5. قراءة عينة بيانات "إحصاءات Google" من مجموعة البيانات العامة في BigQuery
  6. تحويل البيانات باستخدام تجميع البيانات حسب متصفّح الجهاز (المقاييس الأساسية)
  7. تحويل البيانات باستخدام تحليل مصدر الزيارات مع احتساب الإيرادات
  8. تحويل البيانات باستخدام التحليل الجغرافي
  9. كتابة البيانات بعد تحويلها في جدول BigQuery

نظرة عامة على البنية

186f332da87c2ef3.png

المتطلبات الأساسية

  • مشروع على Google Cloud Platform (GCP) تم تفعيل الفوترة فيه
  • تفعيل BigQuery API وBigQuery Connection API في مشروع GCP
  • معرفة أساسية بلغتَي SQL وPython

ما ستتعلمه

  • كيفية استخراج البيانات باستخدام Apache Spark في ورقة ملاحظات BigQuery Studio
  • كيفية تحويل البيانات أو تجميعها باستخدام Apache Spark في ورقة ملاحظات BigQuery Studio
  • كيفية كتابة البيانات بعد تحويلها أو تجميعها باستخدام Apache Spark في ورقة ملاحظات BigQuery Studio

ما تحتاج إليه

  • متصفّح الويب Chrome
  • حساب Gmail
  • مشروع على السحابة الإلكترونية تم تفعيل الفوترة فيه

2- الإعداد الأساسي والمتطلبات

إعداد بيئة الاختبار الذاتية

  1. سجِّل الدخول إلى Google Cloud Console وأنشِئ مشروعًا جديدًا أو أعِد استخدام مشروع حالي. إذا لم يكن لديك حساب على Gmail أو Google Workspace، عليك إنشاء حساب.

fbef9caa1602edd0.png

97bdebccea2ba4be.png

5e3ff691252acf41.png

  • اسم المشروع هو الاسم المعروض للمشاركين في هذا المشروع. وهو عبارة عن سلسلة أحرف لا تستخدمها Google APIs. يمكنك تعديله في أي وقت.
  • رقم تعريف المشروع فريد بين جميع مشاريع Google Cloud ولا يمكن تغييره (لا يمكن تعديله بعد ضبطه). تُنشئ Cloud Console تلقائيًا سلسلة فريدة، ولا يهمّك عادةً ما هي. في معظم الدروس التطبيقية حول الترميز، عليك الرجوع إلى رقم تعريف مشروعك (يُشار إليه عادةً باسم PROJECT_ID). إذا لم يعجبك رقم التعريف الذي تم إنشاؤه، يمكنك إنشاء رقم تعريف عشوائي آخر. بدلاً من ذلك، يمكنك تجربة رقم تعريف خاص بك ومعرفة ما إذا كان متاحًا. لا يمكن تغييره بعد هذه الخطوة ويظل ساريًا طوال مدة المشروع.
  • للعلم، هناك قيمة ثالثة، وهي رقم تعريف المشروع، تستخدمه بعض واجهات برمجة التطبيقات. يمكنك الاطّلاع على مزيد من المعلومات عن هذه القيم الثلاث في المستندات.
  1. بعد ذلك، عليك تفعيل الفوترة في Cloud Console لاستخدام موارد السحابة الإلكترونية وواجهات برمجة التطبيقات. لن يكلفك إكمال هذا الدرس التطبيقي حول الترميز الكثير، إن وُجدت أي تكلفة على الإطلاق. لإيقاف الموارد وتجنُّب تكبّد رسوم فوترة تتجاوز هذا البرنامج التعليمي، يمكنك حذف الموارد التي أنشأتها أو حذف المشروع. يمكن لمستخدمي Google Cloud الجدد الاستفادة من برنامج التجربة المجانية بقيمة 300 دولار أمريكي.

3- قبل البدء

تفعيل واجهة برمجة التطبيقات

قبل استخدام أوراق ملاحظات BigQuery Studio، يجب تفعيل واجهات برمجة التطبيقات التالية:

  • ‫Compute Engine API
  • ‫Dataform API
  • ‫Vertex AI API

لتفعيلها يدويًا، انتقِل إلى BigQuery. في شريط علامات التبويب في لوحة المحرّر، انقر على القائمة المنسدلة للسهم بجانب علامة + ، وأشِر إلى ورقة ملاحظات ، ثم اختَر نموذج BigQuery أو ورقة ملاحظات فارغة أو نموذج Spark

2073fec24366e7c4.png

في النافذة "تفعيل واجهة برمجة التطبيقات للميزة الأساسية"، انقر على "تفعيل" في BigQuery Unified API.

44dc4e398b4e8fb5.png

بعد الانتهاء، انقر على "تفعيل"، ثم على "إغلاق". يُرجى الرجوع إلى مقالة تفعيل BigQuery Studio لإدارة مواد العرض لمزيد من التفاصيل.

4- قراءة مجموعة بيانات عامة

أولاً، سننشئ حزمة في Cloud Storage للاستخدام المؤقت حتى نتمكّن من تشغيل Spark في أوراق ملاحظات BigQuery Studio.

  1. في Google Cloud Console، انتقِل إلى BigQuery.
  2. في شريط علامات التبويب في لوحة المحرّر، انقر على القائمة المنسدلة للسهم بجانب علامة + ، وأشِر إلى ورقة ملاحظات ، ثم اختَر ورقة ملاحظات فارغةdc05f38b85ba6844.png
  3. انقر على خلية الرمز، ثم اكتب نصًا برمجيًا لواجهة سطر الأوامر أدناه لإنشاء حزمة في Cloud Storage، ثم انقر على الزر "تشغيل الخلية" أو اضغط على Shift + Enter.
!gsutil mb -p <your_project_id> -c STANDARD -l US gs://ioxid2025-<your_project_id>

عدِّل قيم <your_project_id> بما يتوافق مع ما اخترته أثناء إنشاء مشروع Google Cloud. عدِّل قيم <your_project_id> باستخدام رقم تعريف مشروعك لإنشاء اسم حزمة فريد في Cloud Storage. بعد ذلك، انقر على الزر "تشغيل الخلية" أو اضغط على Shift + Enter لتشغيل خلية الرمز.

بعد ذلك، سنبدأ جلسة Spark. في هذا الدرس التطبيقي حول الترميز، سنستخدم مكتبة SparkSession على الرغم من أنّه يمكننا استخدام DataprocSession للاستفادة من إمكانات Dataproc لتشغيل Spark في ورقة ملاحظات BigQuery Studio.

  1. انقر على خلية الرمز، ثم اكتب نصًا برمجيًا لواجهة سطر الأوامر أدناه لتهيئة جلسة Spark. انقر على الزر "تشغيل الخلية" أو اضغط على Shift + Enter.
# Import required libraries 
from pyspark.sql import SparkSession 
from pyspark.sql.functions import col, sum, count, countDistinct, when, expr, date_format 
from pyspark.sql.types import DecimalType 

# Initialize Spark session with BigQuery connector 
from pyspark.sql import SparkSession
from pyspark.sql.functions import col, sum, count, countDistinct, when, expr, date_format
from pyspark.sql.types import DecimalType

# Initialize Spark session with BigQuery connector
spark = SparkSession.builder \
 .appName("Google Analytics ETL with Apache Spark") \
 .config("spark.jars.packages", "com.google.cloud.spark:spark-bigquery-with-dependencies_2.12:0.32.0") \
 .getOrCreate()

spark

الناتج المتوقَّع :

SparkSession - in-memory
SparkContext
Spark UI
Version
v3.5.4
Master
local[*]
AppName
Google Analytics ETL with Apache Spark
  1. انقر على خلية الرمز، ثم اكتب نصًا برمجيًا لواجهة سطر الأوامر أدناه لضبط مشروع GCP وحزمة Cloud Storage المؤقتة.
# Set GCP project and temporary bucket 
project_id = "your-gcp-project-id"  # Replace with your GCP project ID 
bucket = "your-gcs-bucket"  # Replace with your GCS bucket for temporary files spark.conf.set("temporaryGcsBucket", bucket)

عينة قاعدة بيانات "إحصاءات Google"

يتم توفير عينة قاعدة بيانات "إحصاءات Google" على BigQuery من خلال برنامج مجموعات البيانات العامة في Google Cloud. توفر مجموعة البيانات 12 شهرًا (من أغسطس 2016 إلى أغسطس 2017) من بيانات "إحصاءات Google 360" التي تم إخفاء مفاتيح فك تشفيرها من متجر بيع سلع Google ، وهو متجر تجارة إلكترونية فعلي يبيع سلعًا تحمل علامة Google التجارية، في BigQuery. إنّها طريقة رائعة لتحليل بيانات النشاط الإعلاني ومعرفة مزايا استخدام BigQuery لتحليل بيانات "إحصاءات 360". مزيد من المعلومات عن البيانات

تشمل البيانات ما يظهر عادةً في أي موقع ويب للتجارة الإلكترونية، وتتضمّن المعلومات التالية:

  • بيانات مصادر الزيارات: معلومات حول مصدر زوّار موقع الويب، بما في ذلك بيانات عن الزيارات الواردة من نتائج البحث المجانية، وزيارات نتائج البحث المدفوعة، وزيارات الشبكة الإعلانية
  • بيانات المحتوى: معلومات حول سلوك المستخدمين في موقع الويب، مثل عناوين URL للصفحات التي يتصفّحها الزوّار، وكيفية تفاعلهم مع المحتوى، وما إلى ذلك
  • بيانات المعاملات: معلومات عن المعاملات على موقع "متجر بيع سلع Google" الإلكتروني

شغِّل الرمز أدناه لعرض عينة من أفضل 5 بيانات في Apache Spark.

# EXTRACT: Read data from BigQuery
print("Extracting data from BigQuery...")
ga_df = spark.read.format("bigquery") \
   .option("table", "bigquery-public-data.google_analytics_sample.ga_sessions_20170801") \
   .load()

# Show schema sample data
print("Sample data:")
ga_df.show(5, truncate=False)

الناتج المتوقَّع :

Extracting data from BigQuery...
Sample data:
+---------+-----------+----------+--------------+--------+---------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------+------+--------+---------------+--------------------+
|visitorId|visitNumber|visitId   |visitStartTime|date    |totals                                                         |trafficSource                                                                                                                                                                          |device                                                                                                                                                                                                                                                                                                                                                                                                                      |geoNetwork                                                                                                                                                                                                                                                                     |customDimensions    |hits                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |fullVisitorId      |userId|clientId|channelGrouping|socialEngagementType|
+---------+-----------+----------+--------------+--------+---------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------+------+--------+---------------+--------------------+
|NULL     |1          |1501591568|1501591568    |20170801|{1, 1, 1, NULL, 1, NULL, NULL, 1, NULL, NULL, NULL, NULL, 1}   |{NULL, (not set), (direct), (none), NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, not available in demo dataset, NULL, NULL, NULL, NULL, NULL}, NULL, NULL}                         |{Chrome, not available in demo dataset, not available in demo dataset, Windows, not available in demo dataset, false, not available in demo dataset, not available in demo dataset, not available in demo dataset, not available in demo dataset, not available in demo dataset, not available in demo dataset, NULL, not available in demo dataset, not available in demo dataset, not available in demo dataset, desktop} |{Europe, Southern Europe, Greece, not available in demo dataset, not available in demo dataset, not available in demo dataset, not available in demo dataset, tellas.gr, not available in demo dataset, not available in demo dataset, not available in demo dataset}          |[]                  |[{1, 0, 5, 46, NULL, true, true, true, https://www.google.gr/, {/google+redesign/bags/google+zipper+front+sports+bag.axd, shop.googlemerchandisestore.com, Page Unavailable, NULL, NULL, /google+redesign/, /bags/, /google+zipper+front+sports+bag.axd, }, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, shop.googlemerchandisestore.com/google+redesign/bags/google+zipper+front+sports+bag.axd, shop.googlemerchandisestore.com/google+redesign/bags/google+zipper+front+sports+bag.axd, shop.googlemerchandisestore.com/google+redesign/bags/google+zipper+front+sports+bag.axd, 0}, {NULL, true, NULL, NULL}, NULL, [], [], NULL, NULL, {0, 1, NULL}, [], NULL, [], [], [], PAGE, {NULL, NULL, NULL, NULL, (not set), NULL, No,  : }, NULL, NULL, {(not set), Bags, (not set), (not set), (not set), (entrance), (entrance), (entrance), (entrance), (entrance), NULL, 1, NULL, NULL, NULL}, web, []}]     |3418334011779872055|NULL  |NULL    |Organic Search |Not Socially Engaged|
|NULL     |2          |1501589647|1501589647    |20170801|{1, 1, 1, NULL, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1}|{/analytics/web/, (not set), analytics.google.com, referral, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, not available in demo dataset, NULL, NULL, NULL, NULL, NULL}, NULL, NULL}|{Chrome, not available in demo dataset, not available in demo dataset, Windows, not available in demo dataset, false, not available in demo dataset, not available in demo dataset, not available in demo dataset, not available in demo dataset, not available in demo dataset, not available in demo dataset, NULL, not available in demo dataset, not available in demo dataset, not available in demo dataset, desktop} |{Asia, Southern Asia, India, Maharashtra, (not set), Mumbai, not available in demo dataset, unknown.unknown, not available in demo dataset, not available in demo dataset, not available in demo dataset}                                                                      |[{4, APAC}]         |[{1, 0, 5, 14, NULL, true, true, true, https://analytics.google.com/analytics/web/, {/google+redesign/shop+by+brand/youtube, shop.googlemerchandisestore.com, Page Unavailable, NULL, NULL, /google+redesign/, /shop+by+brand/, /youtube, }, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, shop.googlemerchandisestore.com/google+redesign/shop+by+brand/youtube, shop.googlemerchandisestore.com/google+redesign/shop+by+brand/youtube, shop.googlemerchandisestore.com/google+redesign/shop+by+brand/youtube, 0}, {NULL, true, NULL, NULL}, NULL, [], [], NULL, NULL, {0, 1, NULL}, [], NULL, [], [], [], PAGE, {NULL, NULL, NULL, NULL, (not set), NULL, No,  : }, NULL, NULL, {(not set), Brands, (not set), (not set), (not set), (entrance), (entrance), (entrance), (entrance), (entrance), NULL, 1, NULL, NULL, NULL}, web, []}]                                                                        |2474397855041322408|NULL  |NULL    |Referral       |Not Socially Engaged|
|NULL     |1          |1501616621|1501616621    |20170801|{1, 1, 1, NULL, 1, NULL, NULL, 1, NULL, NULL, NULL, NULL, 1}   |{/analytics/web/, (not set), analytics.google.com, referral, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, not available in demo dataset, NULL, NULL, NULL, NULL, NULL}, NULL, NULL}|{Chrome, not available in demo dataset, not available in demo dataset, Windows, not available in demo dataset, false, not available in demo dataset, not available in demo dataset, not available in demo dataset, not available in demo dataset, not available in demo dataset, not available in demo dataset, NULL, not available in demo dataset, not available in demo dataset, not available in demo dataset, desktop} |{Europe, Northern Europe, United Kingdom, not available in demo dataset, not available in demo dataset, not available in demo dataset, not available in demo dataset, as9105.com, not available in demo dataset, not available in demo dataset, not available in demo dataset} |[{4, EMEA}]         |[{1, 0, 12, 43, NULL, true, true, true, https://analytics.google.com/analytics/web/?utm_source=demoaccount&utm_medium=demoaccount&utm_campaign=demoaccount, {/google+redesign/shop+by+brand/youtube, shop.googlemerchandisestore.com, Page Unavailable, NULL, NULL, /google+redesign/, /shop+by+brand/, /youtube, }, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, shop.googlemerchandisestore.com/google+redesign/shop+by+brand/youtube, shop.googlemerchandisestore.com/google+redesign/shop+by+brand/youtube, shop.googlemerchandisestore.com/google+redesign/shop+by+brand/youtube, 0}, {NULL, true, NULL, NULL}, NULL, [], [], NULL, NULL, {0, 1, NULL}, [], NULL, [], [], [], PAGE, {NULL, NULL, NULL, NULL, (not set), NULL, No,  : }, NULL, NULL, {(not set), Brands, (not set), (not set), (not set), (entrance), (entrance), (entrance), (entrance), (entrance), NULL, 1, NULL, NULL, NULL}, web, []}]|5870462820713110108|NULL  |NULL    |Referral       |Not Socially Engaged|
|NULL     |1          |1501601200|1501601200    |20170801|{1, 1, 1, NULL, 1, NULL, NULL, 1, NULL, NULL, NULL, NULL, 1}   |{/analytics/web/, (not set), analytics.google.com, referral, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, not available in demo dataset, NULL, NULL, NULL, NULL, NULL}, NULL, NULL}|{Firefox, not available in demo dataset, not available in demo dataset, Windows, not available in demo dataset, false, not available in demo dataset, not available in demo dataset, not available in demo dataset, not available in demo dataset, not available in demo dataset, not available in demo dataset, NULL, not available in demo dataset, not available in demo dataset, not available in demo dataset, desktop}|{Americas, Northern America, United States, Texas, Dallas-Ft. Worth TX, Dallas, not available in demo dataset, h5colo.com, not available in demo dataset, not available in demo dataset, not available in demo dataset}                                                        |[{4, North America}]|[{1, 0, 8, 26, NULL, true, true, true, https://analytics.google.com/analytics/web/, {/google+redesign/shop+by+brand/youtube, shop.googlemerchandisestore.com, Page Unavailable, NULL, NULL, /google+redesign/, /shop+by+brand/, /youtube, }, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, shop.googlemerchandisestore.com/google+redesign/shop+by+brand/youtube, shop.googlemerchandisestore.com/google+redesign/shop+by+brand/youtube, shop.googlemerchandisestore.com/google+redesign/shop+by+brand/youtube, 0}, {NULL, true, NULL, NULL}, NULL, [], [], NULL, NULL, {0, 1, NULL}, [], NULL, [], [], [], PAGE, {NULL, NULL, NULL, NULL, (not set), NULL, No,  : }, NULL, NULL, {(not set), Brands, (not set), (not set), (not set), (entrance), (entrance), (entrance), (entrance), (entrance), NULL, 1, NULL, NULL, NULL}, web, []}]                                                                        |9397809171349480379|NULL  |NULL    |Referral       |Not Socially Engaged|
|NULL     |1          |1501615525|1501615525    |20170801|{1, 1, 1, NULL, 1, NULL, NULL, 1, NULL, NULL, NULL, NULL, 1}   |{/analytics/web/, (not set), adwords.google.com, referral, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, not available in demo dataset, NULL, NULL, NULL, NULL, NULL}, NULL, NULL}  |{Chrome, not available in demo dataset, not available in demo dataset, Windows, not available in demo dataset, false, not available in demo dataset, not available in demo dataset, not available in demo dataset, not available in demo dataset, not available in demo dataset, not available in demo dataset, NULL, not available in demo dataset, not available in demo dataset, not available in demo dataset, desktop} |{Americas, Northern America, United States, not available in demo dataset, not available in demo dataset, not available in demo dataset, not available in demo dataset, (not set), not available in demo dataset, not available in demo dataset, not available in demo dataset}|[{4, North America}]|[{1, 0, 12, 25, NULL, true, true, true, https://adwords.google.com/analytics/web/?__o=cues&authuser=0, {/google+redesign/shop+by+brand/youtube, shop.googlemerchandisestore.com, Page Unavailable, NULL, NULL, /google+redesign/, /shop+by+brand/, /youtube, }, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, shop.googlemerchandisestore.com/google+redesign/shop+by+brand/youtube, shop.googlemerchandisestore.com/google+redesign/shop+by+brand/youtube, shop.googlemerchandisestore.com/google+redesign/shop+by+brand/youtube, 0}, {NULL, true, NULL, NULL}, NULL, [], [], NULL, NULL, {0, 1, NULL}, [], NULL, [], [], [], PAGE, {NULL, NULL, NULL, NULL, (not set), NULL, No,  : }, NULL, NULL, {(not set), Brands, (not set), (not set), (not set), (entrance), (entrance), (entrance), (entrance), (entrance), NULL, 1, NULL, NULL, NULL}, web, []}]                                                     |6089902943184578335|NULL  |NULL    |Referral       |Not Socially Engaged|
+---------+-----------+----------+--------------+--------+---------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------+------+--------+---------------+--------------------+
only showing top 5 rows

5- تجميع البيانات حسب متصفّح الجهاز (المقاييس الأساسية)

يُجمِّع هذا الرمز بيانات "إحصاءات Google" حسب متصفّح الجهاز، ويحتسب مقاييس مختلفة مثل إجمالي الجلسات والزيارات والنتائج وعمليات مشاهدة الصفحات على الويب وعدد مرات الارتداد والوقت المستغرَق في الموقع والزوّار الفريدون ومتوسط الوقت لكل زيارة، ثم يعيد تسمية عمود ويُرتِّب النتائج.

print("Transformation 1: Aggregating by device browser...")
device_agg = ga_df.groupBy("device.browser") \
   .agg(
       count("*").alias("total_sessions"),
       sum("totals.visits").alias("total_visits"),
       sum("totals.hits").alias("total_hits"),
       sum("totals.pageviews").alias("total_pageviews"),
       sum("totals.bounces").alias("total_bounces"),
       sum("totals.timeOnSite").alias("total_time_on_site"),
       countDistinct("fullVisitorId").alias("unique_visitors"),
       (sum("totals.timeOnSite")/sum("totals.visits")).alias("avg_time_per_visit")
   ) \
   .withColumnRenamed("browser", "device_browser") \
   .orderBy("total_sessions", ascending=False)

# Show sample transformed data
print("\nDevice Aggregation Sample:")
device_agg.show(5)

الناتج المتوقَّع :

Transformation 1: Aggregating by device browser...

Device Aggregation Sample:
+-----------------+--------------+------------+----------+---------------+-------------+------------------+---------------+------------------+
|   device_browser|total_sessions|total_visits|total_hits|total_pageviews|total_bounces|total_time_on_site|unique_visitors|avg_time_per_visit|
+-----------------+--------------+------------+----------+---------------+-------------+------------------+---------------+------------------+
|           Chrome|          1900|        1900|     10896|           8956|          870|            354691|           1689|186.67947368421054|
|           Safari|           397|         397|      1260|           1137|          218|             43150|            364|108.69017632241814|
|          Firefox|           101|         101|       390|            343|           59|             10659|             95|105.53465346534654|
|Internet Explorer|            54|          54|       107|            102|           36|              5589|             50|             103.5|
|             Edge|            23|          23|        63|             55|           12|              2623|             23|114.04347826086956|
+-----------------+--------------+------------+----------+---------------+-------------+------------------+---------------+------------------+
only showing top 5 rows

6- تحليل مصدر الزيارات مع احتساب الإيرادات

يُحلِّل هذا الرمز بيانات "إحصاءات Google" حسب مصدر الزيارات والوسيط، ويحتسب مقاييس مثل عدد الجلسات والمعاملات وإجمالي الإيرادات والإيرادات لكل جلسة والزوّار الفريدون، ثم يعيد تسمية الأعمدة ويُرتِّب النتائج حسب إجمالي الإيرادات.

print("Transformation 2: Analyzing traffic sources...")
traffic_source_agg = ga_df.groupBy("trafficSource.source", "trafficSource.medium") \
   .agg(
       count("*").alias("session_count"),
       sum(when(col("totals.transactions").isNotNull(), 1).otherwise(0)).alias("transactions"),
       sum("totals.totalTransactionRevenue").cast(DecimalType(20,2)).alias("total_revenue"),
       (sum("totals.totalTransactionRevenue")/count("*")).cast(DecimalType(10,2)).alias("revenue_per_session"),
       countDistinct("fullVisitorId").alias("unique_visitors")
   ) \
   .withColumnRenamed("source", "traffic_source") \
   .withColumnRenamed("medium", "traffic_medium") \
   .orderBy("total_revenue", ascending=False)

print("\nTraffic Source Aggregation Sample:")
traffic_source_agg.show(5)

الناتج المتوقَّع :

Transformation 2: Analyzing traffic sources...

Traffic Source Aggregation Sample:
+--------------------+--------------+-------------+------------+-------------+-------------------+---------------+
|      traffic_source|traffic_medium|session_count|transactions|total_revenue|revenue_per_session|unique_visitors|
+--------------------+--------------+-------------+------------+-------------+-------------------+---------------+
|            (direct)|        (none)|         2166|          42|8872040000.00|         4096048.01|           1943|
|     mail.google.com|      referral|            2|           1|  17960000.00|         8980000.00|              2|
|       google.com.tw|      referral|            1|           0|         NULL|               NULL|              1|
|analytics.google.com|      referral|           57|           0|         NULL|               NULL|             53|
|           quora.com|      referral|            6|           0|         NULL|               NULL|              5|
+--------------------+--------------+-------------+------------+-------------+-------------------+---------------+
only showing top 5 rows

7- التحليل الجغرافي

يُجري هذا الرمز تحليلاً جغرافيًا لبيانات "إحصاءات Google" حسب البلد والمنطقة، ويحتسب عدد الجلسات وإجمالي مشاهدات الصفحات وإجمالي الوقت المستغرَق في الموقع ومتوسط الوقت لكل جلسة والزوّار الفريدين، ثم يعيد تسمية الأعمدة ويُرتِّب النتائج حسب عدد الجلسات.

print("Transformation 3: Geographic analysis...")
geo_agg = ga_df.groupBy("geoNetwork.country", "geoNetwork.region") \
   .agg(
       count("*").alias("session_count"),
       sum("totals.pageviews").alias("total_pageviews"),
       sum("totals.timeOnSite").alias("total_time_on_site"),
       (sum("totals.timeOnSite")/count("*")).alias("avg_time_per_session"),
       countDistinct("fullVisitorId").alias("unique_visitors")
   ) \
   .withColumnRenamed("country", "country") \
   .withColumnRenamed("region", "region") \
   .orderBy("session_count", ascending=False)

print("\nGeographic Aggregation Sample:")
geo_agg.show(5)

الناتج المتوقَّع :

Transformation 3: Geographic analysis...

Geographic Aggregation Sample:
+--------------+--------------------+-------------+---------------+------------------+--------------------+---------------+
|       country|              region|session_count|total_pageviews|total_time_on_site|avg_time_per_session|unique_visitors|
+--------------+--------------------+-------------+---------------+------------------+--------------------+---------------+
| United States|not available in ...|          564|           2326|             97829|  173.45567375886526|            494|
| United States|          California|          420|           3102|            116563|   277.5309523809524|            347|
| United States|            New York|          109|            845|             39976|   366.7522935779817|             84|
|United Kingdom|not available in ...|           82|            161|              7791|   95.01219512195122|             79|
|         India|not available in ...|           62|            139|              2869|  46.274193548387096|             61|
+--------------+--------------------+-------------+---------------+------------------+--------------------+---------------+
only showing top 5 rows

8- التحليل المستند إلى الوقت

يُجري هذا الرمز تحليلاً مستندًا إلى الوقت من خلال استخراج الساعة من عمود visitStartTime، ثم يُجمِّع البيانات حسب الساعة لاحتساب عدد الجلسات والمعاملات وإجمالي الإيرادات وإجمالي عمليات عرض الصفحات لكل ساعة، وأخيرًا يُرتِّب النتائج حسب الساعة.

print("Transformation 4: Time-based analysis...")
hourly_agg = ga_df.withColumn("hour", date_format(col("visitStartTime").cast("timestamp"), "H")) \
   .groupBy("hour") \
   .agg(
       count("*").alias("session_count"),
       sum("totals.transactions").alias("transactions"),
       sum("totals.totalTransactionRevenue").cast(DecimalType(20,2)).alias("total_revenue"),
       sum("totals.pageviews").alias("total_pageviews")
   ) \
   .orderBy("hour")

print("\nHourly Aggregation Sample:")
hourly_agg.show(5)

الناتج المتوقَّع :

Transformation 4: Time-based analysis...

Hourly Aggregation Sample:
+----+-------------+------------+-------------+---------------+
|hour|session_count|transactions|total_revenue|total_pageviews|
+----+-------------+------------+-------------+---------------+
|   0|           87|        NULL|         NULL|            372|
|   1|          102|        NULL|         NULL|            494|
|  10|           67|        NULL|         NULL|            149|
|  11|           73|        NULL|         NULL|            167|
|  12|           99|        NULL|         NULL|            313|
+----+-------------+------------+-------------+---------------+
only showing top 5 rows

9- كتابة النتيجة في جدول BigQuery

يُصدِّر هذا الرمز أربعة إطارات بيانات مجمّعة (device_agg وtraffic_source_agg وgeo_agg وhourly_agg) إلى جداول منفصلة في Google BigQuery، ويستبدل الجداول الحالية إذا كانت متوفّرة، باستخدام طريقة كتابة مباشرة.

# Write to BigQuery tables
print("\nLoading data to BigQuery...")

# Set output tables
device_output_table = f"{project_id}.analytics_sample.device_aggregation"
traffic_output_table = f"{project_id}.analytics_sample.traffic_source_aggregation"
geo_output_table = f"{project_id}.analytics_sample.geo_aggregation"
hourly_output_table = f"{project_id}.analytics_sample.hourly_aggregation"

dataset_id = "demo"  # Replace with your BigQuery dataset ID 

# Set BigQuery output table
device_output_table = f"{project_id}.{dataset_id}.device_aggregation"
traffic_output_table = f"{project_id}.{dataset_id}.traffic_source_aggregation"
geo_output_table = f"{project_id}.{dataset_id}.geo_aggregation"
hourly_output_table = f"{project_id}.{dataset_id}.hourly_aggregation"

# Write each DataFrame to BigQuery
device_agg.write \
   .format("bigquery") \
   .option("table", device_output_table) \
   .option("writeMethod", "direct") \
   .mode("overwrite") \
   .save()

traffic_source_agg.write \
   .format("bigquery") \
   .option("table", traffic_output_table) \
   .option("writeMethod", "direct") \
   .mode("overwrite") \
   .save()

geo_agg.write \
   .format("bigquery") \
   .option("table", geo_output_table) \
   .option("writeMethod", "direct") \
   .mode("overwrite") \
   .save()

hourly_agg.write \
   .format("bigquery") \
   .option("table", hourly_output_table) \
   .option("writeMethod", "direct") \
   .mode("overwrite") \
   .save()

تحقَّق من جدول الإخراج في BigQuery للتأكّد من حفظ البيانات بنجاح بعد إجراء بعض عمليات التحويل.

6227a951f1d1d4e6.png

جدول device_aggregation

da7791f5d15f67be.png

جدول geo_aggregation

76ec9d9dc9929c1c.png

جدول hourly_aggregation

bcf627ef6a13c8cc.png

traffic_source_aggregation

f373d64ace332074.png

10- تنظيم رمز ورقة ملاحظات BigQuery Studio (اختياري)

يمكنك تنظيم رمز ورقة ملاحظات BigQuery Studio بالطرق التالية:

في هذا الدرس التطبيقي حول الترميز، سنستخدم خيار "جدولة رمز ورقة الملاحظات" من Google Cloud Console.

  1. في شريط أدوات ورقة الملاحظات ، انقر على جدولة.
  2. في لوحة جدولة ورقة الملاحظات ، أدخِل اسمًا للجدول في حقل اسم الجدول.
  3. في قسم المصادقة ، امنح الإذن لورقة الملاحظات باستخدام بيانات اعتماد حساب Google أو حساب خدمة.
  4. لاستخدام بيانات اعتماد حسابك على Google ( معاينة)، اختَر التنفيذ باستخدام بيانات اعتماد المستخدم.
  5. لاستخدام حساب خدمة، اختَر التنفيذ باستخدام حساب الخدمة المحدّد، ثم اختَر حساب خدمة.
  6. في قسم خيارات ورقة الملاحظات ، اختَر نموذج وقت تشغيل ورقة ملاحظات Colab أو مواصفات وقت التشغيل التلقائية في حقل نموذج وقت التشغيل. للاطّلاع على تفاصيل إنشاء نموذج وقت تشغيل ورقة ملاحظات Colab، يُرجى الرجوع إلى مقالة إنشاء نموذج وقت تشغيل.
  7. في حقل حزمة Cloud Storage ، انقر على تصفُّح واختَر حزمة في Cloud Storage أو أنشِئ حزمة. يجب منح حساب الخدمة المحدّد دور مشرف مساحة التخزين (roles/storage.admin) في إدارة الهوية وإمكانية الوصول على الحزمة المحدّدة. لمزيد من المعلومات، يُرجى الرجوع إلى مقالة تفعيل جدولة أوراق الملاحظات.
  8. في قسم فترة تكرار الجدول ، اتّبِع الخطوات التالية:
  9. في قائمة التكرار ، اختَر فترة تكرار عمليات تشغيل ورقة الملاحظات المُجدوَلة.
  10. في حقل في الوقت ، أدخِل وقت عمليات تشغيل ورقة الملاحظات المُجدوَلة.
  11. في قائمة المنطقة الزمنية ، اختَر المنطقة الزمنية للجدول.
  12. انقر على إنشاء جدول. إذا اخترت التنفيذ باستخدام بيانات اعتماد المستخدم لطريقة المصادقة، عليك تفويض حسابك على Google ( معاينة).

f3d87c9a3408b08d.png

11- تنظيف

لتجنُّب تكبّد رسوم في حسابك على Google Cloud مقابل الموارد المستخدَمة في هذا الدرس التطبيقي حول الترميز، اتّبِع الخطوات التالية:

  1. في Google Cloud Console، انتقِل إلى صفحة إدارة الموارد.
  2. في قائمة المشاريع، اختَر المشروع الذي تريد حذفه، ثم انقر على حذف.
  3. في مربّع الحوار، اكتب رقم تعريف المشروع، ثم انقر على إيقاف لحذف المشروع.

12- تهانينا

لقد انتهيت من إجراء عمليات تحويل البيانات وتحليلها من خلال الاستفادة من Apache Spark بدون خادم في أوراق ملاحظات BigQuery Studio. خلال هذه العملية، استكشفت مجموعات البيانات العامة في Google Cloud، وأجريت عملية استخراج البيانات وتحويلها وتحميلها بدون خادم باستخدام Apache Spark في ورقة ملاحظات BigQuery Studio، ونظّمت ورقة ملاحظات BigQuery Studio. أحسنت!

الخطوات التالية :

  • تنظيم ورقة الملاحظات باستخدام حساب خدمة لأغراض التشغيل الآلي
  • إضافة نص برمجي لمراقبة المدة عند تشغيل مهمة استخراج البيانات وتحويلها وتحميلها
  • نشر أوراق ملاحظات.
  • استخدام DataprocSparkSession للاستفادة من إمكانات Apache Spark الموزّعة الحقيقية مع Dataproc بدون خادم في أوراق ملاحظات BigQuery Studio
  • إنشاء إجراء مخزَّن لـ Apache Spark في BigQuery Studio. بهذه الطريقة، يمكنك تطبيق مبادئ البرمجة الكائنية التوجّه لهيكلة رمز PySpark من أجل تنظيم أفضل وإعادة الاستخدام والصيانة.

المراجع :