Поиск сходства с помощью Spanner и Vertex AI

1. Введение

Последние достижения в области глубокого обучения позволили представлять текст и другие данные таким образом, чтобы они отражали семантическое значение. Это привело к появлению нового подхода к поиску, называемого векторным поиском, который использует векторные представления текста (известные как встраивания) для поиска документов, наиболее соответствующих запросу пользователя. Векторный поиск предпочтительнее традиционного поиска в таких приложениях, как поиск одежды, где пользователи часто ищут товары по их описанию, стилю или контексту, а не по точным названиям продуктов или брендов. Мы можем интегрировать базу данных Cloud Spanner с векторным поиском для выполнения сопоставления векторов по сходству. Используя Spanner и Vector Search вместе, клиенты могут создать мощную интеграцию, которая сочетает в себе доступность, надежность и масштаб Spanner и расширенные возможности поиска по сходству Vertex AI Vector Search. Этот поиск выполняется путем сравнения вложений элементов в индексе векторного поиска и возврата наиболее похожих совпадений.

Вариант использования

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

  1. Данные взяты из Spanner
  2. Векторы, созданные для данных об одежде с помощью ML.PREDICT и сохраненные в Spanner.
  3. Векторные данные гаечного ключа интегрированы с векторным поиском с использованием потоков данных и заданий рабочего процесса.
  4. Векторный поиск выполняется для поиска совпадений по сходству введенных пользователем данных.

Мы создадим демонстрационное веб-приложение для поиска одежды на основе введенного пользователем текста. Приложение позволяет пользователям искать одежду, вводя текстовое описание.

От гаечного ключа до индекса векторного поиска:

Данные для поиска одежды хранятся в Spanner. Мы будем вызывать API Vertex AI Embeddings в конструкции ML.PREDICT непосредственно из данных Spanner. Затем мы воспользуемся заданиями Dataflow и Workflow, которые массово загружают эти данные (инвентарь и внедрения) в векторный поиск Vertex AI и обновляют индекс.

Выполнение пользовательских запросов по индексу:

Когда пользователь вводит описание одежды, приложение генерирует встраивания в реальном времени с помощью API Text Embeddings. Затем это отправляется в качестве входных данных в API векторного поиска, чтобы найти 10 релевантных описаний продуктов из индекса и отобразить соответствующее изображение.

Обзор архитектуры

Архитектура приложения Spanner-Vector Search показана на следующей схеме, состоящей из двух частей:

От гаечного ключа до индекса векторного поиска: a79932a25bee23a4.png

Клиентское приложение для выполнения пользовательских запросов по индексу:

b2b4d5a5715bd4c4.png Что ты построишь

Ключ к векторному индексу:

  • База данных Spanner для хранения исходных данных и соответствующих вложений и управления ими.
  • Задание рабочего процесса, которое осуществляет массовую загрузку данных (идентификаторов и внедрений) в базу данных Vertex AI Vector Search.
  • API векторного поиска, который используется для поиска соответствующих описаний продуктов в индексе.

Выполнение пользовательских запросов по индексу:

  • Веб-приложение, которое позволяет пользователям вводить текстовые описания одежды, выполняет поиск по сходству с использованием развернутой конечной точки индекса и возвращает на вход ближайшие предметы одежды.

Как это работает

Когда пользователь вводит текстовое описание одежды, веб-приложение отправляет описание в API векторного поиска. Затем API векторного поиска использует встраивания описаний одежды, чтобы найти наиболее релевантные описания продуктов из индекса. Затем пользователю отображаются описания продуктов и соответствующие изображения. Общий порядок работы следующий:

  1. Создавайте внедрения для данных, хранящихся в Spanner.
  2. Экспортируйте и загружайте вложения в индекс векторного поиска.
  3. Запросите индекс векторного поиска на наличие похожих элементов, выполнив поиск ближайшего соседа.

2. Требования

  • Браузер, например Chrome или Firefox.
  • Проект Google Cloud с включенной оплатой

