Ähnlichkeitssuche mit Spanner und Vertex AI

1. Einführung

Dank neuerer Fortschritte beim Deep Learning können Texte und andere Daten so dargestellt werden, dass die semantische Bedeutung erfasst wird. Dies hat zu einem neuen Ansatz für die Suche geführt, der Vektorsuche. Dabei werden Vektordarstellungen von Text (sogenannte Einbettungen) verwendet, um Dokumente zu finden, die für die Suchanfrage eines Nutzers am relevantesten sind. Die Vektorsuche wird gegenüber der herkömmlichen Suche für Anwendungen wie die Bekleidungssuche bevorzugt, bei der Nutzer häufig anhand ihrer Beschreibung, ihres Stils oder ihres Kontexts als nach dem genauen Produkt- oder Markennamen suchen. Wir können die Cloud Spanner-Datenbank in die Vektorsuche einbinden, um einen Abgleich mit Vektorähnlichkeiten durchzuführen. Durch die Kombination von Spanner und Vektorsuche können Kunden eine leistungsstarke Integration erstellen, die die Verfügbarkeit, Zuverlässigkeit und Skalierbarkeit von Spanner mit den erweiterten Funktionen zur Ähnlichkeitssuche von Vertex AI Vector Search kombiniert. Bei dieser Suche werden die Einbettungen von Elementen im Index der Vektorsuche verglichen und die ähnlichsten Übereinstimmungen zurückgegeben.

Anwendungsfall

Stellen Sie sich vor, Sie sind Data Scientist bei einem Modeeinzelhandel und versuchen, mit sich schnell verändernden Trends, Produktsuchen und Empfehlungen Schritt zu halten. Die Herausforderung besteht darin, dass Sie über begrenzte Ressourcen und Datensilos verfügen. In diesem Blogpost wird gezeigt, wie Sie einen Anwendungsfall für Empfehlungen für Bekleidung mithilfe des Ansatzes zur Ähnlichkeitssuche für Bekleidungsdaten implementieren.Dabei werden die folgenden Schritte behandelt:

  1. Datenquelle von Spanner
  2. Vektoren, die mit ML.PREDICT für die Bekleidungsdaten generiert und in Spanner gespeichert wurden
  3. Spanner-Vektordaten mithilfe von Dataflow- und Workflow-Jobs in die Vektorsuche eingebunden
  4. Es wurde eine Vektorsuche durchgeführt, um eine Übereinstimmung für die vom Nutzer eingegebene Eingabe zu finden

Wir werden eine Demo-Webanwendung entwickeln, mit der anhand der Nutzereingabe Text gesucht werden kann. Die Anwendung ermöglicht es Nutzern, nach Bekleidungsartikeln zu suchen, indem sie eine Textbeschreibung eingeben.

Spanner für Vektorsuchindex:

Die Daten für die Bekleidungssuche werden in Spanner gespeichert. Wir rufen die Vertex AI Embeddings API im ML.PREDICT-Konstrukt direkt aus Spanner-Daten auf. Dann nutzen wir die Dataflow- und Workflow-Jobs, mit denen diese Daten (Inventar und Einbettungen) im Bulk in die Vektorsuche von Vertex AI hochgeladen werden, und aktualisieren den Index.

Ausführen von Nutzerabfragen für den Index:

Wenn ein Nutzer eine Beschreibung für ein Kleidungsstück eingibt, generiert die App die Einbettungen in Echtzeit mithilfe der Text Embeddings API. Diese wird dann als Eingabe an die Vector Search API gesendet, um zehn relevante Produktbeschreibungen im Index zu finden und das entsprechende Bild anzuzeigen.

Überblick über die Architektur

Die Architektur der Anwendung „Spanner-Vektorsuche“ ist im folgenden zweiteiligen Diagramm dargestellt:

Spanner-zu-Vektor-Suchindex: a79932a25bee23a4.png

Client-App zum Ausführen von Nutzerabfragen für den Index:

b2b4d5a5715bd4c4.pngDas werden Sie erstellen

Spanner zu Vektorindex:

  • Spanner-Datenbank zum Speichern und Verwalten von Quelldaten und den entsprechenden Einbettungen
  • Ein Workflowjob, mit dem Daten (IDs und Einbettungen) im Bulk in die Vertex AI Vector Search-Datenbank hochgeladen werden.
  • Vector Search API, mit der relevante Produktbeschreibungen im Index gesucht werden

Ausführen von Nutzerabfragen für den Index:

  • Eine Webanwendung, die es Nutzern ermöglicht, Textbeschreibungen für Kleidung einzugeben, eine Ähnlichkeitssuche mit dem bereitgestellten Indexendpunkt durchzuführen und die nächstgelegenen Kleidungsstücke an die Eingabe zurückzugeben.

So gehts

Wenn ein Nutzer eine Beschreibung des Kleidungsstücks eingibt, sendet die Webanwendung die Beschreibung an die Vector Search API. Die Vector Search API sucht dann anhand der Einbettungen der Bekleidungsbeschreibungen im Index die relevantesten Produktbeschreibungen. Die Produktbeschreibungen und die entsprechenden Bilder werden dann den Nutzern angezeigt. Dies ist der allgemeine Workflow:

  1. Generieren Sie Einbettungen für Daten, die in Spanner gespeichert sind.
  2. Exportieren Sie die Einbettungen und laden Sie sie in einen Vektorsuchindex hoch.
  3. Fragen Sie den Vektorsuchindex nach ähnlichen Elementen ab, indem Sie eine Suche nach dem nächsten Nachbarn durchführen.

2. Voraussetzungen

  • Ein Browser wie Chrome oder Firefox
  • Ein Google Cloud-Projekt mit aktivierter Abrechnung

Hinweis

  1. Wählen Sie in der Google Cloud Console auf der Seite für die Projektauswahl ein Google Cloud-Projekt aus oder erstellen Sie eines.
  2. Die Abrechnung für das Cloud-Projekt muss aktiviert sein. Prüfen, ob die Abrechnung für ein Projekt aktiviert ist
  3. Achten Sie darauf, dass alle erforderlichen APIs (Cloud Spanner, Vertex AI, Google Cloud Storage) aktiviert sind
  4. Sie verwenden Cloud Shell, eine in Google Cloud ausgeführte Befehlszeilenumgebung mit vorinstalliertem gcloud. Informationen zu gcloud-Befehlen und deren Verwendung finden Sie in der Dokumentation. Wenn Ihr Projekt noch nicht eingerichtet ist, verwenden Sie den folgenden Befehl, um es festzulegen:
gcloud config set project <YOUR_PROJECT_ID>
  1. Rufen Sie die Seite Cloud Spanner mit Ihrem aktiven Google Cloud-Projekt auf, um zu beginnen

3. Back-End: Spanner-Datenquelle und -Einbettungen erstellen

In diesem Anwendungsfall enthält die Spanner-Datenbank das Bekleidungsinventar mit den entsprechenden Bildern und Beschreibungen. Achten Sie darauf, Einbettungen für die Textbeschreibung zu generieren und in Ihrer Spanner-Datenbank als ARRAY<float64> zu speichern.

  1. Spanner-Daten erstellen

Erstellen Sie eine Instanz mit dem Namen „spanner-vertex“. und eine Datenbank namens „spanner-vertex-embeddings“. Erstellen Sie eine Tabelle mit der 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. Mit INSERT-SQL Daten in die Tabelle einfügen

Einfügeskripts für Beispieldaten finden Sie hier.

  1. Modell mit Texteinbettungen erstellen

Dies ist erforderlich, damit wir Einbettungen für die Inhalte in der Eingabe generieren können. Unten sehen Sie die entsprechende 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. Texteinbettungen für die Quelldaten generieren

