인덱스 및 쿼리 벡터 데이터
팁 (조언)
자세한 내용은 텍스트 및 이미지 탭을 참조하세요.
Azure Managed Redis는 RediSearch를 통해 벡터 데이터베이스 기능을 제공하므로 의미 체계 검색, 권장 시스템 및 RAG(검색 보강 세대)와 같은 AI 애플리케이션에 대한 고차원 임베딩을 저장하고 쿼리할 수 있습니다. 빠른 벡터 검색이 필요한 성능이 뛰어난 AI 백 엔드를 빌드하려면 인덱스를 만들고 벡터를 수집하고 유사성 검색을 실행하는 방법을 이해해야 합니다.
사용자 질문에 따라 관련 문서를 찾아야 하는 고객 지원 챗봇을 빌드한다고 상상해 보세요. 설명서는 텍스트로 존재하지만 의미 체계 유사성이 필요합니다. 다른 단어를 사용하더라도 동일한 것을 의미하는 문서를 찾습니다. 각 문서 및 각 사용자 질문에 대한 AI 모델에서 1536차원 임베딩을 생성하지만, 이제 수백만 개의 벡터를 저장하고 밀리초 단위로 검색해야 합니다. 기존 데이터베이스는 이 규모에서 고차원 유사성 검색을 효율적으로 처리할 수 없습니다. 벡터 인덱싱을 사용하는 Azure Managed Redis는 KNN 쿼리를 빠르게 만드는 특수한 데이터 구조(HNSW 그래프 또는 플랫 인덱스)를 제공하여 이를 해결하여 챗봇이 대규모 기술 자료가 있더라도 실시간으로 사용자에게 응답할 수 있도록 합니다.
벡터 인덱스 만들기
벡터 인덱스는 Redis가 빠른 유사성 검색을 위해 포함을 구성하기 위해 빌드하는 특수 데이터 구조입니다. 벡터를 저장하려면 벡터 필드 이름, 데이터 형식, 차원, 거리 메트릭 및 인덱싱 알고리즘을 포함하여 Redis가 포함을 처리하는 방법을 정확하게 지정하는 인덱스 스키마를 정의해야 합니다. 스키마를 Redis에 예상할 데이터의 종류와 최적의 쿼리 성능을 위해 구성하는 방법을 알려주는 청사진으로 간주합니다.
인덱스 스키마 구성 요소
스키마는 데이터 구조를 설명하는 여러 필드 정의를 결합합니다. 가장 중요한 구성 요소는 VectorField포함을 처리하는 방법을 Redis에 알려 줍니다. 필드 이름은 Redis 해시에 벡터가 저장되는 위치를 식별합니다. 차원은 포함 모델의 출력과 정확히 일치해야 하며(일반적으로 모델에 따라 384-3072), 데이터 형식은 메모리 사용량(FLOAT32 표준)을 결정하고, 거리 메트릭은 유사성 계산 방법을 제어합니다(COSINE은 텍스트 포함에 가장 적합함). 인덱스를 만들 때 Redis는 지정된 접두사를 사용하여 키 모니터링을 시작하고 추가한 모든 벡터를 자동으로 인덱싱합니다.
# Code fragment - focus on VectorField configuration
from redis.commands.search.field import TextField, VectorField
from redis.commands.search.indexDefinition import IndexDefinition, IndexType
schema = (
TextField("title"),
TextField("content"),
VectorField(
"embedding", # Field name in your Redis hashes
"HNSW", # Algorithm: FLAT or HNSW
{
"TYPE": "FLOAT32", # Standard for AI embeddings
"DIM": 1536, # Must match your model's output
"DISTANCE_METRIC": "COSINE" # Use COSINE for text, L2 for images
}
)
)
redis_client.ft("idx:documents").create_index(
fields=schema,
definition=IndexDefinition(
prefix=["doc:"], # Index keys starting with "doc:"
index_type=IndexType.HASH # HASH or JSON
)
)
인덱싱 알고리즘 선택
Redis는 벡터를 구성하기 위한 두 가지 알고리즘인 FLAT(직접 탐색)과 HNSW(그래프 기반 근사화)를 제공합니다. FLAT은 정확한 일치 항목을 찾기 위해 인덱스의 모든 단일 벡터와 쿼리를 비교합니다. 이렇게 하면 완벽한 정확도를 보장하지만 데이터 세트가 증가함에 따라 속도가 느려집니다. HNSW는 Redis가 벡터를 지능적으로 탐색할 수 있는 그래프 구조를 빌드하여 검색 공간의 관련 없는 영역을 건너뛰어 수백만 개의 벡터에서도 밀리초 단위로 근사한 인접 항목을 찾습니다. 완벽한 정확도가 필요한 경우 작은 데이터 세트(10,000개 미만)에 대해 FLAT을 선택하거나, 빠른 쿼리(<10ms)가 필요하고 95-99% 정확도를 허용할 수 있는 경우 큰 데이터 세트의 경우 HNSW를 선택합니다. 대부분의 프로덕션 AI 시스템은 엄청난 성능 향상에 비해 약간의 정확도 절충이 미미하기 때문에 HNSW를 사용합니다.
벡터 데이터 수집
데이터 적재는 임베딩을 Redis에 로드하여 검색할 수 있도록 하는 프로세스입니다. 일반 데이터와 달리 벡터는 특수한 처리가 필요합니다. Redis는 효율성을 극대화하기 위해 이진 Blob(바이트 배열)로 저장합니다. 즉, 스토리지 전에 NumPy tobytes() 배열을 바이트로 변환합니다. 인덱스 접두사(예: doc:*)와 일치하는 키에 벡터를 추가하면 Redis는 백그라운드에서 자동으로 인덱싱하며 별도의 인덱싱 단계가 필요하지 않습니다. 이 자동 인덱싱은 벡터를 추가, 업데이트 또는 삭제할 때 검색 인덱스를 데이터와 동기화된 상태로 유지합니다.
메타데이터를 사용하여 벡터 저장
벡터만 저장하는 것은 유용하지 않습니다. 검색 결과를 이해하려면 메타데이터(예: 제목, 콘텐츠, 범주)가 필요합니다. Redis Hash를 사용하면 사전을 사용하여 hsetmapping 벡터와 해당 메타데이터를 단일 키에 함께 저장할 수 있습니다. 포함 필드에는 바이트로 tobytes()변환된 벡터가 포함되고 다른 필드는 사람이 읽을 수 있는 정보를 보유합니다. 이 공동 배치는 Redis가 유사한 벡터를 발견하면 추가 조회 없이 애플리케이션에 필요한 컨텍스트를 즉시 반환할 수 있습니다.
# Code fragment - focus on vector storage with tobytes()
import numpy as np
embedding = np.array([0.1, 0.2, 0.3, ...], dtype=np.float32)
redis_client.hset(
"doc:001",
mapping={
"title": "Getting Started with Azure AI",
"content": "Azure AI Services provide pre-built models...",
"embedding": embedding.tobytes(), # Convert NumPy array to bytes
"category": "documentation"
}
)
성능을 위한 대량 인제션
수천 또는 수백만 개의 벡터를 로드할 때 개별 hset 명령을 보내면 처리량을 초당 수백 개의 작업으로 제한하는 네트워크 오버헤드가 발생합니다. 파이프라인은 여러 명령을 함께 일괄 처리하고 하나의 네트워크 왕복에서 Redis로 전송하여 이를 해결하므로 네트워크 대기 시간에 따라 처리량이 10~100배 증가할 수 있습니다. 파이프라인의 모든 명령은 서버에서 원자적으로 실행되며, execute()를 호출할 때 모든 응답을 한 번에 받습니다.
# Code fragment - focus on bulk ingestion pattern
# Assumes `documents` is a list of dicts with 'id', 'title', 'content', 'embedding'
pipeline = redis_client.pipeline()
for doc in documents:
vector_bytes = np.array(doc['embedding'], dtype=np.float32).tobytes()
pipeline.hset(
f"doc:{doc['id']}",
mapping={
"title": doc['title'],
"content": doc['content'],
"embedding": vector_bytes,
"category": doc.get('category', 'general')
}
)
# Execute all HSETs in one network round-trip
pipeline.execute()
유사성별 쿼리
벡터 유사성 검색은 KNN(K-Nearest Neighbors)을 사용하여 쿼리 포함과 가장 유사한 벡터를 찾습니다. 쿼리 벡터를 제출하면 Redis는 쿼리와 인덱싱된 벡터 간의 거리(COSINE 같은 선택한 메트릭 사용)를 계산한 다음 유사성 점수로 순위가 지정된 K와 가장 가까운 일치 항목을 반환합니다. 점수가 낮을수록 대부분의 메트릭에서 더 높은 유사성을 의미합니다. COSINE 거리의 경우 0.0은 동일한 벡터를 의미하고 2.0은 반대를 의미합니다. 이러한 점수를 이해하면 관련성 임계값을 설정하고 애플리케이션의 결과 품질을 조정할 수 있습니다.
기본 KNN 쿼리
KNN 쿼리에는 쿼리 벡터(바이트로 변환됨), 반환할 인접 K 수, 검색할 벡터 필드() 및 언어 2(@embedding벡터 쿼리에 필요)와 같은 여러 구성 요소가 함께 작동해야 합니다. 쿼리 문자열 *=>[KNN 5 @embedding $query_vec AS score]* 은 모든 문서를 검색하고, 벡터 검색 구문을 나타내고, =>KNN 5 5개의 가장 가까운 인접 항목을 요청하고, @embedding 벡터를 포함하는 필드를 지정하며$query_vec, 쿼리 바이트로 채우는 매개 변수 자리 표시자입니다. 이 AS score 절은 정렬할 수 있는 필드로 거리를 반환합니다.
# Code fragment - focus on KNN query syntax
from redis.commands.search.query import Query
query_bytes = np.array(query_embedding, dtype=np.float32).tobytes()
query = (
Query("*=>[KNN 5 @embedding $query_vec AS score]")
.return_fields("title", "content", "score")
.sort_by("score")
.dialect(2)
)
results = redis_client.ft("idx:documents").search(
query,
query_params={"query_vec": query_bytes}
)
쿼리 구문 *=>[KNN 5 @embedding $query_vec AS score] 은 모든 문서를 검색하고, 필드에서 가장 가까운 5개의 인접 항목을 embedding 찾고, 유사성 점수를 반환합니다. 벡터 쿼리에 사용합니다 .dialect(2) .
하이브리드 검색: 메타데이터를 사용하여 필터링
하이브리드 검색은 벡터 유사성과 기존 메타데이터 필터를 결합하여 특정 범주 또는 하위 집합 내에서 의미상 유사한 항목을 찾을 수 있도록 합니다. 하이브리드 검색은 실제 응용 프로그램에 강력합니다. "편안한 신발"을 검색하지만 "운동화" 범주 내에서만 검색하거나 지난 달에만 비슷한 문서를 찾는 것을 상상해 보세요. 구문은 필터 식(예: @category:{documentation})을 벡터 검색 연산자 앞에 배치합니다. 이 연산 =>자는 Redis에게 먼저 일치하는 항목으로 필터링한 다음 필터링된 집합 내에서만 K 가장 가까운 인접 항목을 찾도록 지시합니다.
# Code fragment - focus on hybrid query syntax
hybrid_query = Query(
"@category:{documentation}=>[KNN 3 @embedding $query_vec AS score]"
).return_fields("title", "category", "score").sort_by("score").dialect(2)
results = redis_client.ft("idx:documents").search(
hybrid_query,
query_params={"query_vec": query_bytes}
)
범위 쿼리: 임계값 기반 검색
KNN은 고정된 수의 결과(예: 상위 5개)를 반환하지만 범위 쿼리는 거리 임계값 내의 모든 벡터를 반환합니다. 임의 개수가 아닌 특정 유사성 수준 이상의 모든 항목을 원하는 경우에 유용합니다. 예를 들어 데이터에 따라 3개의 결과 또는 300을 반환할 수 있는 쿼리에서 COSINE 거리가 0.2 미만인 모든 문서를 원할 수 있습니다. 거리 임계값을 사용하여 VECTOR_RANGE 해당 경계 내의 모든 벡터를 찾습니다.
# Code fragment - focus on VECTOR_RANGE syntax
range_query = Query(
"@embedding:[VECTOR_RANGE 0.2 $query_vec]=>{$YIELD_DISTANCE_AS: score}"
).return_fields("title", "score").sort_by("score").dialect(2)
results = redis_client.ft("idx:documents").search(
range_query,
query_params={"query_vec": query_bytes}
)
주요 고려 사항
성공적인 벡터 검색은 몇 가지 기술 세부 정보를 정확하게 가져오는 데 달려 있습니다. 구성이 잘못되면 쿼리가 실패하거나 잘못된 결과를 반환할 수 있습니다. 차원 일치, 거리 메트릭 및 HNSW 튜닝을 이해하면 일반적인 문제를 방지하고 특정 사용 사례에 맞게 최적화할 수 있습니다. 이러한 문제는 이론적이지 않습니다. 차원이 일치하지 않으면 런타임 오류가 발생하고, 잘못된 거리 메트릭이 관련 없는 결과를 반환하며, 제대로 조정되지 않은 HNSW 매개 변수로 인해 쿼리가 필요 이상으로 느려질 수 있습니다.
차원 일치 요구 사항
거리 계산은 각 차원 위치별 비교에 의존하기 때문에 벡터 차원은 인덱스 정의와 쿼리 벡터 간에 정확히 일치해야 합니다. 인덱스에 1536차원 벡터가 있지만 768차원 벡터를 사용하여 쿼리하는 경우 Redis는 의미 있는 거리를 계산할 수 없으며 오류와 함께 쿼리를 거부합니다. 여러 포함 모델을 사용하거나 모델 버전 간에 전환할 때 가장 일반적인 실수 중 하나입니다. 항상 쿼리 벡터 차원이 인덱스 생성 시 지정한 DIM 매개 변수와 일치하는지 확인합니다.
거리 메트릭 이해
거리 메트릭은 Redis가 벡터 간의 "유사성"을 계산하는 방법을 정의합니다. 기본적으로 포함을 비교하는 데 사용되는 수식입니다. 잘못된 메트릭을 선택하면 다른 메트릭이 서로 다른 벡터 속성을 측정하므로 관련 없는 결과가 반환됩니다. COSINE은 언어 모델이 의미 체계 의미를 인코딩하는 방법과 일치하는 벡터 사이의 각도(크기 무시)를 측정합니다. L2는 방향과 크기를 모두 고려하여 직선 거리를 측정하며 이미지와 같은 공간 데이터에 더 적합합니다. COSINE 비교를 위해 학습된 텍스트 포함과 함께 L2를 사용하면 수학적으로 정확하지만 의미 없는 결과를 얻을 수 있습니다. 포함 모델의 학습 목표와 일치하는 메트릭을 선택합니다.
- 코사인: 텍스트 포함에 사용(OpenAI, Cohere, 문장 변환기)
- L2: 이미지 포함 및 공간 데이터에 사용
- IP: 미리 정규화된 임베딩에만 사용하십시오
HNSW 성능 조정
HNSW의 속도는 모든 벡터를 확인하는 대신 그래프 구조를 선택적으로 탐색하는 것에서 비롯되지만, 더 많은 그래프를 탐색하면 속도가 향상되는 동시에 정확도가 향상됩니다. 매개 변수는 EF_RUNTIME 검색 중에 Redis가 검사하는 그래프 노드 수를 제어합니다. 값이 높을수록 더 철저한 탐색과 정확도를 제공하지만 쿼리는 느립니다. 기본값은 일반적으로 속도의 우선 순위를 지정하는 10입니다. 쿼리당 이 값을 조정하여 다양한 사용 사례에 대한 속도와 정확도의 균형을 맞출 수 있습니다.
# Code fragment - focus on EF_RUNTIME parameter
query = Query("*=>[KNN 10 @embedding $query_vec EF_RUNTIME 200 AS score]")
값이 높을수록 정확도가 향상되지만 쿼리 속도가 느립니다. 50부터 시작하여 필요한 경우 100-200으로 늘입니다.
추가 리소스
- RediSearch 벡터 유사성 설명서 - 벡터 인덱싱 및 쿼리에 대한 공식 가이드
- redis-py 벡터 검색 예제 - 작업 코드 예제가 포함된 포괄적인 Notebook