1. مقدمة
في هذا الدرس التطبيقي حول الترميز، ستتعرّف على كيفية استخدام "الرسم البياني في BigQuery" لتقديم صورة شاملة حول العملاء ومحرّك لاقتراح المنتجات لشركة Cymbal Pets، وهي شركة وهمية للبيع بالتجزئة. ستستفيد من إمكانات SQL لإنشاء بيانات الرسومات البيانية والاستعلام عنها وتحليلها مباشرةً في BigQuery، مع دمجها مع البحث المتجهي للحصول على اقتراحات متقدّمة للمنتجات.
تتيح لك ميزة "الرسم البياني" في BigQuery وضع نماذج للعلاقات بين عناصر البيانات (مثل العملاء والمنتجات والطلبات) على شكل رسم بياني، ما يسهّل الإجابة عن الأسئلة المعقّدة حول سلوك العملاء والمنتجات المفضّلة لديهم.

الإجراءات التي ستنفذّها
- إنشاء مجموعة بيانات ومخطط في BigQuery للرسم البياني Cymbal Pets
- تحميل بيانات نموذجية (العملاء والمنتجات والطلبات والمتاجر) من Cloud Storage
- إنشاء "رسم بياني للمواقع" في BigQuery يربط بين هذه الكيانات
- عرض سجلّات شراء العملاء بشكل مرئي باستخدام طلبات بحث بيانية
- إنشاء نظام لاقتراح المنتجات باستخدام البحث المتّجه
- تحسين الاقتراحات باستخدام علاقات الرسم البياني "تم شراؤها معًا" ومعامل التشابه جاكارد
المتطلبات
- متصفّح ويب، مثل Chrome
- مشروع Google Cloud تم تفعيل الفوترة فيه
هذا الدرس التطبيقي حول الترميز مخصّص للمطوّرين من جميع المستويات، بما في ذلك المبتدئين.
2. قبل البدء
إنشاء مشروع على Google Cloud
- في Google Cloud Console، اختَر مشروعًا على Google Cloud أو أنشِئ مشروعًا.
- تأكَّد من تفعيل الفوترة لمشروعك على السحابة الإلكترونية.
بدء Cloud Shell
- انقر على تفعيل Cloud Shell في أعلى "وحدة تحكّم Google Cloud".
- إثبات صحة المصادقة:
gcloud auth list
- أكِّد مشروعك:
gcloud config get project
- اضبطه إذا لزم الأمر:
export PROJECT_ID=<YOUR_PROJECT_ID>
gcloud config set project $PROJECT_ID
تفعيل واجهات برمجة التطبيقات
نفِّذ الأمر التالي لتفعيل BigQuery API المطلوبة:
gcloud services enable bigquery.googleapis.com
3- تحديد المخطط
أولاً، عليك إنشاء مجموعة بيانات لتخزين الجداول ذات الصلة بالرسم البياني وتحديد المخطط للعُقد والحواف.
- في هذا الدرس التطبيقي، سننفّذ أوامر SQL. يمكنك تنفيذ هذه الأوامر في BigQuery Studio > محرِّر SQL، أو استخدام الأمر
bq queryفي Cloud Shell.
سنفترض أنّك تستخدم أداة تعديل SQL في BigQuery للحصول على تجربة أفضل مع عبارات الإنشاء المتعددة الأسطر. - أنشئ مجموعة بيانات
cymbal_pets_demo:
CREATE SCHEMA IF NOT EXISTS cymbal_pets_demo;
- أنشئ الجداول الخاصة بـ
order_itemsوproductsوordersوstoresوcustomersوco_related_products_for_angelica. ستكون هذه الجداول بمثابة بيانات المصدر للرسم البياني.
CREATE TABLE IF NOT EXISTS cymbal_pets_demo.order_items
(
order_id INT64,
product_id INT64,
order_item_id INT64,
quantity INT64,
price FLOAT64,
PRIMARY KEY (order_id, product_id, order_item_id) NOT ENFORCED
)
CLUSTER BY order_item_id;
CREATE TABLE IF NOT EXISTS cymbal_pets_demo.products
(
product_id INT64,
product_name STRING,
brand STRING,
category STRING,
subcategory INT64,
animal_type INT64,
search_keywords INT64,
price FLOAT64,
description STRING,
inventory_level INT64,
supplier_id INT64,
average_rating FLOAT64,
uri STRING,
embedding ARRAY<FLOAT64>,
PRIMARY KEY (product_id) NOT ENFORCED
)
CLUSTER BY product_id;
CREATE TABLE IF NOT EXISTS cymbal_pets_demo.orders
(
customer_id INT64,
order_id INT64,
shipping_address_city STRING,
store_id INT64,
order_date DATE,
order_type STRING,
payment_method STRING,
PRIMARY KEY (order_id) NOT ENFORCED
)
PARTITION BY order_date
CLUSTER BY order_id;
CREATE TABLE IF NOT EXISTS cymbal_pets_demo.stores
(
store_id INT64,
store_name STRING,
address_state STRING,
address_city STRING,
latitude FLOAT64,
longitude FLOAT64,
opening_hours STRUCT<Monday STRING, Tuesday STRING, Wednesday STRING, Thursday STRING, Friday STRING, Saturday STRING, Sunday STRING>,
manager_id INT64,
PRIMARY KEY (store_id) NOT ENFORCED
)
CLUSTER BY store_id;
CREATE TABLE IF NOT EXISTS cymbal_pets_demo.customers
(
customer_id INT64,
first_name STRING,
last_name STRING,
email STRING,
gender STRING,
address_city STRING,
address_state STRING,
loyalty_member BOOL,
PRIMARY KEY (customer_id) NOT ENFORCED
)
CLUSTER BY customer_id;
CREATE TABLE IF NOT EXISTS cymbal_pets_demo.co_related_products_for_angelica
(
angelica_product_id INT64,
other_product_id INT64,
co_purchase_count INT64,
jaccard_similarity FLOAT64
);
لقد حدّدت الآن بنية بيانات الرسم البياني.
4. تحميل البيانات
الآن، املأ الجداول ببيانات نموذجية من Cloud Storage.
نفِّذ عبارات LOAD DATA التالية في محرّر SQL في BigQuery:
LOAD DATA INTO `cymbal_pets_demo.customers`
FROM FILES (
format = 'AVRO',
uris = ['gs://sample-data-and-media/cymbal-pets/tables/customers/*.avro'],
enable_logical_types = true
);
LOAD DATA INTO `cymbal_pets_demo.order_items`
FROM FILES (
format = 'AVRO',
uris = ['gs://sample-data-and-media/cymbal-pets/tables/order_items/*.avro'],
enable_logical_types = true
);
LOAD DATA INTO `cymbal_pets_demo.orders`
FROM FILES (
format = 'AVRO',
uris = ['gs://sample-data-and-media/cymbal-pets/tables/orders/*.avro'],
enable_logical_types = true
);
LOAD DATA INTO `cymbal_pets_demo.products`
FROM FILES (
format = 'AVRO',
uris = ['gs://sample-data-and-media/cymbal-pets/tables/products/*.avro'],
enable_logical_types = true
);
LOAD DATA INTO `cymbal_pets_demo.stores`
FROM FILES (
format = 'AVRO',
uris = ['gs://sample-data-and-media/cymbal-pets/tables/stores/*.avro'],
enable_logical_types = true
);
من المفترض أن يظهر لك تأكيد بأنّه تم تحميل الصفوف في كل جدول.
5- إنشاء الرسم البياني للمواقع
بعد تحميل البيانات، يمكنك الآن تحديد الرسم البياني للسمات. يحدّد هذا الخيار الجداول التي تمثّل العُقد (مثل العملاء والمنتجات) والجداول التي تمثّل الحواف (مثل العلاقات "زار" و"وضع" و"يملك") في BigQuery.

