Spanner 및 Vertex AI를 사용한 유사성 검색

1. 소개

최근 딥 러닝의 발전으로 텍스트 및 기타 데이터를 의미론적 의미를 캡처하는 방식으로 표현할 수 있게 되었습니다. 이로 인해 벡터 검색이라는 새로운 검색 접근 방식이 탄생했습니다. 벡터 검색은 임베딩이라고 하는 텍스트의 벡터 표현을 사용하여 사용자의 검색어와 가장 관련성이 높은 문서를 찾습니다. 벡터 검색은 의류 검색과 같은 기존의 애플리케이션 검색보다 선호됩니다. 의류 검색에서는 사용자가 정확한 제품 또는 브랜드 이름보다는 설명, 스타일 또는 컨텍스트로 상품을 검색하는 경우가 많습니다. Cloud Spanner 데이터베이스를 벡터 검색과 통합하여 벡터 유사성 일치를 수행할 수 있습니다. Spanner와 벡터 검색을 함께 사용함으로써 고객은 Spanner의 가용성, 안정성, 확장성과 Vertex AI 벡터 검색의 고급 유사성 검색 기능을 결합한 강력한 통합을 구축할 수 있습니다. 이 검색은 벡터 검색 색인에 있는 항목의 임베딩을 비교하고 가장 유사한 일치 항목을 반환하는 방식으로 수행됩니다.

사용 사례

여러분이 패션 소매업체의 데이터 과학자로서 급변하는 트렌드, 제품 검색, 추천을 따라잡으려 한다고 가정해 보겠습니다. 문제는 제한된 리소스와 데이터 사일로가 있다는 것입니다. 이 블로그 게시물에서는 의류 데이터에 유사성 검색 접근 방식을 사용하여 의류 추천 사용 사례를 구현하는 방법을 설명합니다. 다음 단계를 다룹니다.

  1. Spanner에서 가져온 데이터
  2. ML.PREDICT를 사용하여 의류 데이터에 대해 생성되고 Spanner에 저장된 벡터
  3. Dataflow 및 워크플로 작업을 사용하여 벡터 검색과 통합된 Spanner 벡터 데이터
  4. 사용자가 입력한 입력에 대한 유사성 일치를 찾기 위해 벡터 검색이 수행됨

사용자 입력 텍스트를 기반으로 의류 검색을 수행하는 데모 웹 애플리케이션을 빌드합니다. 이 애플리케이션을 통해 사용자는 텍스트 설명을 입력하여 의류를 검색할 수 있습니다.

Spanner-벡터 검색 색인:

의류 검색을 위한 데이터는 Spanner에 저장됩니다. ML.PREDICT 구성의 Vertex AI Embeddings API를 Spanner 데이터에서 직접 호출합니다. 그런 다음 이 데이터 (인벤토리 및 임베딩)를 Vertex AI의 벡터 검색에 일괄 업로드하고 색인을 새로고침하는 Dataflow 및 Workflow 작업을 활용합니다.

색인에서 사용자 쿼리 실행:

사용자가 의류 설명을 입력하면 앱이 Text Embeddings API를 사용하여 실시간으로 임베딩을 생성합니다. 그런 다음 이 정보가 Vector Search API에 입력으로 전송되어 색인에서 10개의 관련 제품 설명을 찾아 해당 이미지를 표시합니다.

아키텍처 개요

Spanner 벡터 검색 애플리케이션의 아키텍처는 다음의 두 부분으로 구성된 다이어그램에 나와 있습니다.

Spanner-벡터 검색 색인: a79932a25bee23a4.png

색인에서 사용자 쿼리를 실행하는 클라이언트 앱:

b2b4d5a5715bd4c4.png빌드할 항목

Spanner-벡터 색인:

  • 소스 데이터와 해당 임베딩을 저장하고 관리하는 Spanner 데이터베이스
  • 데이터 (ID 및 임베딩)를 Vertex AI 벡터 검색 데이터베이스에 일괄 업로드하는 워크플로 작업입니다.
  • 색인에서 관련 제품 설명을 찾는 데 사용되는 Vector Search API입니다.

색인에서 사용자 쿼리 실행:

  • 사용자가 의류의 텍스트 설명을 입력하고 배포된 색인 엔드포인트를 사용하여 유사성 검색을 수행하며 입력한 항목과 가장 가까운 의류를 반환할 수 있는 웹 애플리케이션입니다.

작동 방식

