Partitioned DML을 사용하여 텍스트 데이터에 대한 벡터 임베딩 일괄 생성

이 문서에서는 SQL 및 Vertex AI textembedding-gecko 모델을 사용하여 Spanner에 저장된 텍스트 데이터(STRING 또는 JSON)에 대해 벡터 임베딩을 일괄 생성하고 백필하는 방법을 설명합니다.

기본 요건

Spanner 데이터베이스에 텍스트 데이터(STRING 또는 JSON)를 포함하는 테이블이 있어야 합니다. 데이터 가져오기에 대한 자세한 내용은 Spanner 가져오기 및 내보내기 개요를 참조하세요.

사용 사례

Spanner에 다음 스키마를 사용하는 테이블이 있다고 가정해 보겠습니다. 이 테이블에는 수백만 개의 레코드가 포함되어 있습니다.

GoogleSQL

CREATE TABLE Products (
  product_id INT64 NOT NULL,
  name STRING(MAX),
  description STRING(MAX)
) PRIMARY KEY(product_id);

PostgreSQL

CREATE TABLE Products (
  product_id INT8 NOT NULL,
  name TEXT,
  description TEXT,
  PRIMARY KEY(product_id)
);

목표는 이 테이블의 description 열의 벡터 임베딩을 생성하고 벡터 검색을 사용하여 고객에게 추천할 유사한 항목을 찾음으로써 쇼핑 경험을 개선하기 위한 것입니다.

임베딩 모델 등록

GoogleSQL

Spanner 데이터베이스에서 Vertex AI textembedding-gecko 엔드포인트에 임베딩 모델을 등록합니다.

CREATE MODEL MODEL_NAME
INPUT(
  content STRING(MAX)
)
OUTPUT(
  embeddings STRUCT<values ARRAY<FLOAT32>>
)
REMOTE OPTIONS(
    endpoint = '//aiplatform.googleapis.com/projects/PROJECT/locations/LOCATION/publishers/google/models/textembedding-gecko$MODEL_VERSION',
  default_batch_size = 5
)

다음을 바꿉니다.

  • MODEL_NAME: 임베딩 모델의 이름입니다.
  • PROJECT: Vertex AI 엔드포인트를 호스팅하는 프로젝트입니다.
  • LOCATION: Vertex AI 엔드포인트의 위치입니다.
  • MODEL_VERSION: textembedding-gecko 임베딩 모델의 버전입니다.

PostgreSQL

PostgreSQL 언어에서는 모델을 등록할 필요가 없습니다. 엔드포인트 이름을 직접 spanner.ML_PREDICT_ROW 함수 호출에 전달합니다.

권장사항으로 다음 사항을 고려하세요.

  • 할당량 분리를 유지하려면 다른 프로젝트의 엔드포인트를 사용하여 프로덕션 엔드포인트와 다른 임베딩을 생성하고 백필합니다. 프로덕션 트래픽을 처리하기 위해 프로덕션 엔드포인트를 예약합니다.
  • 모델 엔드포인트가 default_batch_size 값을 지원하는지 확인합니다. default_batch_size를 쿼리 힌트 @{remote_udf_max_rows_per_rpc=NEW_NUMBER}로 재정의할 수 있습니다. 각 리전의 default_batch_size 한도에 대한 자세한 내용은 텍스트 스니펫의 텍스트 임베딩 가져오기를 참조하세요.
  • 엔드포인트를 @latest 대신 특정 모델 버전(예: @003)으로 정의합니다. 동일한 텍스트 조각에 대해 생성된 임베딩 벡터가 사용되는 모델 버전에 따라 다를 수 있기 때문입니다. 따라서 동일한 데이터 세트에서 서로 다른 모델 버전을 사용하여 임베딩을 생성하지 않는 것이 좋습니다. 또한 모델 정의 문에서 모델 버전을 업데이트해도 이 모델로 이미 생성된 임베딩은 업데이트되지 않습니다. 임베딩의 모델 버전을 관리하는 한 가지 방법은 모델 버전을 저장하는 테이블에 추가 열을 만드는 것입니다.
  • 커스텀 조정된 textembedding-gecko 모델은 GoogleSQL ML.PREDICT 및 PostgreSQL spanner.ML_PREDICT_ROW 함수에서 지원되지 않습니다.

임베딩 모델의 엔드 투 엔드 통합 테스트

쿼리를 실행하여 임베딩 모델이 성공적으로 구성되었고 임베딩이 검색되는지 테스트할 수 있습니다. 예를 들어 다음 쿼리를 실행합니다.

GoogleSQL

SELECT embeddings.values
FROM SAFE.ML.PREDICT(
  MODEL MODEL_NAME,
  (SELECT description AS content FROM products LIMIT 10)
);

다음을 바꿉니다.

  • MODEL_NAME: 임베딩 모델의 이름

PostgreSQL