Прежде чем начать

  1. В Google Cloud Console на странице выбора проекта выберите или создайте проект Google Cloud.
  2. Убедитесь, что для вашего облачного проекта включена оплата. Узнайте, как проверить, включена ли оплата в проекте.
  3. Убедитесь, что все необходимые API (Cloud Spanner, Vertex AI, Google Cloud Storage) включены.
  4. Вы будете использовать Cloud Shell , среду командной строки, работающую в Google Cloud, в которую предварительно загружен gcloud. Обратитесь к документации по командам и использованию gcloud. Если ваш проект не установлен, используйте следующую команду, чтобы установить его:
gcloud config set project <YOUR_PROJECT_ID>
  1. Перейдите на страницу Cloud Spanner с активным проектом Google Cloud, чтобы начать работу.

3. Серверная часть: создайте источник данных и встраивания Spanner.

В этом случае в базе данных Spanner хранится инвентарь одежды с соответствующими изображениями и описаниями. Обязательно сгенерируйте вложения для текстового описания и сохраните их в базе данных Spanner как ARRAY<float64>.

  1. Создайте данные гаечного ключа

Создайте экземпляр с именем «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);
  1. Вставьте данные в таблицу с помощью INSERT SQL.

Скрипты вставки примеров данных доступны здесь .

  1. Создайте модель внедрения текста

Это необходимо, чтобы мы могли генерировать внедрения для содержимого на входе. Ниже приведен 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');
  1. Создание текстовых вложений для исходных данных

Создайте таблицу для хранения внедрений и вставьте сгенерированные внедрения. В реальном приложении базы данных загрузка данных в 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. Задание рабочего процесса: экспорт данных гаечного ключа в векторный поиск

  1. Создайте сегмент облачного хранилища

Это необходимо для хранения внедрений из Spanner в сегменте GCS в формате json, который Vector Search ожидает в качестве входных данных. Создайте сегмент в том же регионе, где находятся ваши данные в Spanner. При необходимости создайте внутри папку, но в основном создайте в ней пустой файл с именем пустой.json.

  1. Настройка облачного рабочего процесса

Чтобы настроить пакетный экспорт из Spanner в индекс векторного поиска Vertex AI:

Создайте пустой индекс :

Убедитесь, что индекс векторного поиска находится в том же регионе, что и ваш сегмент облачного хранилища и данные. Следуйте 11 шагам инструкций на вкладке консоли в разделе «Создание индекса для пакетного обновления» на странице управления индексами. В папке, переданной в содержимоеDeltaUri, создайте пустой файл с именем пустой.json, поскольку без этого файла вы не сможете создать индекс. Это создает пустой индекс.

Если у вас уже есть индекс, вы можете пропустить этот шаг. Рабочий процесс перезапишет ваш index.

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

Клонировать этот репозиторий git . Существует несколько способов клонировать репозиторий git. Один из способов — запустить следующую команду с помощью интерфейса командной строки GitHub . Выполните следующие две команды из терминала 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 (встраивания) в индекс векторного поиска:

Учетная запись службы облачных рабочих процессов :

По умолчанию он использует учетную запись службы Compute Engine по умолчанию.

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

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

Чтобы олицетворять учетную запись службы рабочего потока данных: Пользователь учетной записи службы.

Для записи журналов: Logs Writer.

Чтобы запустить перестроение векторного поиска Vertex AI: Пользователь Vertex AI.

Учетная запись службы рабочего потока данных :

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

Для управления потоком данных: администратор потока данных , работник потока данных. Чтобы прочитать данные из Spanner: Cloud Spanner Database Reader. Доступ на запись к выбранному реестру контейнеров GCS: владелец сегмента хранилища GCS.

  1. Развертывание облачного рабочего процесса

Разверните файл 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. Следуйте инструкциям в облачной консоли. Для определения рабочего процесса скопируйте и вставьте содержимое файла Batch-export.yaml.

После завершения выполните рабочий процесс, чтобы начать экспорт данных.

  1. Выполните облачный рабочий процесс

Запустите следующую команду, чтобы выполнить рабочий процесс:

gcloud workflows execute vector-export-workflow --data="$(cat input.json)"

Выполнение должно отображаться на вкладке «Выполнения» в рабочих процессах. Это должно загрузить ваши данные в базу данных Vector Search и проиндексировать их.

