Начало работы с векторным поиском гаечного ключа

1. Введение

Spanner — это полностью управляемая, горизонтально масштабируемая, глобально распределенная служба баз данных, которая отлично подходит как для реляционных, так и для нереляционных рабочих нагрузок.

Spanner имеет встроенную поддержку векторного поиска, позволяющую выполнять поиск по сходству или семантический поиск, а также реализовывать расширенную генерацию поиска (RAG) в приложениях GenAI в любом масштабе, используя либо функции точного K-ближайшего соседа (KNN), либо функции приблизительного ближайшего соседа (ANN).

Векторные поисковые запросы Spanner возвращают свежие данные в реальном времени сразу после совершения транзакций, как и любой другой запрос к вашим операционным данным.

В этой лабораторной работе вы пройдете настройку основных функций, необходимых для использования Spanner для выполнения векторного поиска, а также получите доступ к моделям внедрения и LLM из сада моделей VertexAI с помощью SQL.

Архитектура будет выглядеть так:

d179a760add7adc0.png

Опираясь на эту основу, вы узнаете, как создавать векторный индекс на основе алгоритма ScaNN и использовать функции расстояния APPROX, когда ваши семантические рабочие нагрузки необходимо масштабировать.

Что ты построишь

В рамках этой лабораторной работы вы:

  • Создайте экземпляр Spanner
  • Настройте схему базы данных Spanner для интеграции с моделями внедрения и LLM в VertexAI.
  • Загрузите набор розничных данных
  • Выполнение поисковых запросов по сходству к набору данных
  • Предоставьте контекст модели LLM для выработки рекомендаций по конкретному продукту.
  • Измените схему и создайте векторный индекс.
  • Измените запросы, чтобы использовать вновь созданный векторный индекс.

Что вы узнаете

  • Как настроить экземпляр Spanner
  • Как интегрироваться с VertexAI
  • Как использовать Spanner для векторного поиска похожих товаров в наборе данных розничной торговли.
  • Как подготовить базу данных для масштабирования рабочих нагрузок векторного поиска с помощью поиска ИНС.

Что вам понадобится

  • Проект Google Cloud, подключенный к платежному аккаунту.
  • Веб-браузер, например Chrome или Firefox .

2. Настройка и требования

Создать проект

Если у вас еще нет учетной записи Google (Gmail или Google Apps), вам необходимо ее создать . Войдите в консоль Google Cloud Platform ( console.cloud.google.com ) и создайте новый проект.

Если у вас уже есть проект, щелкните раскрывающееся меню выбора проекта в левом верхнем углу консоли:

6c9406d9b014760.png

и нажмите кнопку «НОВЫЙ ПРОЕКТ» в появившемся диалоговом окне, чтобы создать новый проект:

949d83c8a4ee17d9.png

Если у вас еще нет проекта, вы должны увидеть подобное диалоговое окно, чтобы создать свой первый:

870a3cbd6541ee86.png

Последующий диалог создания проекта позволяет вам ввести детали вашего нового проекта:

6a92c57d3250a4b3.png

Запомните идентификатор проекта, который является уникальным именем для всех проектов Google Cloud (имя, указанное выше, уже занято и не подойдет вам, извините!). Позже в этой лаборатории он будет называться PROJECT_ID.

Далее, если вы еще этого не сделали, вам необходимо включить выставление счетов в консоли разработчика, чтобы использовать ресурсы Google Cloud и включить Spanner API .

15d0ef27a8fbab27.png

Выполнение этой кодовой лаборатории не должно стоить вам больше нескольких долларов, но может стоить больше, если вы решите использовать больше ресурсов или оставите их включенными (см. раздел «Очистка» в конце этого документа). Цены на Google Cloud Spanner указаны здесь .

Новые пользователи Google Cloud Platform имеют право на бесплатную пробную версию стоимостью 300 долларов США , что делает эту лабораторию кода совершенно бесплатной.

Настройка Google Cloud Shell

Хотя Google Cloud и Spanner можно управлять удаленно с вашего ноутбука, в этой лаборатории мы будем использовать Google Cloud Shell , среду командной строки, работающую в облаке.

