1. Wprowadzenie
W tym ćwiczeniu dowiesz się, jak używać BigQuery Graph do tworzenia widoku klienta 360 i silnika rekomendacji dla Cymbal Pets, fikcyjnej firmy handlowej. Wykorzystasz możliwości SQL do tworzenia, wysyłania zapytań i analizowania danych grafu bezpośrednio w BigQuery, łącząc je z wyszukiwaniem wektorowym w celu uzyskania zaawansowanych rekomendacji produktów.
BigQuery Graph umożliwia modelowanie relacji między encjami danych (takimi jak klienci, produkty i zamówienia) jako grafu, co ułatwia odpowiadanie na złożone pytania dotyczące zachowań klientów i powiązań między produktami.

Jakie zadania wykonasz
- Utworzysz zbiór danych i schemat BigQuery dla grafu Cymbal Pets.
- Wczytasz przykładowe dane (klienci, produkty, zamówienia, sklepy) z Cloud Storage.
- Utworzysz graf właściwości w BigQuery, łącząc te encje.
- Zwizualizujesz historię zakupów klientów za pomocą zapytań grafowych.
- Utworzysz system rekomendacji produktów za pomocą wyszukiwania wektorowego.
- Ulepszysz rekomendacje za pomocą relacji grafu „Kupione razem” i podobieństwa Jaccarda.
Czego potrzebujesz
- Przeglądarka internetowa, np. Chrome.
- Projekt Google Cloud z włączonymi rozliczeniami.
To ćwiczenie jest przeznaczone dla deweloperów na wszystkich poziomach zaawansowania, w tym dla początkujących.
2. Zanim zaczniesz
Utwórz projekt Google Cloud
- W konsoli Google Cloud wybierz lub utwórz projekt w chmurze Google Cloud.
- Sprawdź, czy w projekcie w chmurze włączone są płatności.
Uruchamianie Cloud Shell
- Kliknij Aktywuj Cloud Shell na górze konsoli Google Cloud.
- Sprawdź uwierzytelnianie:
gcloud auth list
- Potwierdź wybór projektu:
gcloud config get project
- W razie potrzeby ustaw projekt:
export PROJECT_ID=<YOUR_PROJECT_ID>
gcloud config set project $PROJECT_ID
Włącz interfejsy API
Aby włączyć wymagany interfejs BigQuery API, uruchom to polecenie:
gcloud services enable bigquery.googleapis.com \
bigqueryreservation.googleapis.com
Utwórz rezerwację i przypisanie BigQuery
Aby uruchamiać zapytania GQL, musisz mieć rezerwację, która korzysta z wersji Enterprise lub Enterprise Plus. Utwórz rezerwację w wersji Enterprise z autoskalowaniem w Cloud Shell:
# 1. Create a BigQuery Enterprise reservation with 0 baseline slots and 100 max autoscaling slots
bq mk --reservation \
--project_id=${GCP_PROJECT} \
--location=US \
--edition=ENTERPRISE \
--slots=0 \
--autoscale_max_slots=100 \
--ignore_idle_slots=true \
c360-reservation
# 2. Assign your Cloud project to the newly created reservation for query execution
bq mk --reservation_assignment \
--project_id=${GCP_PROJECT} \
--location=US \
--reservation_id=c360-reservation \
--job_type=QUERY \
--assignee_type=PROJECT \
--assignee_id=${GCP_PROJECT}
3. Określ schemat
Najpierw musisz utworzyć zbiór danych, w którym będą przechowywane tabele związane z grafem, i zdefiniować schemat węzłów i krawędzi.
- W tym ćwiczeniu będziemy wykonywać polecenia SQL. Możesz uruchamiać te polecenia w BigQuery Studio > Edytorze SQL lub użyć polecenia
bq queryw Cloud Shell.
Zakładamy, że używasz edytora SQL BigQuery , aby wygodniej tworzyć instrukcje wielowierszowe. - Utwórz zbiór danych
cymbal_pets_demo:
CREATE SCHEMA IF NOT EXISTS cymbal_pets_demo;
- Utwórz tabele
order_items,products,orders,stores,customers, ico_related_products_for_angelica. Te tabele będą służyć jako źródło danych dla naszego grafu.
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
);
Strukturę danych grafu masz już zdefiniowaną.
4. Wczytaj dane
Teraz wypełnij tabele przykładowymi danymi z Cloud Storage.
W edytorze SQL BigQuery uruchom te instrukcje LOAD DATA:
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
);
Powinna się wyświetlić informacja, że w każdym wierszu wczytano wiersze.
5. Utwórz graf właściwości
Po wczytaniu danych możesz zdefiniować graf właściwości. Informuje to BigQuery, które tabele reprezentują węzły (encje takie jak klienci i produkty), a które tabele reprezentują krawędzie (relacje takie jak „Odwiedził”, „Złożył”, „Ma”).