SELECT spanner.ML_PREDICT_ROW(
    'projects/PROJECT/locations/LOCATION/publishers/google/models/textembedding-gecko$MODEL_VERSION',
    JSONB_BUILD_OBJECT('instances', JSONB_BUILD_ARRAY(JSONB_BUILD_OBJECT('content', description))))
FROM Products
LIMIT 10;

다음을 바꿉니다.

  • PROJECT: Vertex AI 엔드포인트를 호스팅하는 프로젝트입니다.
  • LOCATION: Vertex AI 엔드포인트의 위치입니다.
  • MODEL_VERSION: textembedding-gecko 임베딩 모델의 버전입니다.

임베딩을 저장할 추가 열을 포함하도록 소스 테이블 업데이트

다음으로, 생성된 임베딩을 저장하기 위해 데이터 유형 ARRAY<FLOAT32>의 추가 열을 포함하도록 소스 테이블 스키마를 업데이트합니다.

GoogleSQL

ALTER TABLE TABLE_NAME
ADD COLUMN EMBEDDING_COLUMN_NAME ARRAY<FLOAT32>;

다음을 바꿉니다.

  • TABLE_NAME: 소스 테이블 이름입니다.
  • EMBEDDING_COLUMN_NAME: 생성된 임베딩을 추가할 열의 이름입니다.

PostgreSQL

ALTER TABLE TABLE_NAME
ADD COLUMN EMBEDDING_COLUMN_NAME real[];

다음을 바꿉니다.

  • TABLE_NAME: 소스 테이블 이름입니다.
  • EMBEDDING_COLUMN_NAME: 생성된 임베딩을 추가할 열의 이름입니다.

예를 들어 products 테이블 예시를 사용하여 다음을 실행합니다.

GoogleSQL

ALTER TABLE Products
ADD COLUMN desc_embed ARRAY<FLOAT32>;

PostgreSQL

ALTER TABLE Products
ADD COLUMN desc_embed real[];

다른 열을 추가하여 임베딩 모델 버전을 관리할 수 있습니다.

GoogleSQL

ALTER TABLE Products
ADD COLUMN desc_embed_model_version INT64;

PostgreSQL

ALTER TABLE Products
ADD COLUMN desc_embed_model_version INT8;

Vertex AI 할당량 늘리기

모델을 사용하는 리전에서 textembedding-gecko의 Vertex AI API 할당량을 늘려야 할 수 있습니다. 상향을 요청하려면 Vertex AI 할당량 상향 조정을 참조하세요.

자세한 내용은 Vertex AI 할당량 및 한도를 참조하세요.

임베딩 백필

마지막으로 Partitioned DML을 사용하여 다음 UPDATE 문을 실행하여 텍스트 데이터 열의 임베딩을 생성하고 데이터베이스에 임베딩을 저장합니다. 임베딩과 함께 모델 버전을 저장할 수 있습니다. 데이터베이스에 대한 트래픽이 적을 때 이 쿼리를 실행하는 것이 좋습니다.

GoogleSQL

UPDATE TABLE_NAME
SET
  TABLE_NAME.EMBEDDING_COLUMN_NAME = (
    SELECT embeddings.values
    FROM SAFE.ML.PREDICT(
      MODEL MODEL_NAME,
      (SELECT TABLE_NAME.DATA_COLUMN_NAME AS content)
    ) @{remote_udf_max_rows_per_rpc=MAX_ROWS}
  ),
  TABLE_NAME.EMBEDDING_VERSION_COLUMN = MODEL_VERSION
WHERE FILTER_CONDITION;

다음을 바꿉니다.

  • TABLE_NAME: 텍스트 데이터가 있는 테이블의 이름입니다.
  • EMBEDDING_COLUMN_NAME: 생성된 임베딩을 추가할 열의 이름입니다.
  • DATA_COLUMN_NAME: 텍스트 데이터가 있는 열의 이름입니다.
  • MODEL_NAME: 임베딩 모델의 이름입니다.
  • MAX_ROWS: RPC당 최대 행 수입니다.
  • EMBEDDING_VERSION_COLUMN: 임베딩 백필에 사용되는 textembedding-gecko 임베딩 모델의 버전을 관리하는 열입니다.
  • MODEL_VERSION: textembedding-gecko 임베딩 모델의 버전입니다.
  • FILTER_CONDITION: 적용할 파티셔닝 가능 필터 조건입니다.

SAFE.ML.PREDICT를 사용하면 실패한 요청에 대해 NULL이 반환됩니다. 또한 SAFE.ML.PREDICTWHERE embedding_column IS NULL 필터와 함께 사용하여 이미 계산된 필드의 임베딩을 계산하지 않고 쿼리를 다시 실행할 수도 있습니다.

PostgreSQL

UPDATE TABLE_NAME
SET
  EMBEDDING_COLUMN_NAME = spanner.FLOAT32_ARRAY(spanner.ML_PREDICT_ROW(
    'projects/PROJECT/locations/LOCATION/publishers/google/models/textembedding-gecko$MODEL_VERSION',
    JSONB_BUILD_OBJECT('instances', JSONB_BUILD_ARRAY(JSONB_BUILD_OBJECT('content', DATA_COLUMN_NAME)))
  ) /*@ remote_udf_max_rows_per_rpc=MAX_ROWS */ ->'predictions'->0->'embeddings'->'values'),
  EMBEDDING_VERSION_COLUMN = MODEL_VERSION