Эта виртуальная машина на базе Debian оснащена всеми необходимыми инструментами разработки. Он предлагает постоянный домашний каталог объемом 5 ГБ и работает в Google Cloud, что значительно повышает производительность сети и аутентификацию. Это означает, что все, что вам понадобится для этой лаборатории кода, — это браузер (да, он работает на Chromebook).

  1. Чтобы активировать Cloud Shell из Cloud Console, просто нажмите «Активировать Cloud Shell». gcLMt5IuEcJJNnMId-Bcz3sxCd0rZn7IzT_r95C8UZeqML68Y1efBG_B0VRp7hc7qiZTLAF-TXD7SsOadxn8uadgHhaLeASnVS3ZHK39eOlKJOgj9SJua_oeGhMxRrbOg3qigddS2A (подготовка и подключение к среде займет всего несколько минут).

JjEuRXGg0AYYIY6QZ8d-66gx_Mtc-_jDE9ijmbXLJSAXFvJt-qUpNtsBsYjNpv2W6BQSrDc1D-ARINNQ-1EkwUhz-iUK-FUCZhJ-NtjviEx9pIkE-246DomWuCfiGHK78DgoeWkHRw

Снимок экрана 14.06.2017, 22.13.43.png

После подключения к Cloud Shell вы увидите, что вы уже прошли аутентификацию и что для проекта уже установлен ваш PROJECT_ID.

gcloud auth list

Вывод команды

Credentialed accounts:
 - <myaccount>@<mydomain>.com (active)
gcloud config list project

Вывод команды

[core]
project = <PROJECT_ID>

Если по какой-то причине проект не установлен, просто введите следующую команду:

gcloud config set project <PROJECT_ID>

Ищете свой PROJECT_ID ? Узнайте, какой идентификатор вы использовали на этапах настройки, или найдите его на панели управления Cloud Console:

158fNPfwSxsFqz9YbtJVZes8viTS3d1bV4CVhij3XPxuzVFOtTObnwsphlm6lYGmgdMFwBJtc-FaLrZU7XHAg_ZYoCrgombMRR3h-eolLPcvO351c5iBv506B3ZwghZoiRg6cz23Qw

Cloud Shell также по умолчанию устанавливает некоторые переменные среды, которые могут быть полезны при выполнении будущих команд.

echo $GOOGLE_CLOUD_PROJECT

Вывод команды

<PROJECT_ID>

Включить API-интерфейс Spanner

gcloud services enable spanner.googleapis.com

Краткое содержание

На этом этапе вы настроили свой проект, если у вас его еще не было, активировали облачную оболочку и включили необходимые API.

Дальше

Далее вы настроите экземпляр и базу данных Spanner.

3. Создайте экземпляр Spanner и базу данных.

Создайте экземпляр Spanner

На этом этапе мы настраиваем наш экземпляр Spanner для лаборатории кода. Для этого откройте Cloud Shell и выполните следующую команду:

export SPANNER_INSTANCE_ID=retail-demo
gcloud spanner instances create $SPANNER_INSTANCE_ID \
--config=regional-us-central1 \
--description="spanner AI retail demo" \
--nodes=1

Вывод команды:

$ gcloud spanner instances create $SPANNER_INSTANCE_ID \
--config=regional-us-central1 \
--description="spanner AI retail demo" \
--nodes=1
Creating instance...done.  

Создать базу данных

После запуска экземпляра вы можете создать базу данных. Spanner позволяет использовать несколько баз данных в одном экземпляре.

База данных — это место, где вы определяете свою схему. Вы также можете контролировать, кто имеет доступ к базе данных, настраивать собственное шифрование, настраивать оптимизатор и устанавливать период хранения.

Чтобы создать базу данных, снова используйте инструмент командной строки gcloud:

export SPANNER_DATABASE=cymbal-bikes
gcloud spanner databases create $SPANNER_DATABASE \
 --instance=$SPANNER_INSTANCE_ID

Вывод команды:

$ gcloud spanner databases create $SPANNER_DATABASE \
 --instance=$SPANNER_INSTANCE_ID