Uruchom tę instrukcję 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
);
Spowoduje to utworzenie grafu PetsOrderGraph, który umożliwia przechodzenie po grafie za pomocą operatora GRAPH_TABLE.
6. Wizualizacja historii zakupów wszystkich klientów
W części tego ćwiczenia dotyczącej wizualizacji i rekomendacji będziemy używać natywnej wizualizacji grafu w BigQuery Studio. Umożliwia to łatwe wizualizowanie wyników grafu.
Możesz też wizualizować dane w notatniku BigQuery Graph za pomocą poleceń magicznych IPython. Dodając polecenie magiczne %%bigquery z funkcją TO_JSON, możesz wizualizować wyniki tak jak w kolejnych sekcjach.
Załóżmy, że Cymbal Pets chce uzyskać wizualizację 360 stopni wszystkich klientów i ich zakupów w określonym przedziale czasu.
W nowej karcie BigQuery Studio uruchom to polecenie:
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
Aby wizualizować wyniki, w panelu Wyniki zapytania kliknij Graf.

7. Wizualizacja historii zakupów Angeliki
Załóżmy, że Cymbal Pets chce szczegółowo przeanalizować dane klientki o imieniu Angelika Russell. Firma chce przeanalizować produkty, które Angelika kupiła w ciągu ostatnich 3 miesięcy, oraz sklepy, które odwiedziła.
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. Rekomendacje produktów za pomocą wyszukiwania wektorowego
Cymbal Pets chce polecać Angelice produkty na podstawie tego, co ostatnio kupiła. Możemy użyć wyszukiwania wektorowego , aby znaleźć produkty o podobnych wektorach dystrybucyjnych do jej poprzednich zakupów.
W nowej komórce Colab uruchom ten skrypt SQL. Ten skrypt:
- identyfikuje produkty, które Angelika kupiła ostatnio;
- używa
VECTOR_SEARCHdo znajdowania 4 najbardziej podobnych produktów w tabeliproducts.
Uwaga: w tym kroku zakładamy, że masz już uruchomioną funkcję AI.GENERATE_EMBEDDINGS, aby utworzyć kolumnę wektorów dystrybucyjnych w tabeli produktów.
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;
Powinna się wyświetlić lista polecanych produktów, które są semantycznie podobne do tego, co kupiła Angelika.

9. Rekomendacje na podstawie „Kupionych razem” i podobieństwa Jaccarda
Kolejną skuteczną techniką rekomendacji jest „filtrowanie oparte na współpracy” – polecanie produktów, które są często kupowane razem przez innych użytkowników.
Możemy znaleźć te produkty, przechodząc po grafie od klienta do kupionych przez niego produktów, a następnie do innych klientów, którzy kupili te produkty, i wreszcie do innych produktów, które kupili ci klienci.
Eliminowanie efektu popularności za pomocą podobieństwa Jaccarda
Surowe liczby wspólnych zakupów są przydatne, ale mogą być obciążone efektami popularności produktów. Bardzo popularny produkt może być kupowany z wieloma innymi produktami przypadkowo.
Podobieństwo Jaccarda przenosi rekomendacje na wyższy poziom, normalizując liczbę wspólnych zakupów. Mierzy podobieństwo między 2 zbiorami (w tym przypadku zbiorami zamówień zawierających każdy produkt).
Wzór na podobieństwo Jaccarda:
Gdzie:
- A intersect B to liczba zamówień zawierających zarówno produkt A, jak i produkt B (liczba wspólnych zakupów).
- A to łączna liczba zamówień zawierających produkt A.
- B to łączna liczba zamówień zawierających produkt B.
W tym przykładzie zbiór A = {b, c,e,f,g}, zbiór B = {a,d,b,g}, ich przecięcie A⋂B = {b,g}, ich suma A⋃B = {a,b,c,d,e,f,g}, a zatem podobieństwo Jaccarda między A i B wynosi 2 / 7 = 0,285714.