Erstellen Sie eine Tabelle zum Speichern der Einbettungen und fügen Sie die generierten Einbettungen ein. In einer realen Datenbankanwendung wäre das Laden der Daten in Spanner bis zu Schritt 2 transaktional. Damit die Best Practices für das Design beibehalten werden, ziehe ich es vor, die Transaktionstabellen normalisiert zu lassen, also eine separate Tabelle für Einbettungen zu erstellen.

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

Nachdem die Bulk-Inhalte und -Einbettungen nun bereit sind, können Sie einen Vektorsuchindex und einen Endpunkt erstellen, um die Einbettungen zu speichern, die für die Vektorsuche benötigt werden.

4. Workflowjob: Export von Spanner-Daten in die Vektorsuche

  1. Cloud Storage-Bucket erstellen

Dies ist erforderlich, um Einbettungen aus Spanner in einem GCS-Bucket im JSON-Format zu speichern, das von der Vektorsuche als Eingabe erwartet wird. Erstellen Sie einen Bucket in derselben Region wie Ihre Daten in Spanner. Erstellen Sie darin bei Bedarf einen Ordner, aber hauptsächlich eine leere Datei namens empty.json.

  1. Cloud Workflow einrichten

So richten Sie einen Batchexport aus Spanner in einen Vertex AI-Vektorsuchindex ein:

Leeren Index erstellen:

Der Vektorsuchindex muss sich in derselben Region wie der Cloud Storage-Bucket und die Daten befinden. Befolgen Sie die 11 Anleitungsschritte auf der Seite „Indexe verwalten“ auf dem Tab „Konsole“ im Abschnitt Index für Batch-Aktualisierung erstellen. Erstellen Sie in dem Ordner, der an contentDeltaUri übergeben wird, eine leere Datei mit dem Namen empty.json, da Sie ohne diese Datei keinen Index erstellen können. Dadurch wird ein leerer Index erstellt.

Wenn Sie bereits einen Index haben, können Sie diesen Schritt überspringen. Der Workflow überschreibt Ihren Index.

Hinweis: Sie können einen leeren Index nicht an einem Endpunkt bereitstellen. Daher verschieben wir den Schritt der Bereitstellung auf einem Endpunkt auf einen späteren Schritt, nachdem wir die Vektordaten nach Cloud Storage exportiert haben.

Git-Repository klonen: Es gibt mehrere Möglichkeiten, ein Git-Repository zu klonen. Eine Möglichkeit besteht darin, den folgenden Befehl über die GitHub-Befehlszeile auszuführen. Führen Sie die beiden folgenden Befehle über das Cloud Shell-Terminal aus:

gh repo clone cloudspannerecosystem/spanner-ai

cd spanner-ai/vertex-vector-search/workflows

Dieser Ordner enthält zwei Dateien

  • batch-export.yaml: Dies ist die Workflowdefinition.
  • sample-batch-input.json: Dies ist ein Beispiel für die Workflow-Eingabeparameter.

input.json über die Beispieldatei einrichten:Kopieren Sie zuerst die Beispiel-JSON-Datei.

cp sample-batch-input.json input.json

Bearbeiten Sie dann input.json mit Details für Ihr Projekt. In diesem Fall sollte Ihre JSON-Datei so aussehen:

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

Einrichtungsberechtigungen

In Produktionsumgebungen empfehlen wir dringend, ein neues Dienstkonto zu erstellen und ihm eine oder mehrere IAM-Rollen zu gewähren, die die Mindestberechtigungen für die Dienstverwaltung enthalten. Die folgenden Rollen sind erforderlich, um den Workflow für den Export von Daten aus Spanner (Einbettungen) in den Index der Vektorsuche einzurichten:

Cloud Workflow-Dienstkonto:

Standardmäßig wird das Compute Engine-Standarddienstkonto verwendet.

Wenn Sie ein manuell konfiguriertes Dienstkonto verwenden, müssen Sie die folgenden Rollen hinzufügen:

Zum Auslösen eines Dataflow-Jobs: Dataflow-Administrator, Dataflow-Worker.