نفِّذ جملة DDL التالية:
CREATE OR REPLACE PROPERTY GRAPH cymbal_pets_demo.PetsOrderGraph
NODE TABLES (
cymbal_pets_demo.customers KEY(customer_id) LABEL Customer,
cymbal_pets_demo.products KEY(product_id) LABEL Products,
cymbal_pets_demo.stores KEY(store_id) LABEL Stores,
cymbal_pets_demo.orders KEY(order_id) LABEL Orders
)
EDGE TABLES (
cymbal_pets_demo.orders as customer_to_store_edge
KEY (order_id)
SOURCE KEY (customer_id) references customers(customer_id)
DESTINATION KEY (store_id) references stores(store_id)
LABEL Visited
PROPERTIES ALL COLUMNS,
cymbal_pets_demo.order_items
KEY (order_item_id)
SOURCE KEY (order_id) references orders(order_id)
DESTINATION KEY (product_id) references products(product_id)
LABEL Has
PROPERTIES ALL COLUMNS,
cymbal_pets_demo.orders as customer_to_orders_edge
KEY (order_id)
SOURCE KEY (customer_id) references customers(customer_id)
DESTINATION KEY (order_id) references orders(order_id)
LABEL Placed
PROPERTIES ALL COLUMNS,
cymbal_pets_demo.co_related_products_for_angelica
KEY (angelica_product_id)
SOURCE KEY (angelica_product_id) references products(product_id)
DESTINATION KEY (other_product_id) references products(product_id)
LABEL BoughtTogether
PROPERTIES ALL COLUMNS
);
يؤدي ذلك إلى إنشاء الرسم البياني PetsOrderGraph الذي يتيح لنا تنفيذ عمليات اجتياز الرسم البياني باستخدام عامل التشغيل GRAPH_TABLE.
6. تصوُّر سجلّ الشراء لجميع العملاء
افتح دفتر ملاحظات جديد في BigQuery Studio.