Generowanie kandydatów i ponowne ocenianie
W rzeczywistych systemach rekomendacji działających na ogromnych zbiorach danych często nie można obliczyć złożonych wyników podobieństwa (takich jak Jaccard) dla wszystkich możliwych par produktów. Zamiast tego powszechnie stosuje się podejście dwuetapowe:
- Generowanie kandydatów: użyj prostej i szybkiej miary (np.surowej liczby wspólnych zakupów), aby przefiltrować przestrzeń wyszukiwania i znaleźć odpowiednią liczbę kandydatów (np. 10 najlepszych).
- Ponowne ocenianie: zastosuj dokładniejszą, ale bardziej wymagającą obliczeniowo miarę (np. podobieństwo Jaccarda), aby ocenić ten niewielki zbiór kandydatów i wybrać ostateczne najlepsze rekomendacje.
W tym ćwiczeniu będziemy postępować zgodnie z tym wzorcem:
- Etap 1: uruchom zapytanie, aby znaleźć 10 najczęściej kupowanych razem produktów dla każdego produktu na podstawie surowej liczby wspólnych zakupów, i zapisz je w tabeli.
- Etap 2: użyj zapytania grafowego, aby pobrać tych kandydatów, ocenić ich według podobieństwa Jaccarda i zwrócić 3 najlepsze.
[!WARNING] Wada: filtrując według surowej liczby na etapie 1, możemy utracić "czułość" w przypadku bardzo konkretnych, ale rzadkich wspólnych zakupów. Jeśli produkt jest bardzo podobny do innego, ale oba są rzadko kupowane, może nie znaleźć się w 10 najlepszych kandydatach i zostanie pominięty.
Aby obliczyć zarówno surową liczbę wspólnych zakupów, jak i podobieństwo Jaccarda, i zapisać 10 najlepszych kandydatów według surowej liczby, uruchom to zapytanie:
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;

Aby polecić 3 najlepsze produkty dla każdego zakupu Angeliki, połączone bezpośrednio krawędzią BoughtTogether, i wyświetlić zarówno liczbę wspólnych zakupów, jak i podobieństwo Jaccarda, uruchom to zapytanie:
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;
To zapytanie przechodzi od klienta przez zamówienie do produktu, a następnie do polecanego produktu (BoughtTogether), wyświetlając rekomendacje na podstawie zbiorowego zachowania zakupowego i pobierając wyniki podobieństwa.

10. Zwalnianie miejsca
Aby uniknąć obciążenia konta Google Cloud bieżącymi opłatami, usuń zasoby utworzone podczas tego ćwiczenia.
Usuń zbiór danych i wszystkie tabele:
DROP SCHEMA IF EXISTS cymbal_pets_demo CASCADE;
Jeśli na potrzeby tego ćwiczenia został przez Ciebie utworzony nowy projekt, możesz go też usunąć:
gcloud projects delete $PROJECT_ID
11. Gratulacje
Gratulacje! Udało Ci się utworzyć widok klienta 360 i silnik rekomendacji za pomocą BigQuery Graph.
Czego się dowiesz
- Jak utworzyć graf właściwości w BigQuery.
- Jak wczytywać dane do węzłów i krawędzi grafu.
- Jak wysyłać zapytania dotyczące wzorców grafu za pomocą
GRAPH_TABLEiMATCH. - Jak łączyć zapytania grafowe z wyszukiwaniem wektorowym w celu uzyskania rekomendacji hybrydowych.
Dalsze kroki
- Zapoznaj się z dokumentacją BigQuery Graph.
- Dowiedz się więcej o wyszukiwaniu wektorowym w BigQuery.