1. Giới thiệu
Trong lớp học lập trình này, bạn sẽ tìm hiểu cách sử dụng BigQuery Graph để xây dựng chân dung khách hàng 360 độ và công cụ đề xuất cho Cymbal Pets, một công ty bán lẻ giả định. Bạn sẽ tận dụng sức mạnh của SQL để tạo, truy vấn và phân tích dữ liệu đồ thị ngay trong BigQuery, kết hợp với tính năng tìm kiếm vectơ để đưa ra các đề xuất sản phẩm nâng cao.
BigQuery Graph cho phép bạn lập mô hình mối quan hệ giữa các thực thể dữ liệu (như khách hàng, sản phẩm và đơn đặt hàng) dưới dạng đồ thị, giúp bạn dễ dàng trả lời các câu hỏi phức tạp về hành vi của khách hàng và mối quan hệ giữa các sản phẩm.

Bạn sẽ thực hiện
- Tạo tập dữ liệu và giản đồ BigQuery cho biểu đồ Cymbal Pets
- Tải dữ liệu mẫu (Khách hàng, Sản phẩm, Đơn đặt hàng, Cửa hàng) từ Cloud Storage
- Tạo một Đồ thị thuộc tính trong BigQuery để kết nối các thực thể này
- Trực quan hoá nhật ký mua hàng của khách hàng bằng truy vấn đồ thị
- Xây dựng hệ thống đề xuất sản phẩm bằng tính năng tìm kiếm vectơ
- Cải thiện nội dung đề xuất bằng cách sử dụng mối quan hệ trong biểu đồ "Thường được mua cùng" và độ tương đồng Jaccard
Bạn cần có
- Một trình duyệt web, chẳng hạn như Chrome
- Một dự án Google Cloud đã bật tính năng thanh toán
Lớp học lập trình này dành cho nhà phát triển ở mọi cấp độ, kể cả người mới bắt đầu.
2. Trước khi bắt đầu
Tạo một dự án trên Google Cloud
- Trong Google Cloud Console, hãy chọn hoặc tạo một dự án trên đám mây của Google Cloud.
- Đảm bảo rằng bạn đã bật tính năng thanh toán cho dự án trên đám mây của bạn.
Bắt đầu Cloud Shell
- Nhấp vào Kích hoạt Cloud Shell ở đầu Google Cloud Console.
- Xác minh việc xác thực:
gcloud auth list
- Xác nhận dự án của bạn:
gcloud config get project
- Hãy đặt nếu cần:
export PROJECT_ID=<YOUR_PROJECT_ID>
gcloud config set project $PROJECT_ID
Bật API
Chạy lệnh này để bật BigQuery API cần thiết:
gcloud services enable bigquery.googleapis.com
3. Xác định giản đồ
Trước tiên, bạn cần tạo một tập dữ liệu để lưu trữ các bảng liên quan đến biểu đồ và xác định giản đồ cho các nút và cạnh.
- Trong lớp học lập trình này, chúng ta sẽ thực thi các lệnh SQL. Bạn có thể chạy các lệnh này trong BigQuery Studio > Trình chỉnh sửa SQL hoặc sử dụng lệnh
bq querytrong Cloud Shell.
Chúng tôi giả định rằng bạn đang sử dụng Trình chỉnh sửa SQL của BigQuery để có trải nghiệm tốt hơn với các câu lệnh tạo nhiều dòng. - Tạo tập dữ liệu
cymbal_pets_demo:
CREATE SCHEMA IF NOT EXISTS cymbal_pets_demo;
- Tạo bảng cho
order_items,products,orders,stores,customersvàco_related_products_for_angelica. Các bảng này sẽ đóng vai trò là dữ liệu nguồn cho biểu đồ của chúng ta.
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
);
Bây giờ, bạn đã xác định cấu trúc cho dữ liệu biểu đồ.
4. Tải dữ liệu
Bây giờ, hãy điền dữ liệu mẫu từ Cloud Storage vào các bảng.
Chạy các câu lệnh LOAD DATA sau trong trình chỉnh sửa SQL của 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
);
-- 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
);
Bạn sẽ thấy thông báo xác nhận rằng các hàng đã được tải vào mỗi bảng.
5. Tạo biểu đồ thuộc tính
Sau khi tải dữ liệu, giờ đây bạn có thể xác định biểu đồ thuộc tính. Thao tác này cho BigQuery biết bảng nào đại diện cho nút (các thực thể như Khách hàng, Sản phẩm) và bảng nào đại diện cho cạnh (các mối quan hệ như "Đã truy cập", "Đã đặt", "Có").