So übernehmen Sie die Identität eines Dataflow-Worker-Dienstkontos: Dienstkontonutzer.

So schreiben Sie Logs: Logautor.

Zum Auslösen der Neuerstellung der Vertex AI-Vektorsuche: Vertex AI-Nutzer.

Dataflow-Worker-Dienstkonto:

Wenn Sie ein manuell konfiguriertes Dienstkonto verwenden, müssen Sie die folgenden Rollen hinzufügen:

So verwalten Sie Dataflow: Dataflow-Administrator, Dataflow-Worker. So lesen Sie Daten aus Spanner: Cloud Spanner-Datenbank-Leser. Schreibzugriff auf die ausgewählte GCS Container Registry: Inhaber von GCS-Storage-Buckets.

  1. Cloud-Workflow bereitstellen

Stellen Sie die YAML-Workflow-Datei in Ihrem Google Cloud-Projekt bereit. Sie können die Region oder den Standort konfigurieren, an dem der Workflow ausgeführt wird.

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"

Der Workflow sollte jetzt auf der Seite „Workflows“ in der Google Cloud Console angezeigt werden.

Hinweis: Sie können den Workflow auch über die Google Cloud Console erstellen und bereitstellen. Folgen Sie der Anleitung in der Cloud Console. Kopieren Sie für die Workflow-Definition den Inhalt der Datei Batch-export.yaml und fügen Sie ihn ein.

Führen Sie anschließend den Workflow aus, damit der Datenexport beginnt.

  1. Cloud-Workflow ausführen

Führen Sie den folgenden Befehl aus, um den Workflow auszuführen:

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

Die Ausführung sollte in Workflows auf dem Tab „Ausführungen“ angezeigt werden. Dadurch sollten Ihre Daten in die Datenbank für die Vektorsuche geladen und indexiert werden.

Hinweis: Sie können die Ausführung auch über die Console mithilfe der Schaltfläche „Ausführen“ ausführen. Folgen Sie der Anleitung und kopieren Sie für die Eingabe den Inhalt der benutzerdefinierten „input.json“-Datei.

5. Vektorsuchindex bereitstellen

Index auf einem Endpunkt bereitstellen

So stellen Sie den Index bereit:

  1. Auf der Seite Indexe der Vektorsuche sollte neben dem Index, den Sie in Schritt 2 des vorherigen Abschnitts erstellt haben, die Schaltfläche BEREITSTELLEN angezeigt werden. Alternativ können Sie die Seite mit den Indexinformationen aufrufen und auf die Schaltfläche DEPLOY TO ENDPOINT (An Endpunkt bereitstellen) klicken.
  2. Geben Sie die erforderlichen Informationen an und stellen Sie den Index an einem Endpunkt bereit.

Alternativ können Sie sich dieses Notebook ansehen, um es auf einem Endpunkt bereitzustellen. (Überspringen Sie diesen Schritt, wenn Sie mit dem Bereitstellungsteil des Notebooks fortfahren möchten.) Notieren Sie sich nach der Bereitstellung die bereitgestellte Index-ID und die Endpunkt-URL.

6. Frontend: Nutzerdaten für die Vektorsuche

Lassen Sie uns eine einfache Python-Anwendung mit einer gradio-fähigen UX erstellen, um unsere Implementierung schnell zu testen: Sie können die Implementierung hier nachlesen, um diese Demo-App in Ihrem eigenen Colab-Notebook zu implementieren.

  1. Wir verwenden das aiplatform Python SDK zum Aufrufen der Embeddings API und zum Aufrufen des Indexendpunkts der Vektorsuche.
# [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. Wir verwenden gradio, um die KI-Anwendung zu demonstrieren, die wir mit einer Benutzeroberfläche schnell und einfach entwickeln. Starten Sie die Laufzeit neu, bevor Sie diesen Schritt implementieren.
!pip install gradio
import gradio as gr
  1. Rufen Sie in der Webanwendung die Embeddings API auf und verwenden Sie das Texteinbettungsmodell: textembedding-gecko@latest

