1. Введение
Последние достижения в области глубокого обучения позволили представлять текст и другие данные таким образом, чтобы они передавали семантическое значение. Это привело к появлению нового подхода к поиску, называемого векторным поиском, который использует векторные представления текста (известные как эмбеддинги) для поиска документов, наиболее релевантных запросу пользователя. Векторный поиск предпочтительнее традиционного поиска в таких приложениях, как поиск одежды, где пользователи часто ищут товары по их описанию, стилю или контексту, а не по точным названиям товаров или брендов. Мы можем интегрировать базу данных Cloud Spanner с векторным поиском для выполнения векторного сопоставления по сходству. Используя Spanner и векторный поиск вместе, клиенты могут создать мощную интеграцию, которая сочетает в себе доступность, надежность и масштабируемость Spanner и расширенные возможности поиска по сходству векторного поиска Vertex AI. Этот поиск выполняется путем сравнения эмбеддингов элементов в индексе векторного поиска и возврата наиболее похожих совпадений.
Вариант использования
Представьте, что вы — специалист по анализу данных в компании, занимающейся розничной продажей модной одежды, и пытаетесь угнаться за быстро меняющимися тенденциями, поисковыми запросами и рекомендациями товаров. Проблема в том, что у вас ограниченные ресурсы и разрозненные хранилища данных. В этой статье показано, как реализовать сценарий рекомендаций одежды с использованием подхода поиска по сходству на основе данных об одежде. Рассматриваются следующие шаги:
- Данные получены от компании Spanner.
- Векторы, сгенерированные для данных об одежде с помощью ML.PREDICT и сохраненные в Spanner.
- Интеграция векторных данных Spanner с векторным поиском с использованием потоков данных и заданий рабочих процессов.
- Для поиска сходства между введенными пользователем данными был выполнен векторный поиск.
Мы разработаем демонстрационное веб-приложение для поиска одежды на основе текстового ввода пользователя. Приложение позволит пользователям искать одежду, вводя текстовое описание.
Кроссворд для векторного поиска по индексу:
Данные для поиска одежды хранятся в Spanner. Мы будем вызывать API Vertex AI Embeddings непосредственно из данных Spanner в конструкции ML.PREDICT. Затем мы воспользуемся заданиями Dataflow и Workflow, которые будут массово загружать эти данные (инвентарь и эмбеддинги) в векторный поиск Vertex AI и обновлять индекс.
Выполнение пользовательских запросов к индексу:
Когда пользователь вводит описание одежды, приложение в режиме реального времени генерирует векторные представления (embeddings) с помощью API текстовых векторных представлений. Затем эти данные отправляются в качестве входных данных в API векторного поиска, где находится 10 релевантных описаний товаров в индексе, после чего отображается соответствующее изображение.
Обзор архитектуры
Архитектура приложения Spanner-Vector Search представлена на следующей двухчастной диаграмме:
Кроссворд для векторного поиска по индексу: 
Клиентское приложение для выполнения пользовательских запросов к индексу:
Что вы построите
Гаечный ключ к векторному индексу:
- База данных Spanner для хранения и управления исходными данными и соответствующими векторными представлениями.
- Задача рабочего процесса, которая выполняет массовую загрузку данных (идентификаторов и векторных представлений) в базу данных векторного поиска Vertex AI.
- API векторного поиска, используемый для поиска релевантных описаний товаров в индексе.
Выполнение пользовательских запросов к индексу:
- Веб-приложение, позволяющее пользователям вводить текстовые описания одежды, выполняющее поиск сходства с использованием развернутой индексной конечной точки и возвращающее наиболее близкие по описанию предметы одежды.
Как это работает
Когда пользователь вводит текстовое описание одежды, веб-приложение отправляет это описание в API векторного поиска. Затем API векторного поиска использует векторные представления описаний одежды для поиска наиболее релевантных описаний товаров в индексе. После этого пользователю отображаются описания товаров и соответствующие изображения. Общий рабочий процесс выглядит следующим образом:
- Сгенерировать векторные представления для данных, хранящихся в Spanner.
- Экспорт и загрузка векторных представлений в индекс векторного поиска.
- Для поиска похожих элементов в векторном поисковом индексе выполните поиск по ближайшему соседу.
2. Требования
Прежде чем начать
- В консоли Google Cloud на странице выбора проекта выберите или создайте проект Google Cloud.
- Убедитесь, что для вашего облачного проекта включена функция выставления счетов. Узнайте, как проверить, включена ли функция выставления счетов для проекта.
- Убедитесь, что все необходимые API (Cloud Spanner, Vertex AI, Google Cloud Storage) включены .
- Вы будете использовать Cloud Shell — среду командной строки, работающую в Google Cloud и поставляемую с предустановленным gcloud. Для получения информации о командах и использовании gcloud обратитесь к документации . Если ваш проект не задан, используйте следующую команду для его настройки:
gcloud config set project <YOUR_PROJECT_ID>
- Для начала перейдите на страницу Cloud Spanner с вашим активным проектом Google Cloud.
3. Бэкенд: Создайте источник данных Spanner и встраивания.
В данном случае база данных Spanner хранит информацию об ассортименте одежды с соответствующими изображениями и описаниями. Убедитесь, что вы сгенерировали векторные представления для текстового описания и сохранили их в базе данных Spanner в виде массива ARRAY<float64>.
- Создайте данные для гаечного ключа.
Создайте экземпляр с именем "spanner-vertex" и базу данных с именем "spanner-vertex-embeddings". Создайте таблицу, используя DDL:
CREATE TABLE
apparels ( id NUMERIC,
category STRING(100),
sub_category STRING(50),
uri STRING(200),
content STRING(2000),
embedding ARRAY<FLOAT64>
)
PRIMARY KEY
(id);
- Вставьте данные в таблицу, используя SQL-запрос INSERT.
Здесь доступны скрипты для вставки примеров данных.
- Создание модели векторных представлений текста
Это необходимо для генерации эмбеддингов для содержимого входных данных. Ниже приведен DDL-код для этой задачи:
CREATE MODEL text_embeddings INPUT(content STRING(MAX))
OUTPUT(
embeddings
STRUCT<
statistics STRUCT<truncated BOOL, token_count FLOAT64>,
values ARRAY<FLOAT64>>
)
REMOTE OPTIONS (
endpoint = '//aiplatform.googleapis.com/projects/abis-345004/locations/us-central1/publishers/google/models/textembedding-gecko');
- Сгенерировать текстовые векторные представления для исходных данных.
Создайте таблицу для хранения эмбеддингов и вставьте сгенерированные эмбеддинги. В реальном приложении для работы с базами данных загрузка данных в Spanner до шага 2 будет транзакционной. Для соблюдения лучших практик проектирования я предпочитаю сохранять транзакционные таблицы нормализованными , поэтому создаю отдельную таблицу для эмбеддингов.
CREATE TABLE apparels_embeddings (id string(100), embedding ARRAY<FLOAT64>)
PRIMARY KEY (id);
INSERT INTO apparels_embeddings(id, embeddings)
SELECT CAST(id as string), embeddings.values
FROM ML.PREDICT(
MODEL text_embeddings,
(SELECT id, content from apparels)
) ;
Теперь, когда основная часть контента и векторные представления готовы, давайте создадим индекс и конечную точку векторного поиска для хранения векторных представлений, которые помогут выполнить векторный поиск.
4. Задание рабочего процесса: Экспорт данных Spanner в Vector Search.
- Создайте корзину облачного хранилища.
Это необходимо для хранения эмбеддингов из Spanner в хранилище GCS в формате JSON, который Vector Search ожидает в качестве входных данных. Создайте хранилище в том же регионе, что и ваши данные в Spanner. При необходимости создайте внутри него папку, но в основном создайте в ней пустой файл с именем empty.json.
- Настройка облачного рабочего процесса
Чтобы настроить пакетный экспорт из Spanner в индекс векторного поиска Vertex AI:
Создайте пустой индекс :
Убедитесь, что векторный поисковый индекс находится в том же регионе, что и ваш сегмент облачного хранилища и данные. Следуйте инструкциям из 11 шагов на вкладке «Консоль» в разделе «Создание индекса для пакетного обновления» на странице управления индексами. В папке, передаваемой в contentsDeltaUri, создайте пустой файл с именем empty.json, поскольку без этого файла вы не сможете создать индекс. Это создаст пустой индекс.
Если у вас уже есть индекс, вы можете пропустить этот шаг. В ходе рабочего процесса ваш индекс будет перезаписан.
Примечание : Вы не можете развернуть пустой индекс на конечной точке. Поэтому мы откладываем этап его развертывания на конечной точке на более поздний этап, после экспорта векторных данных в Cloud Storage.
Клонирование этого репозитория Git : Существует несколько способов клонирования репозитория Git, один из них — выполнить следующую команду с помощью CLI GitHub . Выполните следующие 2 команды в терминале Cloud Shell:
gh repo clone cloudspannerecosystem/spanner-ai
cd spanner-ai/vertex-vector-search/workflows
Эта папка содержит два файла.
-
batch-export.yaml: Это определение рабочего процесса. -
sample-batch-input.json: Это пример входных параметров рабочего процесса.
Настройка файла input.json из примера: Сначала скопируйте пример файла json.
cp sample-batch-input.json input.json
Затем отредактируйте input.json , указав данные вашего проекта. В этом случае ваш JSON должен выглядеть следующим образом:
{
"project_id": "<<YOUR_PROJECT>>",
"location": "<<us-central1>>",
"dataflow": {
"temp_location": "gs://<<YOUR_BUCKET>>/<<FOLDER_IF_ANY>>/workflow_temp"
},
"gcs": {
"output_folder": "gs://<<YOUR_BUCKET>>/<<FOLDER_IF_ANY>>/workflow_output"
},
"spanner": {
"instance_id": "spanner-vertex",
"database_id": "spanner-vertex-embeddings",
"table_name": "apparels_embeddings",
"columns_to_export": "embedding,id"
},
"vertex": {
"vector_search_index_id": "<<YOUR_INDEX_ID>>"
}
}
Настройка прав доступа
Для производственных сред мы настоятельно рекомендуем создать новую учетную запись службы и предоставить ей одну или несколько ролей IAM, содержащих минимально необходимые разрешения для управления службой. Для настройки рабочего процесса экспорта данных из Spanner (встраивания) в индекс Vector Search необходимы следующие роли:
Учетная запись службы облачных рабочих процессов :
По умолчанию используется учетная запись службы Compute Engine по умолчанию.
Если вы используете учетную запись службы, настроенную вручную, необходимо включить следующие роли:
Чтобы запустить задание потока данных: Администрирование потока данных, Рабочий процесс потока данных.
Для имитации учетной записи службы обработчика потока данных: Пользователь учетной записи службы.
Для записи логов: Logs Writer.
Для запуска перестроения векторного поиска Vertex AI: Пользователь Vertex AI.
Учетная запись службы Dataflow Worker :
Если вы используете учетную запись службы, настроенную вручную, необходимо включить следующие роли:
Для управления потоком данных: Dataflow Admin , Dataflow Worker. Для чтения данных из Spanner: Cloud Spanner Database Reader. Права на запись в выбранный реестр контейнеров GCS: GCS Storage Bucket Owner.
- Разверните облачный рабочий процесс.
Разверните YAML-файл рабочего процесса в свой проект Google Cloud. Вы можете настроить регион или местоположение, где будет выполняться рабочий процесс.
gcloud workflows deploy vector-export-workflow --source=batch-export.yaml --location="us-central1" [--service account=<service_account>]
or
gcloud workflows deploy vector-export-workflow --source=batch-export.yaml --location="us-central1"
Теперь рабочий процесс должен отображаться на странице «Рабочие процессы» в консоли Google Cloud.
Примечание : Вы также можете создать и развернуть рабочий процесс из консоли Google Cloud. Следуйте подсказкам в консоли Cloud. Для определения рабочего процесса скопируйте и вставьте содержимое файла batch-export.yaml.
После завершения этого процесса запустите рабочий процесс, чтобы начать экспорт данных.
- Запустите облачный рабочий процесс.
Для выполнения рабочего процесса выполните следующую команду:
gcloud workflows execute vector-export-workflow --data="$(cat input.json)"
Результат выполнения должен отобразиться на вкладке «Выполнения» в разделе «Рабочие процессы». Это позволит загрузить ваши данные в базу данных Vector Search и проиндексировать их.
Примечание : Вы также можете выполнить команду из консоли, используя кнопку «Выполнить». Следуйте подсказкам, а в качестве входных данных скопируйте и вставьте содержимое вашего пользовательского файла input.json.
5. Развернуть векторный поисковый индекс.
Разверните индекс на конечной точке
Для развертывания индекса выполните следующие действия:
- На странице индексов векторного поиска вы должны увидеть кнопку «РАЗВЕРНУТЬ» рядом с индексом, который вы только что создали на шаге 2 предыдущего раздела. В качестве альтернативы вы можете перейти на страницу информации об индексе и нажать кнопку «РАЗВЕРНУТЬ НА КОНЕЧНУЮ ТОЧКУ».
- Предоставьте необходимую информацию и разверните индекс на конечной точке.
В качестве альтернативы вы можете использовать этот блокнот для развертывания на конечной точке (перейдите к разделу развертывания в блокноте). После развертывания запишите идентификатор развернутого индекса и URL-адрес конечной точки.
6. Фронтенд: Преобразование пользовательских данных в векторный поиск.
Давайте создадим простое приложение на Python с пользовательским интерфейсом на основе Gradio, чтобы быстро протестировать нашу реализацию: вы можете обратиться к реализации здесь, чтобы создать это демонстрационное приложение в своем блокноте Colab .
- Мы будем использовать Python SDK от aiplatform для вызова API Embeddings, а также для вызова конечной точки индекса Vector Search.
# [START aiplatform_sdk_embedding]
!pip install google-cloud-aiplatform==1.35.0 --upgrade --quiet --user
import vertexai
vertexai.init(project=PROJECT_ID, location="us-central1")
from vertexai.language_models import TextEmbeddingModel
import sys
if "google.colab" in sys.modules:
# Define project information
PROJECT_ID = " " # Your project id
LOCATION = " " # Your location
# Authenticate user to Google Cloud
from google.colab import auth
auth.authenticate_user()
- Мы будем использовать Gradio для быстрой и простой демонстрации разрабатываемого нами приложения с искусственным интеллектом и пользовательским интерфейсом. Перед выполнением этого шага перезапустите среду выполнения.
!pip install gradio
import gradio as gr
- В веб-приложении при вводе пользователем данных вызывается API Embeddings, мы будем использовать модель встраивания текста: textembedding-gecko@latest
Приведённый ниже метод вызывает модель векторного представления текста и возвращает векторные представления текста, введённого пользователем:
def text_embedding(content) -> list:
"""Text embedding with a Large Language Model."""
model = TextEmbeddingModel.from_pretrained("textembedding-gecko@latest")
embeddings = model.get_embeddings(content)
for embedding in embeddings:
vector = embedding.values
#print(f"Length of Embedding Vector: {len(vector)}")
return vector
Проверьте это
text_embedding("red shorts for girls")
В результате вы должны увидеть изображение, похожее на приведенное ниже (обратите внимание, что изображение обрезано по высоте, поэтому вы не можете увидеть весь вектор ответа):