بالنسبة إلى أجزاء التمثيل البصري والاقتراحات في هذا الدرس التطبيقي حول الترميز، سنستخدم دفتر ملاحظات Google Colab في BigQuery Studio. يتيح لنا ذلك عرض نتائج الرسم البياني بسهولة.
ألصِق ما يلي في خلية رمز برمجي:
!pip install bigquery-magics==0.12.1
يتم تنفيذ BigQuery Graph Notebook كـ IPython Magics. من خلال إضافة الأمر السحري %%bigquery مع الدالة TO_JSON، يمكنك عرض النتائج كما هو موضّح في الأقسام التالية.
لنفترض أنّ شركة Cymbal Pets تريد الحصول على عرض مرئي بزاوية 360 درجة لجميع العملاء وعمليات الشراء التي أجروها خلال فترة زمنية محدّدة.
نفِّذ ما يلي في خلية جديدة:
%%bigquery --graph
GRAPH cymbal_pets_demo.PetsOrderGraph
# finds the customer node and then finds all
# the Orders nodes that are connected to that customer through the
# Placed relationship
MATCH (customer:Customer)-[placed:Placed]->(ordr:Orders)-[has:Has]->(product:Products)
# filters the Orders nodes to only include those where the
# order_date is within the last 3 months.
WHERE ordr.order_date >= date('2024-11-27')
# # This line finds all the Products nodes that are connected to the
# # filtered Orders nodes through the Has relationship.
MATCH p=(customer:Customer)-[placed:Placed]->(ordr:Orders)-[has:Has]->(product:Products)
LIMIT 40
RETURN
TO_JSON(p) as paths
من المفترض أن يظهر لك تمثيل مرئي لنتيجة الرسم البياني.

