1. Wprowadzenie
Spanner to usługa w pełni zarządzana, skalowalna w poziomie, globalnie rozproszona usługa bazy danych, która doskonale sprawdza się w przypadku relacyjnych i nierelacyjnych obciążeń operacyjnych.
Spanner ma wbudowaną obsługę wyszukiwania wektorowego, co umożliwia przeprowadzanie wyszukiwania podobieństwa lub semantycznego oraz implementowanie generowania rozszerzonego przez wyszukiwanie w zapisanych informacjach (RAG) w aplikacjach GenAI na dużą skalę. Możesz korzystać z funkcji dokładnego wyszukiwania K najbliższych sąsiadów (KNN) lub przybliżonego wyszukiwania najbliższych sąsiadów (ANN).
Zapytania wyszukiwania wektorowego w usłudze Spanner zwracają aktualne dane w czasie rzeczywistym zaraz po zatwierdzeniu transakcji, tak jak każde inne zapytanie dotyczące danych operacyjnych.
W tym laboratorium dowiesz się, jak skonfigurować podstawowe funkcje wymagane do korzystania z usługi Spanner w celu przeprowadzania wyszukiwania wektorowego oraz uzyskiwania dostępu do modeli wektorów dystrybucyjnych i LLM z model garden VertexAI za pomocą SQL.
Architektura będzie wyglądać tak:
Na tej podstawie dowiesz się, jak utworzyć indeks wektorowy oparty na algorytmie ScaNN, oraz jak używać funkcji odległości APPROX, gdy obciążenia semantyczne wymagają skalowania.
Co utworzysz
W ramach tego modułu wykonasz te czynności:
- Utworzysz instancję Spannera.
- Skonfigurujesz schemat bazy danych Spannera, aby zintegrować go z modelami wektorów dystrybucyjnych i LLM w VertexAI.
- Wczytasz zbiór danych o sprzedaży detalicznej.
- Wyślesz do zbioru danych zapytania o wyszukiwanie podobieństwa.
- Podasz modelowi LLM kontekst, aby wygenerować rekomendacje dotyczące konkretnych produktów.
- Zmodyfikujesz schemat i utworzysz indeks wektorowy.
- Zmienisz zapytania, aby korzystać z nowo utworzonego indeksu wektorowego.
Czego się nauczysz
- Jak skonfigurować instancję Spannera.
- Jak zintegrować się z VertexAI.
- Jak używać Spannera do przeprowadzania wyszukiwania wektorowego w celu znajdowania podobnych produktów w zbiorze danych o sprzedaży detalicznej.
- Jak przygotować bazę danych do skalowania obciążeń wyszukiwania wektorowego za pomocą wyszukiwania ANN.
Czego potrzebujesz
2. Konfiguracja i wymagania
Utwórz projekt
Jeśli nie masz jeszcze konta Google (Gmail 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:

W wyświetlonym oknie kliknij przycisk „NOWY PROJEKT”, aby utworzyć nowy projekt:

Jeśli nie masz jeszcze projektu, powinno się wyświetlić takie okno, w którym możesz utworzyć pierwszy projekt:

W kolejnym oknie tworzenia projektu możesz wpisać szczegóły nowego projektu:

Zapamiętaj identyfikator projektu, który jest unikalną nazwą we wszystkich projektach Google Cloud (nazwa powyżej jest już zajęta i nie będzie działać, przepraszamy). W dalszej części tego ćwiczenia będzie on określany jako PROJECT_ID.
Następnie, jeśli jeszcze tego nie zrobisz, musisz włączyć płatności w konsoli dewelopera, aby móc korzystać z zasobów Google Cloud i włączyć interfejs Spanner API.

Wykonanie tego ćwiczenia nie powinno kosztować więcej niż kilka dolarów, ale może okazać się droższe, jeśli zdecydujesz się wykorzystać więcej zasobów lub pozostawisz je uruchomione (patrz sekcja „Czyszczenie” na końcu tego dokumentu). Ceny Google Cloud Spanner są opisane tutaj.
Nowi użytkownicy Google Cloud Platform mogą skorzystać z bezpłatnego okresu próbnego, w którym mają do dyspozycji środki w wysokości 300 USD. Dzięki temu to ćwiczenie powinno być całkowicie bezpłatne.
Konfiguracja Google Cloud Shell
Chociaż Google Cloud i Spanner można obsługiwać zdalnie z laptopa, w tym ćwiczeniu będziemy używać Google Cloud Shell, czyli środowiska wiersza poleceń działającego w chmurze.
Ta maszyna wirtualna oparta na Debianie zawiera wszystkie potrzebne narzędzia dla programistów. Zawiera również stały katalog domowy o pojemności 5 GB i działa w Google Cloud, co znacznie zwiększa wydajność sieci i usprawnia proces uwierzytelniania. Oznacza to, że do wykonania tego ćwiczenia potrzebujesz tylko przeglądarki (tak, działa ona na Chromebooku).
- Aby aktywować Cloud Shell w konsoli Cloud, kliknij Aktywuj Cloud Shell
(uzyskanie dostępu do środowiska i połączenie się z nim powinno zająć tylko kilka chwil).


Po połączeniu z Cloud Shell zobaczysz, że uwierzytelnianie zostało już przeprowadzone, a projekt jest już ustawiony na Twój identyfikator projektu.
gcloud auth list
Wynik polecenia
Credentialed accounts:
- <myaccount>@<mydomain>.com (active)
gcloud config list project
Wynik polecenia
[core]
project = <PROJECT_ID>
Jeśli z jakiegoś powodu projekt nie jest ustawiony, po prostu uruchom to polecenie:
gcloud config set project <PROJECT_ID>
Szukasz swojego PROJECT_ID? Sprawdź, jakiego identyfikatora używasz w krokach konfiguracji, lub znajdź go w panelu konsoli Cloud:

Cloud Shell domyślnie ustawia też kilka zmiennych środowiskowych, które mogą się przydać podczas wykonywania przyszłych poleceń.
echo $GOOGLE_CLOUD_PROJECT
Wynik polecenia
<PROJECT_ID>
Włącz interfejs Spanner API
gcloud services enable spanner.googleapis.com
Podsumowanie
W tym kroku skonfigurowaliśmy projekt, jeśli go jeszcze nie było, aktywowaliśmy Cloud Shell i włączyliśmy wymagane interfejsy API.
Następny krok
Następnie skonfigurujesz instancję i bazę danych Spannera.
3. Tworzenie instancji i bazy danych Spannera
Tworzenie instancji Spannera
W tym kroku skonfigurujemy instancję Spannera na potrzeby ćwiczenia. Aby to zrobić, 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
--edition=ENTERPRISE
Wynik polecenia:
$ gcloud spanner instances create $SPANNER_INSTANCE_ID \
--config=regional-us-central1 \
--description="spanner AI retail demo" \
--nodes=1
--edition=ENTERPRISE
Creating instance...done.
Tworzenie bazy danych
Gdy instancja będzie działać, możesz utworzyć bazę danych. Spanner umożliwia korzystanie z wielu baz danych w jednej instancji.
W bazie danych definiujesz schemat. Możesz też kontrolować, kto ma dostęp do bazy danych, konfigurować niestandardowe szyfrowanie, konfigurować optymalizator i ustawiać 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
Wynik polecenia:
$ gcloud spanner databases create $SPANNER_DATABASE \
--instance=$SPANNER_INSTANCE_ID
Creating database...done.
Podsumowanie
W tym kroku utworzyliśmy instancję i bazę danych Spannera.
Następny krok
Następnie skonfigurujesz schemat i dane Spannera.
4. Wczytywanie schematu i danych Cymbal
Tworzenie schematu Cymbal
Aby skonfigurować schemat, otwórz Spanner Studio:

Schemat składa się z 2 części. Najpierw dodaj tabelę products. Skopiuj i wklej to stwierdzenie na pustej karcie.
Aby utworzyć schemat, skopiuj i wklej ten kod DDL w polu:
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 poczekaj kilka sekund na utworzenie schematu.
Następnie utworzysz 2 modele i skonfigurujesz je do punktów końcowych modelu VertexAI.
Pierwszy model to model wektorów dystrybucyjnych, który służy do generowania wektorów dystrybucyjnych z tekstu, a drugi to model LLM, który służy do generowania odpowiedzi na podstawie danych w usłudze Spanner.
Wklej ten schemat na nową kartę 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 panelu po lewej stronie Spanner Studio powinny się wyświetlać te tabele i modele:

Wczytywanie danych
Teraz musisz wstawić do bazy danych kilka produktów. 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);
Aby wstawić dane, kliknij przycisk run.
Podsumowanie
W tym kroku utworzyliśmy schemat i wczytaliśmy podstawowe dane do bazy danych cymbal-bikes.
Następny krok
Następnie zintegrujesz się z modelem wektorów dystrybucyjnych, aby wygenerować wektory dystrybucyjne dla opisów produktów, a także przekonwertować tekstowe żądanie wyszukiwania na wektor dystrybucyjny, aby wyszukać odpowiednie produkty.
5. Praca z wektorami dystrybucyjnymi
Generowanie wektorów dystrybucyjnych 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.
W przypadku modelu 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;
Aby zaktualizować opisy produktów, kliknij przycisk run.
Korzystanie z wyszukiwania wektorowego
W tym przykładzie podasz żądanie wyszukiwania w języku naturalnym za pomocą zapytania SQL. 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 wygenerowanych 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;
Aby znaleźć podobne produkty, kliknij przycisk run. Wyniki powinny wyglądać tak:

Zwróć uwagę, że w zapytaniu są używane dodatkowe filtry, np. tylko produkty dostępne w magazynie (inventoryCount > 0).
Podsumowanie
W tym kroku utworzyliśmy wektory dystrybucyjne opisów produktów i wektor dystrybucyjny żądania wyszukiwania za pomocą SQL, wykorzystując integrację Spannera z modelami w VertexAI. Przeprowadziliśmy też wyszukiwanie wektorowe, aby znaleźć podobne produkty pasujące do żądania wyszukiwania.
Następne kroki
Następnie użyjemy wyników wyszukiwania, aby przekazać je do modelu LLM i wygenerować niestandardową odpowiedź dla każdego produktu.
6. Praca z modelem LLM
Spanner ułatwia integrację z modelami LLM obsługiwanymi przez VertexAI. Dzięki temu deweloperzy mogą używać SQL do bezpośredniej komunikacji z modelami LLM, zamiast wymagać od aplikacji wykonywania logiki.
Na przykład mamy wyniki poprzedniego zapytania SQL od użytkownika "I'd like to buy a starter bike for my 3 year old child".
Deweloper chce podać odpowiedź dla każdego wyniku, czy produkt jest odpowiedni dla użytkownika, używając tego prompta:
"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"
Oto 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 3-latka ze względu na przedział wiekowy w opisie produktu (2–4 lata). Pozostałe produkty nie są odpowiednie.
Podsumowanie
W tym kroku pracowaliśmy z modelem LLM, aby generować podstawowe odpowiedzi na prompty od użytkownika.
Następne kroki
Następnie dowiesz się, jak używać ANN do skalowania wyszukiwania wektorowego.
7. Skalowanie wyszukiwania wektorowego
W poprzednich przykładach wyszukiwania wektorowego używaliśmy dokładnego wyszukiwania wektorowego KNN. Jest to przydatne, gdy możesz wysyłać zapytania do bardzo konkretnych podzbiorów danych Spannera. Zapytania tego typu są łatwe do podzielenia.
Jeśli nie masz obciążeń, które można łatwo podzielić, i masz dużą ilość danych, możesz użyć wyszukiwania wektorowego ANN z algorytmem ScaNN, aby zwiększyć wydajność wyszukiwania.
Aby to zrobić w usłudze Spanner, musisz wykonać 2 czynności:
- Utworzyć indeks wektorowy.
- Zmodyfikować zapytanie, aby używać funkcji odległości APPROX.
Tworzenie indeksu wektorowego
Aby utworzyć indeks wektorowy w tym zbiorze danych, musimy najpierw zmodyfikować kolumnę productDescriptionEmbeddings, aby zdefiniować długość każdego wektora. Aby dodać długość wektora do kolumny, musisz usunąć oryginalną 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, wykonując krok Generate Vector embedding, który został wcześniej przeprowadzony.
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'
);
Korzystanie z nowego indeksu
Aby używać nowego indeksu wektorowego, musisz nieznacznie zmodyfikować poprzednie zapytanie dotyczące wektorów dystrybucyjnych.
Oto oryginalne 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 wektorowego:
@{force_index=ProductDescriptionEmbeddingIndex} - Zmień wywołanie funkcji
COSINE_DISTANCEnaAPPROX_COSINE_DISTANCE. Pamiętaj, że w ostatecznym zapytaniu poniżej wymagane są też opcje JSON. - Oddzielnie wygeneruj wektory dystrybucyjne za pomocą funkcji ML.PREDICT.
- Skopiuj wyniki wektorów dystrybucyjnych do ostatecznego 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 tym 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;
Powinno to wyglądać mniej więcej tak:

Podsumowanie
W tym kroku przekonwertowaliśmy schemat, aby utworzyć indeks wektorowy. Następnie przepisaliśmy zapytanie dotyczące wektorów dystrybucyjnych, aby przeprowadzić wyszukiwanie ANN za pomocą indeksu wektorowego. Jest to ważny krok, ponieważ wraz ze wzrostem ilości danych trzeba skalować obciążenia wyszukiwania wektorowego.
Następne kroki
Następnie czas na zwalnianie miejsca.
8. Czyszczenie (opcjonalne)
Aby zwolnić miejsce, otwórz sekcję Cloud Spanner w konsoli Cloud i usuń instancję 'retail-demo' utworzoną w ćwiczeniu.

9. Gratulacje!
Gratulacje! Udało Ci się przeprowadzić wyszukiwanie podobieństwa za pomocą wbudowanego wyszukiwania wektorowego Spannera. Dodatkowo zobaczyliśmy, jak łatwo jest pracować z modelami wektorów dystrybucyjnych i LLM, aby udostępniać funkcje generatywnej AI bezpośrednio za pomocą SQL.
Na koniec dowiedzieliśmy się, jak przeprowadzać wyszukiwanie ANN oparte na algorytmie ScaNN w celu skalowania obciążeń wyszukiwania wektorowego.
Co dalej?
Więcej informacji o funkcji dokładnego wyszukiwania najbliższych sąsiadów (KNN) w usłudze Spanner znajdziesz tutaj: https://cloud.google.com/spanner/docs/find-k-nearest-neighbors
Więcej informacji o funkcji przybliżonego wyszukiwania najbliższych sąsiadów (ANN) w usłudze Spanner znajdziesz tutaj: https://cloud.google.com/spanner/docs/find-approximate-nearest-neighbors
Możesz też dowiedzieć się więcej o tym, jak przeprowadzać prognozy online za pomocą SQL przy użyciu integracji Spannera z VertexAI: https://cloud.google.com/spanner/docs/ml