- Укажите идентификатор развернутого индекса и идентификатор конечной точки.
from google.cloud import aiplatform
DEPLOYED_INDEX_ID = "spanner_vector1_1702366982123"
#Vector Search Endpoint
index_endpoint = aiplatform.MatchingEngineIndexEndpoint('projects/273845608377/locations/us-central1/indexEndpoints/2021628049526620160')
- Определите метод векторного поиска для вызова конечной точки индекса и отображения результата с 10 ближайшими совпадениями для ответа встраивания, соответствующего тексту, введенному пользователем.
В приведенном ниже определении метода Vector Search обратите внимание, что метод find_neighbors вызывается для определения 10 ближайших векторов.
def vector_search(content) -> list:
result = text_embedding(content)
#call_vector_search_api(content)
index_endpoint = aiplatform.MatchingEngineIndexEndpoint('projects/273845608377/locations/us-central1/indexEndpoints/2021628049526620160')
# run query
response = index_endpoint.find_neighbors(
deployed_index_id = DEPLOYED_INDEX_ID,
queries = [result],
num_neighbors = 10
)
out = []
# show the results
for idx, neighbor in enumerate(response[0]):
print(f"{neighbor.distance:.2f} {spanner_read_data(neighbor.id)}")
out.append(f"{spanner_read_data(neighbor.id)}")
return out
Вы также заметите вызов метода spanner_read_data. Давайте рассмотрим его на следующем шаге.
- Определите реализацию метода чтения данных Spanner, который вызывает метод execute_sql для извлечения изображений, соответствующих идентификаторам векторов ближайших соседей, возвращенных на предыдущем шаге.
!pip install google-cloud-spanner==3.36.0
from google.cloud import spanner
instance_id = "spanner-vertex"
database_id = "spanner-vertex-embeddings"
projectId = PROJECT_ID
client = spanner.Client()
client.project = projectId
instance = client.instance(instance_id)
database = instance.database(database_id)
def spanner_read_data(id):
query = "SELECT uri FROM apparels where id = " + id
outputs = []
with database.snapshot() as snapshot:
results = snapshot.execute_sql(query)
for row in results:
#print(row)
#output = "ID: {}, CONTENT: {}, URI: {}".format(*row)
output = "{}".format(*row)
outputs.append(output)
return "\n".join(outputs)
Функция должна возвращать URL-адреса изображений, соответствующих выбранным векторам.
- Наконец, давайте соберем все элементы воедино в пользовательском интерфейсе и запустим процесс векторного поиска.
from PIL import Image
def call_search(query):
response = vector_search(query)
return response
input_text = gr.Textbox(label="Enter your query. Examples: Girls Tops White Casual, Green t-shirt girls, jeans shorts, denim skirt etc.")
output_texts = [gr.Image(label="") for i in range(10)]
demo = gr.Interface(fn=call_search, inputs=input_text, outputs=output_texts, live=True)
resp = demo.launch(share = True)
Результат должен выглядеть так, как показано ниже:

Изображение: Ссылка
Посмотреть видео с результатами можно здесь .
7. Уборка
Чтобы избежать списания средств с вашего аккаунта Google Cloud за ресурсы, использованные в этой статье, выполните следующие действия:
- В консоли Google Cloud перейдите на страницу «Управление ресурсами» .
- В списке проектов выберите проект, который хотите удалить, и нажмите кнопку «Удалить».
- В диалоговом окне введите идентификатор проекта, а затем нажмите «Завершить», чтобы удалить проект.
- Если вы не хотите удалять проект, удалите экземпляр Spanner, перейдя к только что созданному для этого проекта экземпляру и нажав кнопку «УДАЛИТЬ ЭКЗЕМПЛЯР» в правом верхнем углу страницы обзора экземпляра.
- Вы также можете перейти к индексу Vector Search, удалить конечную точку и индекс, а также удалить индекс.
8. Заключение
Поздравляем! Вы успешно завершили реализацию алгоритма Spanner - Vertex Vector Search.
- Создание источника данных Spanner и встраивания данных для приложений, использующих базу данных Spanner.
- Создание индекса базы данных Vector Search.
- Интеграция векторных данных из Spanner в Vector Search с использованием заданий Dataflow и Workflow.
- Развертывание индекса на конечной точке.
- Наконец, в реализации SDK Vertex AI на основе Python реализован алгоритм векторного поиска по пользовательскому вводу.
Вы можете свободно расширить реализацию под свои собственные задачи или дополнить существующие функции новыми возможностями. Подробнее о возможностях машинного обучения Spanner можно узнать здесь .