7. تصوُّر سجلّ شراء "أنجليكا"
لنفترض أنّ شركة Cymbal Pets تريد التعرّف أكثر على إحدى العملاء، وهي "أنجليكا راسل". يريدون تحليل المنتجات التي اشترتها "أنجليكا" خلال آخر 3 أشهر والمتاجر التي زارتها.
%%bigquery --graph
GRAPH cymbal_pets_demo.PetsOrderGraph
# finds the customer node with the name "Angelica Russell" and then finds all
# the Orders nodes that are connected to that customer through the
# Placed relationship and all the Products nodes that are connected to the
# filtered Orders nodes through the Has relationship.
MATCH p=(customer:Customer {first_name: 'Angelica', last_name: 'Russell'})-[placed:Placed]->(ordr:Orders)-[has:Has]->(product:Products)
# filters the Orders nodes to only include those where the
# order_date is within the last 3 months.
WHERE ordr.order_date >= date('2024-11-27')
# finds the Stores nodes where Angelica placed order from
MATCH p2=(customer)-[visited:Visited]->(store:Stores)
RETURN
TO_JSON(p) as path, TO_JSON(p2) as path2

8. اقتراح المنتجات باستخدام البحث المتّجهي
تريد شركة Cymbal Pets أن تقترح منتجات على "أنجليكا" استنادًا إلى ما اشترته مؤخرًا. يمكننا استخدام البحث المتّجه للعثور على منتجات تتضمّن عمليات تضمين مشابهة لعمليات الشراء السابقة.
نفِّذ نص SQL البرمجي التالي في خلية Colab جديدة. يعمل هذا النص البرمجي على:
- تحدّد هذه السمة المنتجات التي اشترتها "أنجليكا" مؤخرًا.
- يستخدم
VECTOR_SEARCHللعثور على أفضل 4 منتجات مشابهة من الجدولproducts.
ملاحظة: تفترض هذه الخطوة أنّك سبق أن نفّذت AI.GENERATE_EMBEDDINGS لإنشاء عمود تضمين في جدول المنتجات.
%%bigquery
DECLARE products_bought_by_angelica ARRAY<INT64>;
-- 1. Get IDs of products bought by Angelica
SET products_bought_by_angelica = (
SELECT ARRAY_AGG(product_id) FROM
GRAPH_TABLE(
cymbal_pets_demo.PetsOrderGraph
MATCH (c:Customer {first_name: 'Angelica', last_name: 'Russell'})-[placed:Placed]->(o:Orders)
WHERE o.order_date >= date('2024-11-27')
MATCH (o)-[has_edge:Has]->(p:Products)
RETURN DISTINCT p.product_id as product_id
));
-- 2. Find similar products using vector search
SELECT
query.product_name as AngelicaBought,
base.product_name as RecommendedProducts,
base.category
FROM
VECTOR_SEARCH(
TABLE cymbal_pets_demo.products,
'embedding',
(SELECT * FROM cymbal_pets_demo.products
WHERE product_id IN UNNEST(products_bought_by_angelica)),
'embedding',
top_k => 4)
WHERE query.product_name <> base.product_name;
ستظهر لك قائمة بالمنتجات المقترَحة التي تتشابه دلاليًا مع ما اشترته أنجيليكا.

9- اقتراح باستخدام "تم شراؤه معًا" ومقياس التشابه بين المجموعات
هناك أسلوب آخر قوي للتوصية وهو "التصفية التعاونية"، أي اقتراح منتجات يشتريها المستخدمون الآخرون بشكل متكرر.
يمكننا العثور على هذه المنتجات من خلال الانتقال في الرسم البياني من العميل إلى المنتجات التي اشتراها، ثم إلى العملاء الآخرين الذين اشتروا هذه المنتجات، وأخيرًا إلى المنتجات الأخرى التي اشتراها هؤلاء العملاء.
التغلّب على الانحياز حسب مدى الرواج باستخدام مقياس التشابه وفقًا لمعامل جاكار
على الرغم من أنّ أعداد عمليات الشراء المشترك غير المعالَجة مفيدة، إلا أنّها قد تكون متحيزة لصالح المنتجات الرائجة. قد يتم شراء منتج شائع جدًا مع العديد من المنتجات الأخرى بمحض الصدفة.
تتجاوز ميزة "تشابه جاكار" الاقتراحات خطوة إضافية من خلال تسوية عدد عمليات الشراء المشتركة. يقيس هذا المقياس التشابه بين مجموعتين (في هذه الحالة، مجموعات الطلبات التي تحتوي على كل منتج).
صيغة Jaccard Similarity هي:
المكان:
- A intersect B هو عدد الطلبات التي تحتوي على المنتج A والمنتج B (عدد عمليات الشراء المشتركة).
- أ هو إجمالي عدد الطلبات التي تتضمّن المنتج "أ".
- ب هو إجمالي عدد الطلبات التي تحتوي على المنتج "ب".
في المثال التالي، المجموعة A = {b,c,e,f,g}، والمجموعة B = {a,d,b,g}، والتقاطع بينهما A⋂B = {b,g}، والاتحاد بينهما A⋃B = {a,b,c,d,e,f,g}، وبالتالي فإنّ تشابه جاكارد بين A وB هو 2 / 7 = 0.285714