Die folgende Methode ruft das Texteinbettungsmodell auf und gibt die Vektoreinbettungen für den vom Nutzer eingegebenen Text zurück:

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

Testen

text_embedding("red shorts for girls")

Die Ausgabe sollte in etwa so aussehen (das Bild ist auf die Höhe zugeschnitten, sodass Sie nicht die gesamte Vektorantwort sehen können):

5d8355ec04dac1f9.png

  1. Geben Sie die bereitgestellte Index-ID und die Endpunkt-ID an
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. Definieren Sie die Methode der Vektorsuche, um den Indexendpunkt aufzurufen und das Ergebnis mit den zehn nächstgelegenen Übereinstimmungen für die Einbettungsantwort anzuzeigen, die dem eingegebenen Text des Nutzers entspricht.

Beachten Sie, dass in der folgenden Methodendefinition für die Vektorsuche die Methode find_Neighborhoods aufgerufen wird, um die zehn nächstgelegenen Vektoren zu identifizieren.

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

Sie werden auch den Aufruf der Methode spanner_read_data bemerken. Sehen wir uns das im nächsten Schritt an.

  1. Definieren Sie die Implementierung der Spanner-Lesedatenmethode, die die Methode „execute_sql“ aufruft, um die Bilder zu extrahieren, die den IDs der nächsten Nachbarvektoren entsprechen, die aus dem letzten Schritt zurückgegeben wurden.
!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)

Sie sollte die URLs der Bilder zurückgeben, die den ausgewählten Vektoren entsprechen.

  1. Zuletzt kombinieren wir die einzelnen Teile in einer Benutzeroberfläche und lösen die Vektorsuche aus.
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)

Sie sollten das Ergebnis wie unten sehen:

8093b39fbab1a9cc.png

Bild: Link

Das Ergebnisvideo findest du hier.

7. Bereinigen

So vermeiden Sie, dass Ihrem Google Cloud-Konto die in diesem Beitrag verwendeten Ressourcen in Rechnung gestellt werden:

  1. Rufen Sie in der Google Cloud Console die Seite Ressourcen verwalten auf.
  2. Wählen Sie in der Projektliste das Projekt aus, das Sie löschen möchten, und klicken Sie auf „Löschen“.
  3. Geben Sie im Dialogfeld die Projekt-ID ein und klicken Sie auf „Beenden“, um das Projekt zu löschen.
  4. Wenn Sie das Projekt nicht löschen möchten, können Sie die Spanner-Instanz löschen. Rufen Sie dazu die Instanz auf, die Sie gerade für dieses Projekt erstellt haben, und klicken Sie oben rechts auf der Übersichtsseite auf die Schaltfläche DELETE INSTANCE (INSTANZ LÖSCHEN).
  5. Sie können auch zum Index der Vektorsuche gehen, die Bereitstellung des Endpunkts und des Index aufheben und den Index löschen.

8. Fazit

Glückwunsch! Sie haben die Implementierung von Spanner – Vertex Vector Search erfolgreich abgeschlossen:

  1. Spanner-Datenquelle und -Einbettungen für Anwendungen erstellen, die aus der Spanner-Datenbank stammen
  2. Datenbankindex für Vektorsuche wird erstellt.
  3. Einbindung von Vektordaten aus Spanner in die Vektorsuche mithilfe von Dataflow- und Workflow-Jobs.
  4. Index wird auf einem Endpunkt bereitgestellt.
  5. Zum Schluss wird die Vektorsuche für Nutzereingaben in einer Python-gestützten Implementierung des Vertex AI SDKs aufgerufen.

Sie können die Implementierung gerne auf Ihren eigenen Anwendungsfall ausweiten oder mit neuen Funktionen den aktuellen Anwendungsfall improvisieren. Weitere Informationen zu den ML-Funktionen von Spanner