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 Console.
- تحقَّق من المصادقة:
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.
سنفترض أنّك تستخدم محرِّر BigQuery SQL للحصول على تجربة أفضل مع عبارات الإنشاء المتعدّدة الأسطر. - أنشِئ مجموعة بيانات
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 STRING,
order_type STRING,
payment_method STRING,
PRIMARY KEY (order_id) NOT ENFORCED
);
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 التالية في محرِّر BigQuery SQL:
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
);
-- 1. Create a new partitioned and clustered table from your current data
CREATE TABLE cymbal_pets_demo.orders_temp
PARTITION BY order_date
CLUSTER BY order_id
AS
SELECT
customer_id,
order_id,
shipping_address_city,
store_id,
-- Parse the string to a DATE type. Adjust format string ('%Y-%m-%d') if necessary.
PARSE_DATE('%Y-%m-%d', order_date) AS order_date,
order_type,
payment_method
FROM
cymbal_pets_demo.orders;
-- 2. Drop the original, non-partitioned table
DROP TABLE cymbal_pets_demo.orders;
-- 3. Rename the temporary table to the original table name
ALTER TABLE cymbal_pets_demo.orders_temp RENAME TO orders;
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. يتيح لنا ذلك عرض نتائج الرسم البياني بسهولة.
بدلاً من ذلك، يمكنك العرض المرئي في BigQuery Graph Notebook باستخدام IPython Magics. من خلال إضافة الأمر السحري %%bigquery مع الدالة TO_JSON، يمكنك عرض النتائج كما هو موضّح في الأقسام التالية.
لنفترض أنّ شركة Cymbal Pets تريد الحصول على عرض مرئي شامل لجميع العملاء والمشتريات التي أجروها خلال فترة زمنية معيّنة.
نفِّذ ما يلي في علامة تبويب جديدة في BigQuery Studio:
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 أشهر والمتاجر التي زارتها.
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 لإنشاء عمود تضمينات في جدول المنتجات.
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- الاقتراحات باستخدام "تم شراؤها معًا" ومعامل تماثل جاكار
هناك أسلوب فعّال آخر للاقتراحات وهو "التصفية التعاونية"، أي اقتراح المنتجات التي يشتريها المستخدمون الآخرون معًا بشكل متكرّر.
يمكننا العثور على هذه المنتجات من خلال اجتياز الرسم البياني من العميل إلى المنتجات التي اشتراها، ثم إلى العملاء الآخرين الذين اشتروا هذه المنتجات، وأخيرًا إلى المنتجات الأخرى التي اشتراها هؤلاء العملاء.
تجاوز التحيز نحو المنتجات الرائجة باستخدام معامل تماثل جاكار
على الرغم من أنّ عدد عمليات الشراء المشتركة الأولية مفيد، فإنّه يمكن أن يكون متحيزًا نحو المنتجات الرائجة. قد يتم شراء منتج رائج جدًا مع العديد من المنتجات الأخرى بمحض الصدفة.
يأخذ معامل تماثل جاكار الاقتراحات خطوة أخرى إلى الأمام من خلال تسوية عدد عمليات الشراء المشتركة. يقيس هذا المعامل التشابه بين مجموعتَين (في هذه الحالة، مجموعات الطلبات التي تحتوي على كل منتج).
صيغة معامل تماثل جاكار هي:
حيث:
- 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

إنشاء المرشّحين وإعادة ترتيبهم
في أنظمة الاقتراحات الواقعية التي تعمل على مجموعات بيانات ضخمة، يكون من غير العملي في كثير من الأحيان حساب نقاط التشابه المعقّدة (مثل معامل تماثل جاكار) لجميع الأزواج المحتملة من المنتجات. بدلاً من ذلك، هناك نمط شائع وهو استخدام نهج من مرحلتَين:
- إنشاء المرشّحين: استخدِم مقياسًا بسيطًا وسريعًا (مثل عدد عمليات الشراء المشتركة الأولية) لفلترة مساحة البحث والعثور على عدد يمكن إدارته من المرشّحين (مثل أفضل 10).
- إعادة الترتيب: طبِّق مقياسًا أكثر دقة، ولكنّه يتطلّب قدرًا أكبر من العمليات الحسابية (مثل معامل تماثل جاكار) لترتيب هذه المجموعة الصغيرة من المرشّحين واختيار أفضل الاقتراحات النهائية.
في هذا الدرس التطبيقي حول الترميز، سنتبع هذا النمط:
- المرحلة 1: نفِّذ طلب بحث للعثور على أفضل 10 منتجات تم شراؤها معًا لكل منتج، استنادًا إلى عدد عمليات الشراء المشتركة الأولية، وخزِّنها في جدول.
- المرحلة 2: استخدِم طلب بحث في الرسم البياني لاسترداد هؤلاء المرشّحين، ورتِّبهم حسب معامل تماثل جاكار، واعرض أفضل 3.
[!WARNING] العيوب: من خلال الفلترة حسب العدد الأولي في المرحلة 1، قد نفقد "الاستدعاء" لعمليات الشراء المشتركة المحدّدة جدًا ولكنّها قليلة التكرار. إذا كان منتج ما مشابهًا جدًا لمنتج آخر ولكنّ كلاهما نادرًا ما يتم شراؤه، فقد لا يتم إدراجهما ضمن أفضل 10 مرشّحين وسيتم تجاهلهما.
نفِّذ طلب البحث التالي لحساب عدد عمليات الشراء المشتركة الأولية ومعامل تماثل جاكار، وخزِّن أفضل 10 مرشّحين حسب العدد الأولي:
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، مع عرض عدد عمليات الشراء المشتركة ومعامل تماثل جاكار:
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;
يجتاز طلب البحث هذا من "العميل" -> "الطلب" -> "المنتج" -> (تم شراؤه معًا) -> "المنتج المقترَح"، ما يعرض لك اقتراحات استنادًا إلى سلوك الشراء الجماعي ويستردّ نقاط التشابه.

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