إنشاء المرشّحين وإعادة ترتيبهم
في أنظمة الاقتراحات الواقعية التي تعمل على مجموعات بيانات ضخمة، غالبًا ما يكون من غير العملي احتساب درجات التشابه المعقّدة (مثل Jaccard) لجميع أزواج المنتجات المحتملة. بدلاً من ذلك، يتم عادةً اتّباع أسلوب من مرحلتين:
- إنشاء المنتجات المرشّحة: استخدِم مقياسًا بسيطًا وسريعًا (مثل عدد عمليات الشراء المشترك غير المعالَج) لفلترة مساحة البحث والعثور على عدد يمكن إدارته من المنتجات المرشّحة (مثل أفضل 10 منتجات).
- إعادة الترتيب: تطبيق مقياس أكثر دقة، ولكنّه يتطلّب قدرًا أكبر من العمليات الحسابية (مثل معامل التشابه جاكارد) لترتيب هذه المجموعة الصغيرة من النتائج المحتملة واختيار أفضل الاقتراحات النهائية
في هذا الدرس العملي، سنتبع النمط التالي:
- المرحلة 1: تنفيذ طلب بحث للعثور على أفضل 10 منتجات يتم شراؤها مع منتجات أخرى لكل منتج، استنادًا إلى عدد عمليات الشراء المشتركة الأولية، وتخزينها في جدول
- المرحلة 2: استخدِم طلب بحث في الرسم البياني لاسترداد هذه النتائج المحتملة، ورتِّبها حسب التشابه في مؤشر جاكار، ثم اعرض أفضل 3 نتائج.
[!WARNING] العيوب: من خلال الفلترة حسب العدد الأولي في المرحلة 1، قد نفقد "تذكُّر" عمليات الشراء المشترك المحدّدة جدًا ولكن المنخفضة التكرار. إذا كان المنتج مشابهًا جدًا لمنتج آخر ولكن نادرًا ما يتم شراؤهما، قد لا يتم إدراجهما ضمن أفضل 10 منتجات مقترَحة، وبالتالي لن يتم عرضهما.
نفِّذ الاستعلام التالي لاحتساب كلّ من عدد عمليات الشراء المشتركة الأولية ومعامل تماثل جاكار، وخزِّن أفضل 10 مرشّحين حسب العدد الأولي:
%%bigquery
CREATE OR REPLACE TABLE cymbal_pets_demo.co_related_products_for_angelica AS
-- Calculate the total number of orders for each product
WITH ProductOrderCounts AS (
SELECT product_id, COUNT(DISTINCT order_id) as total_count
FROM cymbal_pets_demo.order_items
GROUP BY product_id
),
-- Calculate the intersection of each product pairs
CoPurchases AS (
SELECT
angelicaProduct.product_id AS angelica_product_id,
otherProduct.product_id AS other_product_id,
count(DISTINCT otherOrder.order_id) AS co_purchase_count
FROM
GRAPH_TABLE (cymbal_pets_demo.PetsOrderGraph
MATCH (angelica:Customer {first_name: 'Angelica', last_name: 'Russell'})-[:Placed]->(o:Orders)-[:Has]->(angelicaProduct:Products)
WHERE o.order_date >= date('2024-11-27')
WITH angelica, angelicaProduct
MATCH (otherCustomer:Customer)-[:Placed]->(otherOrder:Orders)-[:Has]->(angelicaProduct)
WHERE otherCustomer <> angelica
WITH angelicaProduct, otherOrder
MATCH (otherOrder)-[:HAS]->(otherProduct:Products)
WHERE angelicaProduct <> otherProduct
RETURN angelicaProduct, otherProduct, otherOrder
)
GROUP BY
angelicaProduct.product_id, otherProduct.product_id
)
SELECT * FROM (
SELECT
cp.angelica_product_id,
cp.other_product_id,
cp.co_purchase_count,
-- The Jaccard calculation, which is the intersection of A and B divided by (A + B - intersection)
SAFE_DIVIDE(cp.co_purchase_count, (poc1.total_count + poc2.total_count - cp.co_purchase_count)) AS jaccard_similarity,
ROW_NUMBER() OVER (PARTITION BY cp.angelica_product_id ORDER BY cp.co_purchase_count DESC) AS rn
FROM CoPurchases cp
JOIN ProductOrderCounts poc1 ON cp.angelica_product_id = poc1.product_id
JOIN ProductOrderCounts poc2 ON cp.other_product_id = poc2.product_id
)
WHERE rn <= 10;