Creating database...done.

Краткое содержание

На этом этапе вы создали экземпляр и базу данных Spanner.

Дальше

Далее вы настроите схему и данные Spanner.

4. Загрузите схему и данные Cymbal.

Создайте схему Cymbal

Чтобы настроить схему, перейдите в Spanner Studio:

3e1a0fed928b33cf.png

Схема состоит из двух частей. Сначала вы хотите добавить таблицу products . Скопируйте и вставьте это утверждение в пустую вкладку.

Для схемы скопируйте и вставьте этот DDL в поле:

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);

Затем нажмите кнопку run и подождите несколько секунд, пока схема будет создана.

Далее вы создадите две модели и настроите их для конечных точек модели VertexAI.

Первая модель — это модель внедрения, которая используется для создания внедрений из текста, а вторая — это модель LLM, используемая для генерации ответов на основе данных в Spanner.

Вставьте следующую схему в новую вкладку в 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
);

Затем нажмите кнопку run и подождите несколько секунд, пока модели будут созданы.

На левой панели Spanner Studio вы должны увидеть следующие таблицы и модели:

62455aa4b0e839d9.png

Загрузите данные

Теперь вам нужно добавить несколько продуктов в вашу базу данных. Откройте новую вкладку в Spanner Studio, затем скопируйте и вставьте следующие операторы вставки:

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);

Нажмите кнопку run , чтобы вставить данные.

Краткое содержание

На этом этапе вы создали схему и загрузили некоторые основные данные в базу данных cymbal-bikes .

Дальше

Далее вы выполните интеграцию с моделью внедрения для создания внедрений для описаний продуктов, а также преобразуете текстовый поисковый запрос во внедрение для поиска соответствующих продуктов.

5. Работа с вложениями

Создание векторных вложений для описаний продуктов

Чтобы поиск по сходству работал над продуктами, вам необходимо создать вложения для описаний продуктов.

Поскольку в схеме создана EmbeddingsModel , это простой оператор UPDATE DML.

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;

Нажмите кнопку run , чтобы обновить описания продуктов.

В этом примере вы предоставите запрос на поиск на естественном языке с помощью запроса SQL. Этот запрос превратит поисковый запрос во встраивание, а затем выполнит поиск похожих результатов на основе сохраненных вложений описаний продуктов, созданных на предыдущем шаге.

-- 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;

Нажмите кнопку run , чтобы найти похожие продукты. Результаты должны выглядеть следующим образом:

672e111753077fcf.png

Обратите внимание, что в запросе используются дополнительные фильтры, например, интересуются только теми продуктами, которые есть в наличии ( inventoryCount > 0 ).

Краткое содержание

На этом этапе вы создали встраивание описания продукта и встраивание поискового запроса с помощью SQL, используя интеграцию Spanner с моделями в VertexAI. Вы также выполнили векторный поиск, чтобы найти похожие продукты, соответствующие поисковому запросу.

Следующие шаги

Далее давайте воспользуемся результатами поиска, чтобы передать их в LLM и сгенерировать индивидуальный ответ для каждого продукта.

6. Работа с LLM

Spanner упрощает интеграцию с моделями LLM, предоставляемыми VertexAI. Это позволяет разработчикам использовать SQL для прямого взаимодействия с LLM, не требуя от приложения выполнения логики.

Например, у нас есть результаты предыдущего SQL-запроса пользователя "I'd like to buy a starter bike for my 3 year old child".

Для каждого результата разработчик хотел бы предоставить ответ о том, подходит ли продукт пользователю, используя следующую подсказку:

"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"

Вот запрос, который вы можете использовать:

-- 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)
);

Нажмите кнопку run », чтобы отправить запрос. Результаты должны выглядеть следующим образом:

35878cd0f88f1470.png

Первый продукт подходит для 3-летнего ребенка, поскольку возрастной диапазон указан в описании продукта (2–4 года). Остальные продукты не очень подходят.

Краткое содержание

На этом этапе вы работали с LLM, чтобы генерировать базовые ответы на запросы пользователя.

Следующие шаги

Далее давайте научимся использовать ИНС для масштабирования векторного поиска.