Chạy câu lệnh DDL sau:
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
);
Thao tác này sẽ tạo biểu đồ PetsOrderGraph, cho phép chúng ta duyệt qua biểu đồ bằng toán tử GRAPH_TABLE.
6. Trực quan hoá Nhật ký mua của tất cả khách hàng
Đối với phần trực quan hoá và đề xuất của lớp học lập trình này, chúng ta sẽ sử dụng tính năng trực quan hoá biểu đồ gốc trong BigQuery Studio. Điều này giúp chúng ta dễ dàng hình dung kết quả của biểu đồ.
Ngoài ra, bạn có thể trực quan hoá trong Sổ ghi chú đồ thị BigQuery bằng IPython Magics. Bằng cách thêm lệnh đặc biệt %%bigquery với hàm TO_JSON, bạn có thể trực quan hoá kết quả như trong các phần sau.
Giả sử Cymbal Pets muốn có thông tin trực quan toàn diện về tất cả khách hàng và giao dịch mua của họ trong một khung thời gian cụ thể.
Chạy câu lệnh sau trong một thẻ BigQuery Studio mới:
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
Để trực quan hoá kết quả, trong ngăn Kết quả truy vấn, hãy nhấp vào Biểu đồ.

7. Trực quan hoá nhật ký mua hàng của Angelica
Giả sử Cymbal Pets muốn tìm hiểu sâu về một khách hàng tên là Angelica Russell. Họ muốn phân tích những sản phẩm mà Angelica đã mua trong vòng 3 tháng qua và những cửa hàng mà khách hàng này đã ghé thăm.
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. Đề xuất sản phẩm bằng tính năng tìm kiếm vectơ
Cymbal Pets muốn đề xuất sản phẩm cho Angelica dựa trên những gì cô ấy đã mua gần đây. Chúng ta có thể sử dụng tính năng tìm kiếm vectơ để tìm những sản phẩm có nhúng tương tự như những sản phẩm mà cô ấy đã mua trước đây.
Chạy tập lệnh SQL sau đây trong một ô mới của Colab. Tập lệnh này:
- Xác định những sản phẩm mà Angelica đã mua gần đây.
- Sử dụng
VECTOR_SEARCHđể tìm 4 sản phẩm tương tự hàng đầu trong bảngproducts.
Lưu ý: Bước này giả định rằng bạn đã chạy AI.GENERATE_EMBEDDINGS để tạo một cột nhúng trong bảng sản phẩm.
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;
Bạn sẽ thấy danh sách các sản phẩm được đề xuất có ngữ nghĩa tương tự như những gì Angelica đã mua.

9. Đề xuất sử dụng "Được mua cùng nhau" và độ tương đồng Jaccard
Một kỹ thuật đề xuất hiệu quả khác là "Lọc cộng tác" – đề xuất những sản phẩm mà người dùng khác thường mua cùng nhau.
Chúng ta có thể tìm thấy những sản phẩm này bằng cách duyệt qua biểu đồ từ một khách hàng đến các sản phẩm họ đã mua, sau đó đến những khách hàng khác đã mua các sản phẩm đó và cuối cùng là đến các sản phẩm khác mà những khách hàng đó đã mua.
Khắc phục thiên kiến về mức độ phổ biến bằng độ tương đồng Jaccard
Mặc dù số lượt mua chung thô rất hữu ích, nhưng số liệu này có thể thiên về các sản phẩm phổ biến. Một sản phẩm rất phổ biến có thể được mua cùng với nhiều sản phẩm khác chỉ do tình cờ.
Độ tương đồng Jaccard đưa các đề xuất tiến thêm một bước bằng cách chuẩn hoá số lượt mua chung. Chỉ số này đo lường mức độ tương đồng giữa hai tập hợp (trong trường hợp này là tập hợp các đơn đặt hàng chứa từng sản phẩm).
Công thức tính độ tương đồng Jaccard là:
Vị trí:
- A giao B là số đơn đặt hàng chứa cả sản phẩm A và sản phẩm B (số lượt mua chung).
- A là tổng số đơn đặt hàng có chứa sản phẩm A.
- B là tổng số đơn đặt hàng có chứa sản phẩm B.
Trong ví dụ sau, tập hợp A = {b,c,e,f,g}, tập hợp B = {a,d,b,g}, giao điểm của chúng A⋂B = {b,g}, hợp của chúng A⋃B = {a,b,c,d,e,f,g}, do đó độ tương đồng Jaccard giữa A và B là 2 / 7 = 0,285714

