1. Wprowadzenie
Spanner to w pełni zarządzana, skalowalna w poziomie i rozproszona globalnie usługa baz danych, która doskonale sprawdza się w przypadku relacyjnych i nierelacyjnych zbiorów zadań operacyjnych.
Spanner ma wbudowaną obsługę wyszukiwania wektorowego, umożliwia wykonywanie wyszukiwania podobieństw lub semantycznych oraz implementowanie generowania rozszerzonego przez pobieranie w aplikacjach generatywnej AI na dużą skalę z wykorzystaniem funkcji dokładnie K-najbliższego sąsiada (KNN) lub przybliżonego najbliższego sąsiada (ANN).
Zapytania wektorowe w usłudze Spanner zwracają aktualne dane w czasie rzeczywistym zaraz po zrealizowaniu transakcji, tak jak wszystkie inne zapytania dotyczące danych operacyjnych.
W tym module dowiesz się, jak skonfigurować podstawowe funkcje wymagane do wykorzystania usługi Spanner do wyszukiwania wektorowego oraz uzyskać dostęp do modeli wektorów dystrybucyjnych i LLM z ogrodu modeli VertexAI za pomocą języka SQL.
Architektura będzie wyglądać tak:
Dzięki temu dowiesz się, jak utworzyć indeks wektorów oparty na algorytmie ScaNN i jak używać funkcji odległości APPROX, gdy musisz skalować zadania semantyczne.
Co utworzysz
W ramach tego modułu:
- Tworzenie instancji usługi Spanner
- Skonfiguruj schemat bazy danych Spannera, aby przeprowadzić integrację z modelami wektora dystrybucyjnego i LLM w Vertex AI
- Wczytaj zbiór danych handlu detalicznego
- Wyślij zapytania dotyczące podobieństwa problemów do zbioru danych
- Podaj kontekst dla modelu LLM, aby generować rekomendacje dla poszczególnych usług.
- Zmodyfikuj schemat i utwórz indeks wektorów.
- Zmień zapytania, aby wykorzystać nowo utworzony indeks wektorów.
Czego się nauczysz
- Jak skonfigurować instancję usługi Spanner
- Integracja z VertexAI
- Jak za pomocą usługi Spanner przeprowadzać wyszukiwanie wektorowe, aby znaleźć podobne elementy w zbiorze danych handlu detalicznego
- Jak przygotować bazę danych do skalowania zadań wyszukiwania wektorowego za pomocą wyszukiwania ANN.
Czego potrzebujesz
2. Konfiguracja i wymagania
Utwórz projekt
Jeśli nie masz jeszcze konta Google (w Gmailu lub Google Apps), musisz je utworzyć. Zaloguj się w konsoli Google Cloud Platform ( console.cloud.google.com) i utwórz nowy projekt.
Jeśli masz już projekt, kliknij menu wyboru projektu w lewym górnym rogu konsoli:
i kliknij „NOWY PROJEKT”. w wyświetlonym oknie, aby utworzyć nowy projekt:
Jeśli nie masz jeszcze projektu, zobaczysz takie okno dialogowe umożliwiające utworzenie pierwszego:
W kolejnym oknie tworzenia projektu możesz wpisać szczegóły nowego projektu:
Zapamiętaj identyfikator projektu, który jest niepowtarzalną nazwą we wszystkich projektach Google Cloud (powyższa nazwa jest już zajęta i nie będzie Ci odpowiadać). W dalszej części tego ćwiczenia z programowania będzie on określany jako PROJECT_ID.
Następnie musisz włączyć płatności w Developers Console, aby korzystać z zasobów Google Cloud i włączyć interfejs Spanner API.
Wykonanie tych ćwiczeń w programie nie powinno kosztować więcej niż kilka dolarów, ale może być droższe, jeśli zdecydujesz się na więcej zasobów lub pozostawisz je włączone (patrz sekcja „Czyszczenie” na końcu tego dokumentu). Cennik Google Cloud Spanner znajdziesz tutaj.
Nowi użytkownicy Google Cloud Platform mogą skorzystać z bezpłatnego okresu próbnego w wysokości 300 USD, dzięki czemu te ćwiczenia z programowania są całkowicie bezpłatne.
Konfiguracja Google Cloud Shell
Usługi Google Cloud i Spanner można obsługiwać zdalnie z poziomu laptopa, ale w ramach tego ćwiczenia w programowaniu użyjemy Google Cloud Shell – środowiska wiersza poleceń działającego w chmurze.
Ta maszyna wirtualna oparta na Debianie zawiera wszystkie potrzebne narzędzia dla programistów. Zawiera stały katalog domowy o pojemności 5 GB i działa w Google Cloud, co znacznie zwiększa wydajność sieci i uwierzytelnianie. Oznacza to, że do tego ćwiczenia z programowania wystarczy przeglądarka (tak, działa ona na Chromebooku).
- Aby aktywować Cloud Shell z poziomu konsoli Cloud, kliknij Aktywuj Cloud Shell (udostępnienie środowiska i połączenie z nim powinno zająć tylko chwilę).
Po nawiązaniu połączenia z Cloud Shell powinno pojawić się potwierdzenie, że użytkownik jest już uwierzytelniony, a projekt ma już ustawiony identyfikator PROJECT_ID.
gcloud auth list
Dane wyjściowe polecenia
Credentialed accounts:
- <myaccount>@<mydomain>.com (active)
gcloud config list project
Dane wyjściowe polecenia
[core]
project = <PROJECT_ID>
Jeśli z jakiegoś powodu projekt nie jest skonfigurowany, uruchom po prostu to polecenie:
gcloud config set project <PROJECT_ID>
Szukasz urządzenia PROJECT_ID
? Sprawdź identyfikator użyty w krokach konfiguracji lub wyszukaj go w panelu Cloud Console:
Cloud Shell ustawia też domyślnie niektóre zmienne środowiskowe, które mogą być przydatne podczas uruchamiania kolejnych poleceń.
echo $GOOGLE_CLOUD_PROJECT
Dane wyjściowe polecenia
<PROJECT_ID>
Włączanie interfejsu Spanner API
gcloud services enable spanner.googleapis.com
Podsumowanie
W tym kroku skonfigurujesz projekt (jeśli jeszcze go nie masz), aktywujesz Cloud Shell i włączysz wymagane interfejsy API.
Następny krok
Następnie skonfigurujesz instancję i bazę danych Spanner.
3. Tworzenie instancji i bazy danych Spanner
Tworzenie instancji usługi Spanner
W tym kroku skonfigurowaliśmy instancję Spannera na potrzeby ćwiczeń w Codelabs. W tym celu otwórz Cloud Shell i uruchom to polecenie:
export SPANNER_INSTANCE_ID=retail-demo
gcloud spanner instances create $SPANNER_INSTANCE_ID \
--config=regional-us-central1 \
--description="spanner AI retail demo" \
--nodes=1
Dane wyjściowe polecenia:
$ gcloud spanner instances create $SPANNER_INSTANCE_ID \
--config=regional-us-central1 \
--description="spanner AI retail demo" \
--nodes=1
Creating instance...done.
Tworzenie bazy danych
Gdy instancja zacznie działać, możesz utworzyć bazę danych. Spanner umożliwia korzystanie z wielu baz danych w jednej instancji.
Baza danych to miejsce, w którym definiujesz schemat. Możesz też kontrolować, kto ma dostęp do bazy danych, skonfigurować szyfrowanie niestandardowe, skonfigurować optymalizatora i ustawić okres przechowywania.
Aby utworzyć bazę danych, ponownie użyj narzędzia wiersza poleceń gcloud:
export SPANNER_DATABASE=cymbal-bikes
gcloud spanner databases create $SPANNER_DATABASE \
--instance=$SPANNER_INSTANCE_ID
Dane wyjściowe polecenia:
$ gcloud spanner databases create $SPANNER_DATABASE \
--instance=$SPANNER_INSTANCE_ID
Creating database...done.
Podsumowanie
W tym kroku utworzysz instancję i bazę danych Spanner.
Następny krok
Następnie skonfiguruj schemat i dane Spannera.
4. Wczytaj schemat i dane Cymbal
Tworzenie schematu Cymbal
Aby skonfigurować schemat, otwórz Spanner Studio:
Schemat składa się z 2 części. Najpierw dodaj tabelę products
. Skopiuj tę instrukcję i wklej ją na pustej karcie.
Skopiuj ten DDL i wklej go w polu schematu:
CREATE TABLE products (
categoryId INT64 NOT NULL,
productId INT64 NOT NULL,
productName STRING(MAX) NOT NULL,
productDescription STRING(MAX) NOT NULL,
productDescriptionEmbedding ARRAY<FLOAT32>,
createTime TIMESTAMP NOT NULL OPTIONS (
allow_commit_timestamp = true
),
inventoryCount INT64 NOT NULL,
priceInCents INT64,
) PRIMARY KEY(categoryId, productId);
Następnie kliknij przycisk run
i zaczekaj kilka sekund na utworzenie schematu.
Następnie utworzysz 2 modele i skonfigurujesz je pod kątem punktów końcowych modelu VertexAI.
Pierwszy to model wektora dystrybucyjnego używany do generowania wektorów dystrybucyjnych z tekstu, a drugi to model LLM używany do generowania odpowiedzi na podstawie danych w usłudze Spanner.
Wklej ten schemat na nowej karcie w Spanner Studio:
CREATE MODEL EmbeddingsModel INPUT(
content STRING(MAX),
) OUTPUT(
embeddings STRUCT<statistics STRUCT<truncated BOOL, token_count FLOAT32>, values ARRAY<FLOAT32>>,
) REMOTE OPTIONS (
endpoint = '//aiplatform.googleapis.com/projects/<PROJECT_ID>/locations/us-central1/publishers/google/models/text-embedding-004'
);
CREATE MODEL LLMModel INPUT(
prompt STRING(MAX),
) OUTPUT(
content STRING(MAX),
) REMOTE OPTIONS (
endpoint = '//aiplatform.googleapis.com/projects/<PROJECT_ID>/locations/us-central1/publishers/google/models/gemini-pro',
default_batch_size = 1
);
Następnie kliknij przycisk run
i poczekaj kilka sekund na utworzenie modeli.
W lewym panelu Spanner Studio powinny być widoczne te tabele i modele:
Wczytywanie danych
Teraz musisz wstawić produkty do bazy danych. Otwórz nową kartę w Spanner Studio, a następnie skopiuj i wklej te instrukcje wstawiania:
INSERT INTO products (categoryId, productId, productName, productDescription, createTime, inventoryCount, priceInCents)
VALUES (1, 1, "Cymbal Helios Helmet", "Safety meets style with the Cymbal children's bike helmet. Its lightweight design, superior ventilation, and adjustable fit ensure comfort and protection on every ride. Stay bright and keep your child safe under the sun with Cymbal Helios!", PENDING_COMMIT_TIMESTAMP(), 100, 10999),
(1, 2, "Cymbal Sprout", "Let their cycling journey begin with the Cymbal Sprout, the ideal balance bike for beginning riders ages 2-4 years. Its lightweight frame, low seat height, and puncture-proof tires promote stability and confidence as little ones learn to balance and steer. Watch them sprout into cycling enthusiasts with Cymbal Sprout!", PENDING_COMMIT_TIMESTAMP(), 10, 13999),
(1, 3, "Cymbal Spark Jr.", "Light, vibrant, and ready for adventure, the Spark Jr. is the perfect first bike for young riders (ages 5-8). Its sturdy frame, easy-to-use brakes, and puncture-resistant tires inspire confidence and endless playtime. Let the spark of cycling ignite with Cymbal!", PENDING_COMMIT_TIMESTAMP(), 34, 13900),
(1, 4, "Cymbal Summit", "Conquering trails is a breeze with the Summit mountain bike. Its lightweight aluminum frame, responsive suspension, and powerful disc brakes provide exceptional control and comfort for experienced bikers navigating rocky climbs or shredding downhill. Reach new heights with Cymbal Summit!", PENDING_COMMIT_TIMESTAMP(), 0, 79999),
(1, 5, "Cymbal Breeze", "Cruise in style and embrace effortless pedaling with the Breeze electric bike. Its whisper-quiet motor and long-lasting battery let you conquer hills and distances with ease. Enjoy scenic rides, commutes, or errands with a boost of confidence from Cymbal Breeze!", PENDING_COMMIT_TIMESTAMP(), 72, 129999),
(1, 6, "Cymbal Trailblazer Backpack", "Carry all your essentials in style with the Trailblazer backpack. Its water-resistant material, multiple compartments, and comfortable straps keep your gear organized and accessible, allowing you to focus on the adventure. Blaze new trails with Cymbal Trailblazer!", PENDING_COMMIT_TIMESTAMP(), 24, 7999),
(1, 7, "Cymbal Phoenix Lights", "See and be seen with the Phoenix bike lights. Powerful LEDs and multiple light modes ensure superior visibility, enhancing your safety and enjoyment during day or night rides. Light up your journey with Cymbal Phoenix!", PENDING_COMMIT_TIMESTAMP(), 87, 3999),
(1, 8, "Cymbal Windstar Pump", "Flat tires are no match for the Windstar pump. Its compact design, lightweight construction, and high-pressure capacity make inflating tires quick and effortless. Get back on the road in no time with Cymbal Windstar!", PENDING_COMMIT_TIMESTAMP(), 36, 24999),
(1, 9,"Cymbal Odyssey Multi-Tool","Be prepared for anything with the Odyssey multi-tool. This handy gadget features essential tools like screwdrivers, hex wrenches, and tire levers, keeping you ready for minor repairs and adjustments on the go. Conquer your journey with Cymbal Odyssey!", PENDING_COMMIT_TIMESTAMP(), 52, 999),
(1, 10,"Cymbal Nomad Water Bottle","Stay hydrated on every ride with the Nomad water bottle. Its sleek design, BPA-free construction, and secure lock lid make it the perfect companion for staying refreshed and motivated throughout your adventures. Hydrate and explore with Cymbal Nomad!", PENDING_COMMIT_TIMESTAMP(), 42, 1299);
Kliknij przycisk run
, aby wstawić dane.
Podsumowanie
W tym kroku udało Ci się utworzyć schemat i wczytać podstawowe dane do bazy danych cymbal-bikes
.
Następny krok
Następnie przeprowadzisz integrację z modelem umieszczania, aby generować reprezentacje właściwościowe dla opisów produktów, a także przekonwertować tekstowe żądanie wyszukiwania na wektory dystrybucyjne w celu wyszukiwania odpowiednich produktów.
5. Praca z wektorami dystrybucyjnymi
Generuj wektory dystrybucyjne wektorów dla opisów produktów
Aby wyszukiwanie podobieństwa działało w przypadku produktów, musisz wygenerować wektory dystrybucyjne dla opisów produktów.
Przy użyciu EmbeddingsModel
utworzonego w schemacie jest to prosta instrukcja DML UPDATE
.
UPDATE products p1
SET productDescriptionEmbedding =
(SELECT embeddings.values from ML.PREDICT(MODEL EmbeddingsModel,
(SELECT productDescription as content FROM products p2 where p2.productId=p1.productId)))
WHERE categoryId=1;
Kliknij przycisk run
, aby zaktualizować opisy produktów.
Korzystanie z wyszukiwania wektorowego
W tym przykładzie przekażemy za pomocą zapytania SQL żądanie wyszukiwania w języku naturalnym. To zapytanie przekształci żądanie wyszukiwania w wektor dystrybucyjny, a następnie wyszuka podobne wyniki na podstawie zapisanych wektorów dystrybucyjnych opisów produktów, które zostały wygenerowane w poprzednim kroku.
-- Use Spanner's vector search, and integration with embedding and LLM models to
-- return items that are semantically relevant and available in inventory based on
-- real-time data.
SELECT productName, productDescription, inventoryCount, COSINE_DISTANCE(
productDescriptionEmbedding,
( SELECT embeddings.values
FROM ML.PREDICT(
MODEL EmbeddingsModel,
(SELECT "I'd like to buy a starter bike for my 3 year old child" as content)
)
)
) as distance
FROM products
WHERE inventoryCount > 0
ORDER BY distance
LIMIT 5;
Kliknij przycisk run
, aby znaleźć podobne produkty. Wyniki powinny wyglądać tak:
Zwróć uwagę, że do zapytania zostały użyte dodatkowe filtry, np. interesują Cię tylko produkty, które są w magazynie (inventoryCount > 0
).
Podsumowanie
W tym kroku utworzyliśmy wektory dystrybucyjne opisów produktów i żądania wyszukiwania z użyciem języka SQL, wykorzystując integrację usługi Spanner z modelami w Vertex AI. Przeprowadzono również wyszukiwanie wektorowe, aby znaleźć podobne produkty pasujące do żądania wyszukiwania.
Następne kroki
Następnie użyjemy wyników wyszukiwania, aby przesłać dane do LLM, aby wygenerować niestandardową odpowiedź dla każdego produktu.
6. Praca z LLM
Spanner ułatwia integrację z modelami LLM obsługiwanymi przez VertexAI. Dzięki temu deweloperzy mogą używać SQL do bezpośredniego łączenia się z LLM, bez konieczności wykonywania logiki przez aplikację.
Mamy na przykład wyniki poprzedniego zapytania SQL od użytkownika "I'd like to buy a starter bike for my 3 year old child".
Deweloper chce w przypadku każdego wyniku określić, czy produkt jest odpowiedni dla użytkownika. Aby to zrobić, użyj tego promptu:
"Answer with ‘Yes' or ‘No' and explain why: Is this a good fit for me? I'd like to buy a starter bike for my 3 year old child"
Przykładowe zapytanie, którego możesz użyć:
-- Use an LLM to analyze this list and provide a recommendation on whether each
-- product is a good fit for the user. We use the vector search and real time
-- inventory data to first filter the products to reduce the size of the prompt to
-- the LLM.
SELECT productName, productDescription, inventoryCount, content AS LLMResponse
FROM ML.PREDICT(
MODEL LLMModel,
( SELECT
inventoryCount,
productName,
productDescription,
CONCAT(
"Answer with ‘Yes' or ‘No' and explain why: Is this a good fit for me?",
"I'd like to buy a starter bike for my 3 year old child \n",
"Product Name: ", productName, "\n",
"Product Description:", productDescription) AS prompt,
FROM products
WHERE inventoryCount > 0
ORDER by COSINE_DISTANCE(
productDescriptionEmbedding,
( SELECT embeddings.values
FROM ML.PREDICT(
MODEL EmbeddingsModel,
( SELECT "I'd like to buy a starter bike for my 3 year old child" as content)
)
)
) LIMIT 5
),
STRUCT(256 AS maxOutputTokens)
);
Aby wysłać zapytanie, kliknij przycisk run
. Wyniki powinny wyglądać tak:
Pierwszy produkt jest odpowiedni dla osób w wieku 3 lat ze względu na przedział wiekowy podany w opisie produktu (2–4 lata). Pozostałe produkty nie spełniły oczekiwań.
Podsumowanie
W tym kroku pracowaliśmy z LLM, aby wygenerować podstawowe odpowiedzi na prompty użytkownika.
Następne kroki
Teraz nauczymy się, jak używać ANN do skalowania wyszukiwania wektorowego.
7. Skalowanie wyszukiwania wektorowego
Poprzednie przykłady wyszukiwania wektorowego bazowały na dokładnym wyszukiwaniu wektorowym KNN. To świetne rozwiązanie, gdy możesz wykonywać zapytania na bardzo konkretnych podzbiorach danych Spanner. Tego typu zapytania są podobno dające duże partycje.
Jeśli nie masz zbiorów zadań, które można bardzo partycjonować, i masz dużą ilość danych, warto użyć wyszukiwania wektorowego ANN z wykorzystaniem algorytmu ScaNN, aby zwiększyć wydajność wyszukiwania.
Aby to zrobić w usłudze Spanner, musisz wykonać 2 czynności:
- Utwórz indeks wektorów
- Zmodyfikuj zapytanie, aby użyć funkcji odległości APPROX.
Tworzenie indeksu wektorów
Aby utworzyć indeks wektorów dla tego zbioru danych, musimy najpierw zmodyfikować kolumnę productDescriptionEmbeddings
i określić długość każdego wektora. Aby dodać długość wektora do kolumny, trzeba upuścić pierwotną kolumnę i utworzyć ją ponownie.
ALTER TABLE `products` DROP COLUMN `productDescriptionEmbedding`;
ALTER TABLE
`products` ADD COLUMN `productDescriptionEmbedding` ARRAY<FLOAT32>(vector_length=>768);
Następnie ponownie utwórz wektory dystrybucyjne na podstawie przeprowadzonego wcześniej kroku Generate Vector embedding
.
UPDATE products p1
SET productDescriptionEmbedding =
(SELECT embeddings.values from ML.PREDICT(MODEL EmbeddingsModel,
(SELECT productDescription as content FROM products p2 where p2.productId=p1.productId)))
WHERE categoryId=1;
Po utworzeniu kolumny utwórz indeks:
CREATE VECTOR INDEX ProductDescriptionEmbeddingIndex
ON products(productDescriptionEmbedding)
WHERE productDescriptionEmbedding IS NOT NULL
OPTIONS (
distance_type = 'COSINE'
);
Użyj nowego indeksu
Aby użyć nowego indeksu wektorów, musisz nieznacznie zmodyfikować poprzednie zapytanie wektora dystrybucyjnego.
Oto pierwotne zapytanie:
SELECT productName, productDescription, inventoryCount, COSINE_DISTANCE(
productDescriptionEmbedding,
( SELECT embeddings.values
FROM ML.PREDICT(
MODEL EmbeddingsModel,
(SELECT "I'd like to buy a starter bike for my 3 year old child" as content)
)
)
) as distance
FROM products
WHERE inventoryCount > 0
ORDER BY distance
LIMIT 5;
Musisz wprowadzić te zmiany:
- Użyj wskazówki dotyczącej indeksu dla nowego indeksu wektorów:
@{force_index=ProductDescriptionEmbeddingIndex}
- Zmień wywołanie funkcji
COSINE_DISTANCE
naAPPROX_COSINE_DISTANCE
. Pamiętaj, że opcje JSON w ostatnim zapytaniu poniżej też są wymagane. - Wygeneruj wektory dystrybucyjne oddzielnie z funkcji ML.PREDICT.
- Skopiuj wyniki wektorów dystrybucyjnych do końcowego zapytania.
Generowanie wektorów dystrybucyjnych
-- Generate the prompt embeddings
SELECT embeddings.values
FROM ML.PREDICT(
MODEL EmbeddingsModel,
(SELECT "I'd like to buy a starter bike for my 3 year old child" as content)
)
)
Zaznacz wyniki zapytania i skopiuj je.
Następnie zastąp <VECTOR>
w następującym zapytaniu, wklejając skopiowane wektory dystrybucyjne.
-- Embedding query now using the vector index
SELECT productName, productDescription, inventoryCount,
APPROX_COSINE_DISTANCE(productDescriptionEmbedding, array<float32>[@VECTOR], options => JSON '{\"num_leaves_to_search\": 10}')
FROM products @{force_index=ProductDescriptionEmbeddingIndex}
WHERE productDescriptionEmbedding IS NOT NULL AND inventoryCount > 0
ORDER BY distance
LIMIT 5;
Powinna wyglądać mniej więcej tak:
Podsumowanie
W tym kroku przekonwertowano schemat w celu utworzenia indeksu wektorów. Następnie przeredagowaliśmy zapytanie wektora dystrybucyjnego tak, aby przeprowadzać wyszukiwanie ANN przy użyciu indeksu wektorów. Jest to ważny krok podczas zwiększania ilości danych w celu skalowania zadań wyszukiwania wektorowego.
Następne kroki
Czas na posprzątanie!
8. Czyszczenie (opcjonalne)
Aby wyczyścić dane, przejdź do sekcji Cloud Spanner w konsoli Cloud i usuń instancję „retail-demo
”, którą utworzyliśmy w ramach ćwiczenia.
9. Gratulacje!
Gratulujemy! Udało Ci się przeprowadzić wyszukiwanie podobieństw za pomocą wbudowanego wyszukiwania wektorowego w usłudze Spanner. Wiesz też, jak łatwo można korzystać z modeli wektora dystrybucyjnego i LLM do udostępniania funkcji generatywnej AI bezpośrednio za pomocą języka SQL.
Przedstawiliśmy też proces wyszukiwania ANN oparty na algorytmie ScaNN na potrzeby skalowania zadań wyszukiwania wektorowego.
Co dalej?
Więcej informacji o funkcji dokładnego najbliższych sąsiadów usługi Spanner (wyszukiwanie wektorowe KNN) znajdziesz tutaj: https://cloud.google.com/spanner/docs/find-k-nearest-neighbors.
Więcej informacji o funkcji przybliżonych najbliższych sąsiadów (wyszukiwanie wektorowe ANN) znajdziesz tutaj: https://cloud.google.com/spanner/docs/find-approximate-nearest-neighbors.
Więcej informacji o wykonywaniu prognoz online za pomocą SQL przy użyciu integracji VertexAI w usłudze Spanner znajdziesz też tutaj: https://cloud.google.com/spanner/docs/ml.