Xây dựng ứng dụng đề xuất 360 độ về khách hàng bằng BigQuery Graph

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.

Biểu đồ trường hợp sử dụng

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

  1. 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.
  2. Đả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

  1. Nhấp vào Kích hoạt Cloud Shell ở đầu Google Cloud Console.
  2. Xác minh việc xác thực:
gcloud auth list
  1. Xác nhận dự án của bạn:
gcloud config get project
  1. 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.

  1. 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 query trong Cloud Shell. Truy vấn SQL mớiChú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.
  2. Tạo tập dữ liệu cymbal_pets_demo:
CREATE SCHEMA IF NOT EXISTS cymbal_pets_demo;
  1. Tạo bảng cho order_items, products, orders, stores, customers và 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ó").

Giản đồ biểu đồ

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 đồ.

Nhật ký mua hàng của tất cả khách hàng

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

Nhật ký mua hàng của Angelica

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:

  1. Xác định những sản phẩm mà Angelica đã mua gần đây.
  2. Sử dụng VECTOR_SEARCH để tìm 4 sản phẩm tương tự hàng đầu trong bảng products.

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.

Kết quả tìm kiếm vectơ

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:

  1. 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).
  2. 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;

Logic đề xuất

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 đó.

Thường được mua cùng nhau

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_TABLE và 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