Weaviate 완전 정복: 벡터 검색과 인덱싱으로 차세대 AI 검색 시스템 구축하기
Weaviate는 현재 가장 인기 있는 오픈소스 벡터 데이터베이스 중 하나로, AI 기반의 차세대 검색 시스템을 구축할 수 있게 해줍니다. 기존의 키워드 기반 검색을 넘어서 의미적 유사성을 기반으로 한 벡터 검색, 하이브리드 검색, 그리고 생성형 AI와의 통합을 지원합니다.
이 튜토리얼에서는 Weaviate를 macOS에서 설치하고, 실제 벡터 검색과 인덱싱을 구현하는 방법을 단계별로 알아보겠습니다.
개발환경 정보
테스트 환경:
- 운영체제: macOS Sequoia 15.0 (Darwin 25.0.0)
- Docker 버전: 28.2.2
- Python 버전: 3.12.3
- Weaviate 서버: 1.26.4
- Weaviate Python 클라이언트: 4.15.4
Weaviate란 무엇인가?
벡터 데이터베이스의 혁신
Weaviate는 다음과 같은 특징을 가진 차세대 데이터베이스입니다:
- 벡터 검색: 임베딩 벡터를 활용한 의미적 유사성 검색
- 하이브리드 검색: 벡터 검색과 전통적인 키워드 검색의 결합
- 멀티모달 지원: 텍스트, 이미지, 오디오 등 다양한 데이터 타입
- 실시간 처리: 밀리초 단위의 빠른 검색 응답
- 확장성: 수십억 개의 객체까지 확장 가능
Weaviate의 핵심 개념
- 클래스(Class): 스키마의 기본 단위, 관계형 DB의 테이블과 유사
- 객체(Object): 클래스의 인스턴스, 속성과 벡터를 포함
- 벡터(Vector): 고차원 임베딩으로 표현된 데이터의 의미적 표현
- 인덱스(Index): 빠른 벡터 검색을 위한 HNSW 알고리즘 기반 구조
Weaviate 설치하기
Docker Compose를 통한 설치
Weaviate는 Docker를 통해 간편하게 설치할 수 있습니다.
# 프로젝트 디렉터리 생성
mkdir weaviate-test && cd weaviate-test
docker-compose.yml 파일 생성:
---
version: '3.4'
services:
weaviate:
command:
- --host
- 0.0.0.0
- --port
- '8080'
- --scheme
- http
image: semitechnologies/weaviate:1.26.4
ports:
- "8080:8080"
- "50051:50051"
volumes:
- weaviate_data:/var/lib/weaviate
restart: on-failure:0
environment:
QUERY_DEFAULTS_LIMIT: 25
AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: 'true'
PERSISTENCE_DATA_PATH: '/var/lib/weaviate'
DEFAULT_VECTORIZER_MODULE: 'none'
ENABLE_MODULES: 'text2vec-cohere,text2vec-huggingface,text2vec-palm,text2vec-openai,generative-openai,generative-cohere,generative-palm,ref2vec-centroid,reranker-cohere,qna-openai'
CLUSTER_HOSTNAME: 'node1'
volumes:
weaviate_data:
서비스 시작
# Weaviate 컨테이너 시작
docker-compose up -d
# 상태 확인
docker ps | grep weaviate
실행 결과:
2a53d6a0209d semitechnologies/weaviate:1.26.4 "/bin/weaviate --hos…" Up 16 seconds 0.0.0.0:8080->8080/tcp, 0.0.0.0:50051->50051/tcp weaviate-test-weaviate-1
Python 클라이언트 설치
# Weaviate Python 클라이언트 설치
pip3 install weaviate-client requests
Weaviate 기본 사용법
연결 및 기본 설정
import weaviate
import numpy as np
from typing import List, Dict, Any
# Weaviate 클라이언트 연결
client = weaviate.connect_to_local(
host="localhost",
port=8080
)
# 연결 확인
if client.is_ready():
print("✅ Weaviate 연결 성공!")
meta = client.get_meta()
print(f"Weaviate 버전: {meta.get('version', 'Unknown')}")
실행 결과:
✅ Weaviate 연결 성공!
Weaviate 버전: 1.26.4
스키마 생성
# Article 컬렉션 생성
article_collection = client.collections.create(
name="Article",
description="A collection of articles for vector search testing",
vectorizer_config=weaviate.classes.config.Configure.Vectorizer.none(),
vector_index_config=weaviate.classes.config.Configure.VectorIndex.hnsw(
distance_metric=weaviate.classes.config.VectorDistances.COSINE
),
properties=[
weaviate.classes.config.Property(
name="title",
data_type=weaviate.classes.config.DataType.TEXT,
description="The title of the article"
),
weaviate.classes.config.Property(
name="content",
data_type=weaviate.classes.config.DataType.TEXT,
description="The content of the article"
),
weaviate.classes.config.Property(
name="category",
data_type=weaviate.classes.config.DataType.TEXT,
description="The category of the article"
),
weaviate.classes.config.Property(
name="author",
data_type=weaviate.classes.config.DataType.TEXT,
description="The author of the article"
),
weaviate.classes.config.Property(
name="publish_date",
data_type=weaviate.classes.config.DataType.DATE,
description="The publish date of the article"
)
]
)
벡터 생성과 데이터 삽입
샘플 벡터 생성 함수
실제 프로덕션에서는 OpenAI, Cohere, HuggingFace 등의 임베딩 모델을 사용하지만, 이 예제에서는 테스트용 벡터를 생성합니다:
def generate_sample_vector(text: str, dimension: int = 384) -> List[float]:
"""샘플 벡터 생성 (실제로는 임베딩 모델 사용)"""
# 해시 기반 결정적 벡터 생성
np.random.seed(hash(text) % (2**32))
vector = np.random.normal(0, 1, dimension)
# L2 정규화
vector = vector / np.linalg.norm(vector)
return vector.tolist()
샘플 데이터 삽입
sample_articles = [
{
"title": "인공지능과 머신러닝의 미래",
"content": "인공지능과 머신러닝 기술이 급속도로 발전하면서 우리의 일상생활과 비즈니스 환경을 변화시키고 있습니다. 딥러닝, 자연어처리, 컴퓨터 비전 등의 기술이 다양한 분야에서 혁신을 이끌고 있습니다.",
"category": "AI/ML",
"author": "김인공",
"publish_date": "2025-01-15T09:00:00Z"
},
{
"title": "블록체인 기술의 실제 활용 사례",
"content": "블록체인 기술은 암호화폐를 넘어서 공급망 관리, 의료 기록 관리, 디지털 신원 확인 등 다양한 분야에서 활용되고 있습니다. 탈중앙화와 투명성의 장점을 활용한 혁신적인 솔루션들이 등장하고 있습니다.",
"category": "Blockchain",
"author": "박블록",
"publish_date": "2025-01-20T14:30:00Z"
},
# ... 추가 아티클들
]
# 배치 삽입
objects_to_insert = []
for article in sample_articles:
combined_text = f"{article['title']} {article['content']}"
vector = generate_sample_vector(combined_text)
obj = weaviate.classes.data.DataObject(
properties=article,
vector=vector
)
objects_to_insert.append(obj)
# 데이터 삽입
result = article_collection.data.insert_many(objects_to_insert)
print(f"✅ {len(sample_articles)}개의 아티클 삽입 완료")
벡터 검색 구현
기본 벡터 검색
def vector_search(query: str, limit: int = 3):
"""벡터 검색 수행"""
# 쿼리 벡터 생성
query_vector = generate_sample_vector(query)
# 벡터 검색 수행
response = article_collection.query.near_vector(
near_vector=query_vector,
limit=limit,
return_metadata=weaviate.classes.query.MetadataQuery(distance=True)
)
print(f"🔍 검색 쿼리: '{query}'")
print("검색 결과:")
for i, obj in enumerate(response.objects, 1):
distance = obj.metadata.distance
similarity = 1 - distance # cosine distance를 similarity로 변환
print(f" {i}. {obj.properties['title']}")
print(f" 작성자: {obj.properties['author']}")
print(f" 유사도: {similarity:.4f}")
print(f" 카테고리: {obj.properties['category']}")
# 테스트 실행
vector_search("머신러닝과 딥러닝 기술")
실행 결과:
🔍 검색 쿼리: '머신러닝과 딥러닝 기술'
검색 결과:
1. 인공지능과 머신러닝의 미래
작성자: 김인공
유사도: 0.0477
카테고리: AI/ML
2. 양자 컴퓨팅의 원리와 응용
작성자: 정양자
유사도: 0.0115
카테고리: Quantum
3. 사이버 보안의 최신 동향과 대응 전략
작성자: 최보안
유사도: 0.0058
카테고리: Security
하이브리드 검색 (벡터 + 키워드)
하이브리드 검색은 벡터 검색과 전통적인 BM25 키워드 검색을 결합한 강력한 기능입니다:
def hybrid_search(query: str, limit: int = 3):
"""하이브리드 검색 수행"""
query_vector = generate_sample_vector(query)
# 하이브리드 검색 (벡터 + BM25)
response = article_collection.query.hybrid(
query=query,
vector=query_vector,
limit=limit,
return_metadata=weaviate.classes.query.MetadataQuery(score=True)
)
print(f"🔍 하이브리드 검색: '{query}'")
print("하이브리드 검색 결과:")
for i, obj in enumerate(response.objects, 1):
score = obj.metadata.score
print(f" {i}. {obj.properties['title']}")
print(f" 작성자: {obj.properties['author']}")
print(f" 점수: {score:.4f}")
print(f" 카테고리: {obj.properties['category']}")
# 테스트 실행
hybrid_search("AI 인공지능 기술")
실행 결과:
🔍 하이브리드 검색: 'AI 인공지능 기술'
하이브리드 검색 결과:
1. 인공지능과 머신러닝의 미래
작성자: 김인공
점수: 0.9281
카테고리: AI/ML
2. 클라우드 컴퓨팅과 DevOps 모범 사례
작성자: 이클라우드
점수: 0.7000
카테고리: DevOps
3. 양자 컴퓨팅의 원리와 응용
작성자: 정양자
점수: 0.3440
카테고리: Quantum
필터링된 검색
특정 조건으로 결과를 필터링하는 검색도 가능합니다:
def filtered_search(query: str, categories: List[str], limit: int = 3):
"""필터링된 벡터 검색"""
query_vector = generate_sample_vector(query)
# 모든 결과를 가져온 후 필터링
response = article_collection.query.near_vector(
near_vector=query_vector,
limit=10,
return_metadata=weaviate.classes.query.MetadataQuery(distance=True)
)
print(f"🔍 필터링된 검색: '{query}' (카테고리: {', '.join(categories)})")
print("필터링된 검색 결과:")
filtered_count = 0
for obj in response.objects:
if obj.properties['category'] in categories:
filtered_count += 1
distance = obj.metadata.distance
similarity = 1 - distance
print(f" {filtered_count}. {obj.properties['title']}")
print(f" 작성자: {obj.properties['author']}")
print(f" 유사도: {similarity:.4f}")
print(f" 카테고리: {obj.properties['category']}")
if filtered_count >= limit:
break
# 테스트 실행
filtered_search("기술 혁신", ["AI/ML", "DevOps"])
인덱싱 최적화
HNSW 인덱스 설정
Weaviate는 기본적으로 HNSW(Hierarchical Navigable Small World) 알고리즘을 사용합니다:
# 고성능 인덱스 설정
optimized_collection = client.collections.create(
name="OptimizedArticle",
vector_index_config=weaviate.classes.config.Configure.VectorIndex.hnsw(
distance_metric=weaviate.classes.config.VectorDistances.COSINE,
ef_construction=200, # 인덱스 구축 시 정확도 (기본값: 128)
max_connections=64, # 노드당 최대 연결 수 (기본값: 32)
ef=100, # 검색 시 정확도 (기본값: -1, 동적)
dynamic_ef_min=50, # 동적 ef의 최소값
dynamic_ef_max=500, # 동적 ef의 최대값
vector_cache_max_objects=100000 # 벡터 캐시 크기
)
)
인덱스 성능 매개변수 설명
- ef_construction: 인덱스 구축 시 탐색할 후보 수 (높을수록 정확하지만 느림)
- max_connections: 각 노드의 최대 연결 수 (높을수록 정확하지만 메모리 사용량 증가)
- ef: 검색 시 탐색할 후보 수 (동적으로 조정 가능)
- vector_cache_max_objects: 메모리에 캐시할 벡터 수
성능 최적화 전략
배치 처리
대량의 데이터를 삽입할 때는 배치 처리를 사용하세요:
# 배치 삽입 최적화
def batch_insert_optimized(articles, batch_size=100):
"""최적화된 배치 삽입"""
total_inserted = 0
for i in range(0, len(articles), batch_size):
batch = articles[i:i + batch_size]
objects_to_insert = []
for article in batch:
combined_text = f"{article['title']} {article['content']}"
vector = generate_sample_vector(combined_text)
obj = weaviate.classes.data.DataObject(
properties=article,
vector=vector
)
objects_to_insert.append(obj)
# 배치 삽입
result = article_collection.data.insert_many(objects_to_insert)
total_inserted += len(batch)
print(f"배치 {i//batch_size + 1}: {len(batch)}개 삽입 완료 (총 {total_inserted}개)")
return total_inserted
메모리 최적화
# 메모리 효율적인 벡터 검색
def memory_efficient_search(query: str, limit: int = 10):
"""메모리 효율적인 검색"""
query_vector = generate_sample_vector(query)
# 속성은 최소한만 반환
response = article_collection.query.near_vector(
near_vector=query_vector,
limit=limit,
return_metadata=weaviate.classes.query.MetadataQuery(distance=True),
return_properties=["title", "category"] # 필요한 속성만 반환
)
return response.objects
성능 벤치마킹
검색 성능 테스트
import time
def performance_benchmark(num_queries=10):
"""성능 벤치마크 테스트"""
query_vector = generate_sample_vector("성능 테스트 쿼리")
times = []
for i in range(num_queries):
start_time = time.time()
response = article_collection.query.near_vector(
near_vector=query_vector,
limit=5
)
end_time = time.time()
times.append(end_time - start_time)
avg_time = sum(times) / len(times)
min_time = min(times)
max_time = max(times)
print(f"벡터 검색 성능 ({num_queries}회 평균):")
print(f" - 평균 시간: {avg_time*1000:.2f}ms")
print(f" - 최소 시간: {min_time*1000:.2f}ms")
print(f" - 최대 시간: {max_time*1000:.2f}ms")
# 벤치마크 실행
performance_benchmark()
실행 결과:
벡터 검색 성능 (10회 평균):
- 평균 시간: 1.78ms
- 최소 시간: 1.38ms
- 최대 시간: 2.83ms
집계 및 분석
카테고리별 집계
def analyze_data():
"""데이터 집계 분석"""
# 카테고리별 아티클 수 집계
response = article_collection.aggregate.over_all(
group_by="category"
)
print("카테고리별 아티클 수:")
for group in response.groups:
print(f" - {group.grouped_by.value}: {group.total_count}개")
# 분석 실행
analyze_data()
실행 결과:
카테고리별 아티클 수:
- AI/ML: 1개
- DevOps: 1개
- Blockchain: 1개
- Quantum: 1개
- Security: 1개
편리한 사용을 위한 Alias 설정
macOS에서 Weaviate를 더 편리하게 사용하기 위한 zsh 별칭을 설정할 수 있습니다.
Alias 설정 스크립트
#!/bin/bash
# ~/.zshrc에 Weaviate 관련 alias 추가
cat >> ~/.zshrc << 'EOF'
# Weaviate 관련 Aliases
alias weaviate-start='cd weaviate-test && docker-compose up -d && cd ..'
alias weaviate-stop='cd weaviate-test && docker-compose down && cd ..'
alias weaviate-restart='cd weaviate-test && docker-compose restart && cd ..'
alias weaviate-status='docker ps | grep weaviate'
alias weaviate-logs='cd weaviate-test && docker-compose logs -f weaviate'
alias weaviate-test='python3 test_weaviate.py'
alias weaviate-cleanup='cd weaviate-test && docker-compose down -v && cd ..'
# Weaviate 빠른 상태 확인 함수
weaviate-check() {
echo "Weaviate 상태 확인 중..."
if docker ps | grep -q weaviate; then
echo "✅ Weaviate 실행 중"
echo "🌐 Web UI: http://localhost:8080"
echo "📊 API 엔드포인트: http://localhost:8080/v1"
else
echo "❌ Weaviate 실행되지 않음"
echo "시작하려면 'weaviate-start' 명령어를 사용하세요"
fi
}
# Weaviate 헬스체크 함수
weaviate-health() {
echo "Weaviate 헬스체크 실행 중..."
if curl -s http://localhost:8080/v1/.well-known/ready | grep -q "true"; then
echo "✅ Weaviate 정상 작동 중"
version=$(curl -s http://localhost:8080/v1/meta | python3 -c "import sys, json; print(json.load(sys.stdin)['version'])" 2>/dev/null)
if [ ! -z "$version" ]; then
echo "📦 버전: $version"
fi
else
echo "❌ Weaviate 응답 없음"
fi
}
EOF
# 설정 적용
source ~/.zshrc
사용 가능한 명령어들
설정 후 다음 명령어들을 사용할 수 있습니다:
weaviate-start
: Weaviate 시작weaviate-stop
: Weaviate 중지weaviate-status
: 실행 상태 확인weaviate-health
: 헬스체크 수행weaviate-test
: 테스트 스크립트 실행weaviate-check
: 빠른 상태 확인
실전 활용 시나리오
1. 문서 검색 시스템
class DocumentSearchSystem:
def __init__(self, client):
self.client = client
self.collection = client.collections.get("Document")
def add_document(self, title: str, content: str, metadata: dict):
"""문서 추가"""
vector = generate_embedding(f"{title} {content}")
self.collection.data.insert(
properties={
"title": title,
"content": content,
**metadata
},
vector=vector
)
def search_documents(self, query: str, limit: int = 5):
"""문서 검색"""
query_vector = generate_embedding(query)
return self.collection.query.near_vector(
near_vector=query_vector,
limit=limit,
return_metadata=weaviate.classes.query.MetadataQuery(distance=True)
)
2. 추천 시스템
class RecommendationSystem:
def __init__(self, client):
self.client = client
self.collection = client.collections.get("Product")
def find_similar_products(self, product_id: str, limit: int = 5):
"""유사 상품 추천"""
# 기준 상품의 벡터 가져오기
product = self.collection.query.fetch_object_by_id(product_id)
if product:
# 유사한 상품 검색
similar = self.collection.query.near_vector(
near_vector=product.vector,
limit=limit + 1 # 자기 자신 제외
)
# 자기 자신 제외하고 반환
return [obj for obj in similar.objects if obj.uuid != product_id]
return []
3. 질의응답 시스템
class QASystem:
def __init__(self, client):
self.client = client
self.collection = client.collections.get("KnowledgeBase")
def answer_question(self, question: str, context_limit: int = 3):
"""질문에 대한 답변 생성"""
# 관련 컨텍스트 검색
query_vector = generate_embedding(question)
contexts = self.collection.query.near_vector(
near_vector=query_vector,
limit=context_limit
)
# 컨텍스트 결합
combined_context = "\n".join([
obj.properties['content'] for obj in contexts.objects
])
# GPT에게 답변 요청 (실제 구현에서는 OpenAI API 사용)
answer = generate_answer(question, combined_context)
return {
"question": question,
"answer": answer,
"sources": [obj.properties['title'] for obj in contexts.objects]
}
고급 기능
멀티테넌시
# 테넌트별 데이터 분리
collection = client.collections.create_from_config({
"name": "MultiTenantCollection",
"multiTenancyConfig": {
"enabled": True
}
})
# 테넌트 생성
collection.tenants.create(
tenants=[
weaviate.classes.tenants.Tenant(name="tenant_a"),
weaviate.classes.tenants.Tenant(name="tenant_b")
]
)
# 테넌트별 데이터 삽입
collection.with_tenant("tenant_a").data.insert(properties={"title": "Tenant A Document"})
collection.with_tenant("tenant_b").data.insert(properties={"title": "Tenant B Document"})
지리적 검색
# 지리적 속성이 있는 컬렉션
geo_collection = client.collections.create(
name="LocationBasedService",
properties=[
weaviate.classes.config.Property(
name="name",
data_type=weaviate.classes.config.DataType.TEXT
),
weaviate.classes.config.Property(
name="location",
data_type=weaviate.classes.config.DataType.GEO_COORDINATES
)
]
)
# 위치 기반 검색
response = geo_collection.query.near_object(
near_object={"latitude": 37.5665, "longitude": 126.9780}, # 서울시청
distance=1000 # 1km 반경
)
모니터링과 최적화
성능 모니터링
def monitor_performance():
"""성능 모니터링"""
# 클러스터 상태 확인
cluster_stats = client.cluster.get_nodes_status()
print("클러스터 상태:", cluster_stats)
# 메모리 사용량 확인
meta = client.get_meta()
print("메모리 사용량:", meta.get('memory', 'Unknown'))
# 인덱스 상태 확인
schema = client.schema.get()
for class_config in schema['classes']:
print(f"클래스 {class_config['class']}: {class_config.get('vectorIndexConfig', {})}")
백업과 복원
# 데이터 백업
docker exec weaviate-container weaviate-cli backup create \
--backend filesystem \
--backup-id backup-$(date +%Y%m%d) \
--include Document,Article
# 데이터 복원
docker exec weaviate-container weaviate-cli backup restore \
--backend filesystem \
--backup-id backup-20250628
실제 테스트 결과 요약
이 튜토리얼에서 실행한 테스트들의 결과를 요약하면:
- ✅ 설치 성공: Docker를 통한 Weaviate 1.26.4 설치 완료
- ✅ 연결 성공: Python 클라이언트 4.15.4로 정상 연결
- ✅ 스키마 생성: Article 컬렉션 생성 및 HNSW 인덱스 설정 완료
- ✅ 데이터 삽입: 5개 샘플 아티클 배치 삽입 성공
- ✅ 벡터 검색: 의미적 유사성 기반 검색 정상 동작
- ✅ 하이브리드 검색: 벡터 + 키워드 검색 결합 성공
- ✅ 필터링 검색: 카테고리 기반 필터링 검색 구현
- ✅ 집계 쿼리: 카테고리별 데이터 집계 정상 동작
- ✅ 성능 측정: 평균 1.78ms의 빠른 검색 속도 확인
트러블슈팅
일반적인 문제들
- Docker 컨테이너 시작 실패
# 포트 충돌 확인 lsof -i :8080 # 컨테이너 로그 확인 docker-compose logs weaviate
- 메모리 부족 오류
# docker-compose.yml에 메모리 제한 추가 services: weaviate: deploy: resources: limits: memory: 4G
- Python 클라이언트 버전 충돌
# 클라이언트 재설치 pip3 uninstall weaviate-client pip3 install weaviate-client==4.15.4
다음 단계
Weaviate 기초를 익혔다면 다음 주제들을 학습해보세요:
- 외부 임베딩 모델 연동: OpenAI, Cohere, HuggingFace 임베딩 사용
- 생성형 AI 통합: GPT, Claude 등과 연동한 RAG 시스템 구축
- 멀티모달 검색: 텍스트, 이미지, 오디오 통합 검색
- 클러스터 구성: 고가용성과 확장성을 위한 멀티노드 설정
- 프로덕션 배포: Kubernetes, 클라우드 환경 배포 전략
결론
Weaviate는 차세대 AI 애플리케이션을 구축하는 데 필수적인 벡터 데이터베이스입니다. 전통적인 키워드 기반 검색의 한계를 넘어서 의미적 유사성을 기반으로 한 검색, 하이브리드 검색, 그리고 생성형 AI와의 완벽한 통합을 제공합니다.
이 튜토리얼을 통해 Weaviate의 핵심 기능들을 익혔다면, 이제 실제 프로젝트에서 강력한 AI 검색 시스템을 구축해보시기 바랍니다. 문서 검색, 추천 시스템, 질의응답 시스템 등 다양한 영역에서 Weaviate가 제공하는 혁신적인 검색 경험을 활용할 수 있을 것입니다.
특히 RAG(Retrieval-Augmented Generation) 시스템이나 의미적 검색이 중요한 애플리케이션에서 Weaviate의 진가를 발휘할 수 있으며, 밀리초 단위의 빠른 응답 속도와 뛰어난 확장성으로 프로덕션 환경에서도 안정적으로 운영할 수 있습니다.