7. Масштабирование векторного поиска

В предыдущих примерах векторного поиска использовался точный векторный поиск KNN. Это здорово, когда вы можете запрашивать очень конкретные подмножества данных вашего Spanner. Говорят, что такие типы запросов имеют высокую степень секционируемости .

Если у вас нет рабочих нагрузок с высокой степенью разделения и у вас большой объем данных, вам нужно будет использовать векторный поиск ANN с использованием алгоритма ScaNN для повышения производительности поиска.

Чтобы сделать это в Spanner, вам нужно будет сделать две вещи:

  • Создайте векторный индекс
  • Измените свой запрос, чтобы использовать функции расстояния APPROX .

Создайте векторный индекс

Чтобы создать векторный индекс для этого набора данных, нам сначала нужно изменить столбец productDescriptionEmbeddings , чтобы определить длину каждого вектора. Чтобы добавить длину вектора в столбец, необходимо удалить исходный столбец и создать его заново.

ALTER TABLE `products` DROP COLUMN `productDescriptionEmbedding`;
ALTER TABLE
  `products` ADD COLUMN `productDescriptionEmbedding` ARRAY<FLOAT32>(vector_length=>768);

Затем снова создайте внедрения из шага 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;

После создания столбца создайте индекс:

CREATE VECTOR INDEX ProductDescriptionEmbeddingIndex
    ON products(productDescriptionEmbedding)
    WHERE productDescriptionEmbedding IS NOT NULL
OPTIONS (
 distance_type = 'COSINE'
);

Используйте новый индекс

Чтобы использовать новый векторный индекс, вам придется немного изменить предыдущий запрос на внедрение.

Вот исходный запрос:

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;

Вам придется внести следующие изменения:

  • Используйте подсказку для нового индекса вектора: @{force_index=ProductDescriptionEmbeddingIndex}
  • Измените вызов функции COSINE_DISTANCE на APPROX_COSINE_DISTANCE . Обратите внимание, что параметры JSON в последнем запросе ниже также необходимы.
  • Сгенерируйте внедрения из функции ML.PREDICT отдельно.
  • Скопируйте результаты вложений в окончательный запрос.

Создайте вложения

-- 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)
  )
)

Выделите результаты запроса и скопируйте их.

1b43c5ae4ef9ab68.png

Затем замените <VECTOR> в следующем запросе, вставив скопированные вами внедрения.

-- 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;

Это должно выглядеть примерно так:

12397107ec49c491.png

Краткое содержание

На этом этапе вы преобразовали свою схему для создания векторного индекса. А затем вы переписали запрос на внедрение, чтобы выполнить поиск ИНС с использованием векторного индекса. Это важный шаг, поскольку ваши данные растут для масштабирования рабочих нагрузок векторного поиска.

Следующие шаги

Далее пришло время навести порядок!

8. Уборка (по желанию)

Чтобы выполнить очистку, просто зайдите в раздел Cloud Spanner облачной консоли и удалите экземпляр « retail-demo » , который мы создали в лаборатории кода.

41cbc1a84b3588d5.png

9. Поздравляем!

Поздравляем, вы успешно выполнили поиск по сходству, используя встроенный векторный поиск Spanner. Кроме того, вы увидели, насколько легко работать с моделями внедрения и LLM, чтобы обеспечить генеративные функции ИИ непосредственно с помощью SQL.

Наконец, вы изучили процесс выполнения поиска ИНС на основе алгоритма ScaNN для масштабирования рабочих нагрузок векторного поиска.

Что дальше?

Узнайте больше о функции точного ближайшего соседа Spanner (поиск векторов KNN) здесь: https://cloud.google.com/spanner/docs/find-k-nearest-neighbors

Узнайте больше о функции приблизительного ближайшего соседа Spanner (векторный поиск ANN) здесь: https://cloud.google.com/spanner/docs/find-approximate-nearest-neighbors

Вы также можете узнать больше о том, как выполнять онлайн-прогнозы с помощью SQL с использованием интеграции VertexAI от Spanner здесь: https://cloud.google.com/spanner/docs/ml