사용자가 의류에 대한 텍스트 설명을 입력하면 웹 애플리케이션이 Vector Search API로 설명을 전송합니다. 그러면 Vector Search API가 의류 설명의 임베딩을 사용하여 색인에서 가장 관련성이 높은 제품 설명을 찾습니다. 그러면 제품 설명과 해당 이미지가 사용자에게 표시됩니다. 일반적인 워크플로는 다음과 같습니다.

  1. Spanner에 저장된 데이터의 임베딩을 생성합니다.
  2. 임베딩을 내보내고 벡터 검색 색인에 업로드합니다.
  3. 최근접 이웃 검색을 실행하여 유사한 항목에 대한 벡터 검색 색인을 쿼리합니다.

2. 요구사항

  • 브라우저(Chrome 또는 Firefox 등)
  • 결제가 사용 설정된 Google Cloud 프로젝트

시작하기 전에

  1. Google Cloud 콘솔의 프로젝트 선택기 페이지에서 Google Cloud 프로젝트를 선택하거나 만듭니다.
  2. Cloud 프로젝트에 결제가 사용 설정되어 있어야 하므로 프로젝트에 결제가 사용 설정되어 있는지 확인하는 방법을 알아보세요.
  3. 필요한 모든 API (Cloud Spanner, Vertex AI, Google Cloud Storage)가 사용 설정되어 있는지 확인합니다.
  4. gcloud가 사전 로드되어 제공되는 Google Cloud에서 실행되는 명령줄 환경인 Cloud Shell을 사용합니다. gcloud 명령어 및 사용법은 문서를 참조하세요. 프로젝트가 설정되지 않은 경우 다음 명령어를 사용하여 설정합니다.
gcloud config set project <YOUR_PROJECT_ID>
  1. 시작하려면 활성 Google Cloud 프로젝트가 있는 Cloud Spanner 페이지로 이동하세요.

3. 백엔드: Spanner 데이터 소스 및 임베딩 만들기

이 사용 사례에서 Spanner 데이터베이스에는 의류 인벤토리와 해당 이미지 및 설명이 저장되어 있습니다. 텍스트 설명에 대한 임베딩을 생성하고 Spanner 데이터베이스에 ARRAY<float64>로 저장해야 합니다.

  1. Spanner 데이터 만들기

'spanner-vertex'라는 인스턴스를 만듭니다. 'spanner-vertex-Embeds'라는 데이터베이스가 있습니다. 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. 소스 데이터의 텍스트 임베딩 생성

임베딩을 저장할 테이블을 만들고 생성된 임베딩을 삽입합니다. 실제 데이터베이스 애플리케이션에서 2단계까지의 Spanner에 대한 데이터 로드는 트랜잭션입니다. 설계 권장사항을 그대로 유지하려면 트랜잭션 테이블을 정규화하여 임베딩을 위한 별도의 테이블을 만드는 것이 좋습니다.

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 데이터 내보내기

  1. Cloud Storage 버킷 만들기

이는 Spanner의 임베딩을 벡터 검색에서 입력으로 예상하는 JSON 형식으로 GCS 버킷에 저장하는 데 필요합니다. Spanner의 데이터와 동일한 리전에 버킷을 만듭니다. 필요한 경우 내부에 폴더를 생성하되 주로 empty.json이라는 빈 파일을 만듭니다.

  1. Cloud Workflow 설정

Spanner에서 Vertex AI 벡터 검색 색인으로 일괄 내보내기를 설정하려면 다음 안내를 따르세요.

빈 색인 만들기:

벡터 검색 색인이 Cloud Storage 버킷 및 데이터와 동일한 리전에 있는지 확인합니다. 색인 관리 페이지의 일괄 업데이트를 위한 색인 만들기 섹션에 있는 콘솔 탭에 있는 11단계 안내를 따릅니다. contentDeltaUri에 전달된 폴더에서 empty.json이라는 빈 파일을 만듭니다. 이 파일이 없으면 색인을 만들 수 없기 때문입니다. 이렇게 하면 빈 색인이 생성됩니다.

이미 색인이 있는 경우 이 단계를 건너뛰어도 됩니다. 그러면 워크플로가 색인을 덮어씁니다.

참고: 엔드포인트에 빈 색인을 배포할 수 없습니다. 따라서 벡터 데이터를 Cloud Storage로 내보낸 후에 엔드포인트에 배포하는 단계를 이후 단계로 연기합니다.

이 git 저장소 클론: git 저장소를 클론하는 방법에는 여러 가지가 있으며 한 가지 방법은 GitHub CLI를 사용하여 다음 명령어를 실행하는 것입니다. Cloud Shell 터미널에서 아래 명령어 2개를 실행합니다.

gh repo clone cloudspannerecosystem/spanner-ai

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

이 폴더에는 파일 2개가 포함되어 있습니다.

  • 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 (임베딩)에서 벡터 검색 색인으로 데이터를 내보내도록 워크플로를 설정하려면 다음 역할이 필요합니다.

Cloud Workflow 서비스 계정:

기본적으로 Compute Engine 기본 서비스 계정을 사용합니다.

수동으로 구성된 서비스 계정을 사용하는 경우 다음 역할을 포함해야 합니다.

Dataflow 작업 트리거: Dataflow 관리자, Dataflow 작업자

Dataflow 작업자 서비스 계정을 가장하려면 서비스 계정 사용자를 사용하세요.

로그 작성: 로그 작성자

Vertex AI 벡터 검색 재빌드를 트리거하려면 Vertex AI 사용자를 실행합니다.

Dataflow 작업자 서비스 계정:

수동으로 구성된 서비스 계정을 사용하는 경우 다음 역할을 포함해야 합니다.

Dataflow 관리: Dataflow 관리자, Dataflow Worker. Spanner에서 데이터를 읽으려면 Cloud Spanner 데이터베이스 리더 선택한 GCS Container Registry에 대한 쓰기 액세스: GCS 스토리지 버킷 소유자

  1. Cloud 워크플로 배포

워크플로 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의 콘텐츠를 복사하여 붙여넣습니다.

이 작업이 완료되면 워크플로를 실행하여 데이터 내보내기를 시작합니다.

  1. Cloud 워크플로 실행

다음 명령어를 실행하여 워크플로를 실행합니다.

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

실행은 Workflows의 실행 탭에 표시됩니다. 그러면 벡터 검색 데이터베이스에 데이터가 로드되고 색인이 생성됩니다.

참고: 실행 버튼을 사용하여 콘솔에서 실행할 수도 있습니다. 안내에 따라 입력한 다음, 맞춤설정된 input.json의 콘텐츠를 복사하여 붙여넣습니다.

5. 벡터 검색 색인 배포

엔드포인트에 색인 배포

아래 단계에 따라 색인을 배포할 수 있습니다.

  1. 벡터 검색 색인 페이지의 이전 섹션의 2단계에서 방금 만든 색인 옆에 배포 버튼이 표시됩니다. 또는 색인 정보 페이지로 이동하여 엔드포인트에 배포 버튼을 클릭할 수도 있습니다.
  2. 필요한 정보를 제공하고 엔드포인트에 색인을 배포합니다.

또는 이 노트북을 확인하여 엔드포인트에 배포할 수 있습니다 (노트북의 배포 부분으로 건너뜀). 배포되면 배포된 색인 ID와 엔드포인트 URL을 기록합니다.

6. 프런트엔드: 사용자 데이터를 벡터 검색으로

gRadio 기반 UX로 간단한 Python 애플리케이션을 빌드하여 구현을 빠르게 테스트해 보겠습니다. 여기에서 구현을 참고하여 colab 노트북에서 이 데모 앱을 구현할 수 있습니다.

  1. Embeddings API를 호출하고 벡터 검색 색인 엔드포인트를 호출하는 데 aiplatform python SDK를 사용합니다.
# [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를 사용해 Google에서 사용자 인터페이스로 쉽고 빠르게 빌드하고 있는 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. 배포된 색인 ID 및 엔드포인트 ID 선언
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. run_sql 메서드를 호출하여 이전 단계에서 반환된 최근접 이웃 벡터의 ID에 해당하는 이미지를 추출하는 Spanner 읽기 데이터 메서드 구현을 정의합니다.
!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. 대화상자에서 프로젝트 ID를 입력한 후 '종료'를 클릭하여 프로젝트를 삭제합니다.
  4. 프로젝트를 삭제하지 않으려면 이 프로젝트용으로 방금 만든 인스턴스로 이동하여 Spanner 인스턴스를 삭제하고 인스턴스 개요 페이지 오른쪽 상단의 인스턴스 삭제 버튼을 클릭합니다.
  5. 벡터 검색 색인으로 이동하여 엔드포인트와 색인을 배포 취소하고 색인을 삭제할 수도 있습니다.

8. 결론

축하합니다. 다음 방법으로 Spanner - Vertex 벡터 검색 구현을 완료했습니다.

  1. Spanner 데이터베이스에서 가져온 애플리케이션에 대한 Spanner 데이터 소스 및 임베딩 생성
  2. 벡터 검색 데이터베이스 색인을 만드는 중입니다.
  3. Dataflow 및 워크플로 작업을 사용하여 Spanner의 벡터 데이터를 벡터 검색에 통합
  4. 엔드포인트에 색인을 배포합니다.
  5. 마지막으로 Vertex AI SDK의 Python 기반 구현에서 사용자 입력으로 벡터 검색을 호출합니다.

자유롭게 자체 사용 사례로 구현을 확장하거나 새로운 기능을 통해 현재 사용 사례를 즉흥적으로 만들 수 있습니다. 여기에서 Spanner의 머신러닝 기능에 대해 자세히 알아보세요.