WHERE FILTER_CONDITION;

다음을 바꿉니다.

  • TABLE_NAME: 텍스트 데이터가 있는 테이블의 이름입니다.
  • EMBEDDING_COLUMN_NAME: 생성된 임베딩을 추가할 열의 이름입니다.
  • DATA_COLUMN_NAME: 텍스트 데이터가 있는 열의 이름입니다.
  • PROJECT: Vertex AI 엔드포인트를 호스팅하는 프로젝트입니다.
  • LOCATION: Vertex AI 엔드포인트의 위치입니다.
  • MODEL_VERSION: textembedding-gecko 임베딩 모델의 버전입니다.
  • MAX_ROWS: RPC당 최대 행 수입니다.
  • EMBEDDING_VERSION_COLUMN: 임베딩을 백필하는 데 사용되는 textembedding-gecko 임베딩 모델의 버전을 관리하는 열입니다.
  • FILTER_CONDITION: 적용할 파티셔닝 가능 필터 조건입니다.

products 테이블의 백필 쿼리 예시는 다음과 같습니다.

GoogleSQL

UPDATE products
SET
  products.desc_embed = (
    SELECT embeddings.values
    FROM SAFE.ML.PREDICT(
      MODEL gecko_model,
      (SELECT products.description AS content)
    ) @{remote_udf_max_rows_per_rpc=200}
  ),
  products.desc_embed_model_version = 3
WHERE products.desc_embed IS NULL;

PostgreSQL

UPDATE products
SET
  desc_embed = spanner.FLOAT32_ARRAY(spanner.ML_PREDICT_ROW(
    'projects/PROJECT/locations/LOCATION/publishers/google/models/textembedding-gecko@003',
    JSONB_BUILD_OBJECT('instances', JSONB_BUILD_ARRAY(JSONB_BUILD_OBJECT('content', description)))
  ) /*@ remote_udf_max_rows_per_rpc=200 */ ->'predictions'->0->'embeddings'->'values'),
  desc_embed_model_version = 3
WHERE desc_embed IS NULL;

권장사항으로 다음 사항을 고려하세요.

  • Spanner API의 기본 gRPC 제한 시간은 1시간입니다. 백필하는 임베딩 양에 따라 UPDATE Partitioned DML을 완료하는 데 충분한 시간이 주어지도록 이 제한 시간을 늘려야 할 수 있습니다. 자세한 내용은 커스텀 제한 시간 및 재시도 구성을 참조하세요.

성능 및 기타 고려사항

임베딩 데이터를 백필할 때 성능을 최적화하려면 다음을 고려하세요.

노드 수

Partitioned DML은 여러 파티션에서 지정된 DML 문을 동시에 실행합니다. 노드 수가 많은 인스턴스의 경우 Partitioned DML을 실행하는 동안 할당량 오류가 발생할 수 있습니다. Vertex AI API 요청이 Vertex AI API 할당량 한도로 인해 제한되면 Spanner는 Partitioned DML 트랜잭션 모드로 이러한 실패를 최대 20회까지 재시도합니다. Vertex AI에서 할당량 오류율이 높은 경우 Vertex AI의 할당량을 상향 조정하세요.

데이터 열의 텍스트 크기

Vertex AI 임베딩 모델의 경우 각 텍스트 입력에 대한 최대 토큰 수 제한이 있습니다. 모델 버전마다 토큰 수 제한이 다릅니다. 각 Vertex AI 요청에는 여러 개의 입력 텍스트 필드가 있을 수 있지만 단일 요청의 최대 토큰 수에는 제한이 있습니다. GoogleSQL 데이터베이스의 경우 '요청이 너무 큽니다' 메시지와 함께 INVALID_ARGUMENT 오류가 발생하면 오류를 방지하기 위해 배치 크기를 줄여보세요. 이렇게 하려면 모델을 등록할 때 default_batch_size를 구성하거나 @{remote_udf_max_outstanding_rpcs} 쿼리 힌트를 사용하면 됩니다.

Vertex AI로 전송된 API 요청 수

쿼리 힌트 @{remote_udf_max_outstanding_rpcs}를 사용하여 Spanner에서 Vertex AI로 전송되는 요청 수를 늘리거나 줄일 수 있습니다. 이 한도를 늘리면 Spanner 인스턴스의 CPU 및 메모리 사용량이 증가할 수 있습니다. GoogleSQL 데이터베이스의 경우 이 쿼리 힌트를 사용하면 모델에 구성된 default_batch_size가 재정의됩니다.

백필 진행 상황 모니터링

시스템 통계 대시보드를 사용하여 Spanner에서 Vertex AI로 전송된 요청 수, 지연 시간, 네트워크 바이트를 모니터링할 수 있습니다.

다음 단계