Tạo và xếp hạng lại đề xuất
Trong các hệ thống đề xuất thực tế hoạt động trên các tập dữ liệu khổng lồ, việc tính toán điểm tương đồng phức tạp (như Jaccard) cho tất cả các cặp sản phẩm có thể là không thực tế. Thay vào đó, một mẫu phổ biến là sử dụng phương pháp hai giai đoạn:
- Tạo đề xuất: Sử dụng một chỉ số đơn giản, nhanh chóng (như số lượt mua chung thô) để lọc không gian tìm kiếm và tìm một số lượng đề xuất có thể quản lý được (ví dụ: 10 đề xuất hàng đầu).
- Xếp hạng lại: Áp dụng một chỉ số chính xác hơn nhưng tốn nhiều tài nguyên tính toán hơn (chẳng hạn như Độ tương đồng Jaccard) để xếp hạng nhóm nhỏ các đề xuất tiềm năng đó và chọn ra những đề xuất hàng đầu cuối cùng.
Trong lớp học lập trình này, chúng ta sẽ làm theo mẫu sau:
- Giai đoạn 1: Chạy một truy vấn để tìm 10 sản phẩm hàng đầu được mua cùng nhau cho mỗi sản phẩm, dựa trên số lượng sản phẩm thô được mua cùng nhau và lưu trữ các sản phẩm đó trong một bảng.
- Giai đoạn 2: Sử dụng truy vấn đồ thị để truy xuất các ứng viên này, xếp hạng họ theo độ tương đồng Jaccard và trả về 3 ứng viên hàng đầu.
[!WARNING] Nhược điểm: Bằng cách lọc theo số lượng thô trong Giai đoạn 1, chúng ta có thể mất "khả năng ghi nhớ" về các giao dịch mua chung có tần suất thấp nhưng có tính cụ thể cao. Nếu một sản phẩm rất giống với một sản phẩm khác nhưng cả hai đều hiếm khi được mua, thì sản phẩm đó có thể không lọt vào danh sách 10 đề xuất hàng đầu và sẽ bị bỏ lỡ.
Chạy truy vấn sau để tính cả số lượt mua chung thô và độ tương đồng Jaccard, đồng thời lưu trữ 10 đề xuất hàng đầu theo số lượt mua thô:
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;

Chạy truy vấn này để đề xuất 3 sản phẩm hàng đầu cho mỗi giao dịch mua của Angelica, được kết nối trực tiếp thông qua cạnh BoughtTogether, cho thấy cả số lượt mua chung và độ tương đồng Jaccard:
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;
Truy vấn này duyệt qua Khách hàng -> Đơn đặt hàng -> Sản phẩm -> (BoughtTogether) -> Sản phẩm được đề xuất, cho bạn thấy các đề xuất dựa trên hành vi mua hàng tập thể và truy xuất điểm tương đồng của các sản phẩm đó.

10. Dọn dẹp
Để tránh bị tính phí liên tục vào tài khoản Google Cloud, hãy xoá các tài nguyên được tạo trong lớp học lập trình này.
Xoá tập dữ liệu và tất cả bảng:
DROP SCHEMA IF EXISTS cymbal_pets_demo CASCADE;
Nếu đã tạo một dự án mới cho lớp học lập trình này, bạn cũng có thể xoá dự án đó:
gcloud projects delete $PROJECT_ID
11. Xin chúc mừng
Xin chúc mừng! Bạn đã xây dựng thành công chân dung khách hàng 360 độ và công cụ đề xuất bằng BigQuery Graph.
Kiến thức bạn học được
- Cách tạo đồ thị thuộc tính trong BigQuery.
- Cách tải dữ liệu vào các nút và cạnh của biểu đồ.
- Cách truy vấn mẫu đồ thị bằng
GRAPH_TABLEvàMATCH. - Cách kết hợp truy vấn đồ thị với tìm kiếm vectơ để đưa ra đề xuất kết hợp.
Các bước tiếp theo
- Khám phá tài liệu về BigQuery Graph.
- Tìm hiểu thêm về Vector Search trong BigQuery.