نفِّذ طلب البحث هذا لاقتراح أهم 3 منتجات لكل عمليات شراء أجرتها "أنجليكا"، مع ربطها مباشرةً من خلال حافة BoughtTogether، وعرض كلّ من عدد عمليات الشراء المشتركة ومقياس التشابه وفقًا لمعامل جاكارد:
%%bigquery
SELECT * FROM GRAPH_TABLE(
cymbal_pets_demo.PetsOrderGraph
MATCH (customer:Customer {first_name: 'Angelica', last_name: 'Russell'})-[placed:Placed]->(ordr:Orders)
WHERE ordr.order_date >= date('2024-11-27')
MATCH (ordr)-[has:Has]->(product:Products)
MATCH (product)-[bought_together:BoughtTogether]->(recommended_product:Products)
RETURN
product.product_name AS OriginalProduct,
recommended_product.product_name AS Recommended,
bought_together.co_purchase_count AS Strength,
bought_together.jaccard_similarity AS JaccardSimilarity
)
-- Rank product recommendations by Jaccard Similarity
QUALIFY ROW_NUMBER() OVER (PARTITION BY OriginalProduct ORDER BY JaccardSimilarity DESC) <= 3
ORDER BY OriginalProduct;
يتنقّل طلب البحث هذا من "العميل" -> "الطلب" -> "المنتج" -> (BoughtTogether) -> "المنتج المقترَح"، ويعرض لك اقتراحات استنادًا إلى سلوك الشراء الجماعي ويستردّ نتائج التشابه.

10. تَنظيم
لتجنُّب الرسوم المستمرة على حسابك على Google Cloud، احذف الموارد التي تم إنشاؤها أثناء هذا الدرس العملي.
حذف مجموعة البيانات وجميع الجداول:
DROP SCHEMA IF EXISTS cymbal_pets_demo CASCADE;
إذا أنشأت مشروعًا جديدًا لهذا الدرس التطبيقي حول الترميز، يمكنك أيضًا حذف المشروع:
gcloud projects delete $PROJECT_ID
11. تهانينا
تهانينا! لقد أنشأت بنجاح صورة شاملة حول العملاء ومحرّك اقتراحات باستخدام "الرسم البياني في BigQuery".
ما تعلّمته
- كيفية إنشاء رسم بياني للعلاقات في BigQuery
- كيفية تحميل البيانات في عُقد الرسم البياني وحوافه
- كيفية طلب البحث عن أنماط الرسومات البيانية باستخدام
GRAPH_TABLEوMATCH - كيفية الجمع بين طلبات البحث المستندة إلى الرسوم البيانية والبحث المتّجه للحصول على اقتراحات مختلطة