Примечание . Вы также можете выполнить команду из консоли, используя кнопку «Выполнить». Следуйте инструкциям и для ввода скопируйте и вставьте содержимое настроенного вами input.json.

5. Развертывание индекса векторного поиска

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

Чтобы развернуть индекс, вы можете выполнить следующие шаги:

  1. На странице индексов векторного поиска вы должны увидеть кнопку РАЗВЕРТЫВАТЬ рядом с индексом, который вы только что создали на шаге 2 предыдущего раздела. Альтернативно вы можете перейти на информационную страницу индекса и нажать кнопку РАЗВЕРТЫВАТЬ НА КОНЕЧНОЙ ТОЧКЕ.
  2. Предоставьте необходимую информацию и разверните индекс в конечной точке.

Альтернативно вы можете просмотреть этот блокнот, чтобы развернуть его на конечной точке (перейдите к части блокнота, посвященной развертыванию). После развертывания запишите идентификатор развернутого индекса и URL-адрес конечной точки.

6. Интерфейс: пользовательские данные для векторного поиска

Давайте создадим простое приложение Python с градиентным пользовательским интерфейсом, чтобы быстро протестировать нашу реализацию: вы можете обратиться к реализации здесь , чтобы реализовать это демонстрационное приложение в своем собственном блокноте Colab .

  1. Мы будем использовать SDK aiplatform python для вызова API Embeddings, а также для вызова конечной точки индекса векторного поиска.
# [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()
  1. Мы будем использовать Gradio, чтобы быстро и легко продемонстрировать приложение AI, которое мы создаем, с пользовательским интерфейсом. Перезапустите среду выполнения, прежде чем выполнять этот шаг.
!pip install gradio
import gradio as gr
  1. Из веб-приложения после ввода пользователя вызовите Embeddings API, мы будем использовать модель внедрения текста: 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")

Вы должны увидеть результат, аналогичный приведенному ниже (обратите внимание, что изображение обрезано по высоте, поэтому вы не можете увидеть весь векторный ответ):

5d8355ec04dac1f9.png

  1. Объявите идентификатор развернутого индекса и идентификатор конечной точки.
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')
  1. Определите метод векторного поиска для вызова конечной точки индекса и отображения результата с 10 ближайшими совпадениями для ответа на внедрение, соответствующего введенному пользователем тексту.

Обратите внимание, что в приведенном ниже определении метода поиска векторов метод 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. Давайте посмотрим на это на следующем этапе.

  1. Определите реализацию метода чтения данных 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-адреса изображений, соответствующих выбранным векторам.

  1. Наконец, давайте соединим все части пользовательского интерфейса и запустим процесс векторного поиска.
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)

Вы должны увидеть результат, как показано ниже:

8093b39fbab1a9cc.png

Изображение: ссылка

Посмотреть видео результата: здесь .

7. Очистка

Чтобы избежать списания средств с вашей учетной записи Google Cloud за ресурсы, используемые в этом посте, выполните следующие действия:

  1. В консоли Google Cloud перейдите на страницу «Управление ресурсами» .
  2. В списке проектов выберите проект, который хотите удалить, и нажмите «Удалить».
  3. В диалоговом окне введите идентификатор проекта, а затем нажмите «Завершить работу», чтобы удалить проект.
  4. Если вы не хотите удалять проект, удалите экземпляр Spanner, перейдя к экземпляру, который вы только что создали для этого проекта, и нажмите кнопку «УДАЛИТЬ ЭКЗЕМПЛЯР» в правом верхнем углу страницы обзора экземпляра.
  5. Вы также можете перейти к индексу векторного поиска, отменить развертывание конечной точки и индекса и удалить индекс.

8. Заключение

Поздравляем! Вы успешно завершили реализацию Spanner — Vertex Vector Search.

  1. Создание источника данных Spanner и внедрений для приложений, полученных из базы данных Spanner.
  2. Создание индекса базы данных векторного поиска.
  3. Интеграция векторных данных из Spanner в векторный поиск с использованием заданий Dataflow и Workflow.
  4. Развертывание индекса в конечной точке.
  5. Наконец, вызов векторного поиска при вводе пользователем данных в реализации Vertex AI sdk на базе Python.

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