Qdrant 벡터 스토어
Qdrant 벡터 스토어 (Spring AI)
고성능 벡터 검색 엔진이 필요하다면 Qdrant가 강력한 선택이에요. 이 글은 Qdrant VectorStore를 설정해서 문서 임베딩을 저장하고 유사도 검색을 수행하는 과정을 안내해요.
Qdrant는 오픈소스 고성능 벡터 검색 엔진/데이터베이스예요. 효율적인 k-NN 검색 연산을 위해 HNSW(Hierarchical Navigable Small World) 알고리즘을 사용하고, 메타데이터 기반 쿼리를 위한 고급 필터링 기능을 제공해요.
사전 준비 (Prerequisites)
- Qdrant 인스턴스: Qdrant 문서의 설치 지침을 따라 Qdrant 인스턴스를 설정해요.
- 필요한 경우
QdrantVectorStore에 저장할 임베딩을 생성하는EmbeddingModel용 API 키를 준비해요.
참고: Qdrant 컬렉션은 적절한 차원과 구성으로 미리 만들어 두는 걸 권장해요. 컬렉션이 없으면
QdrantVectorStore가Cosine유사도와 설정된EmbeddingModel의 차원으로 컬렉션을 만들려고 시도해요.
자동 설정 (Auto-configuration)
중요: Spring AI 자동 설정과 스타터 모듈의 아티팩트 이름에 큰 변화가 있었어요. 자세한 내용은 upgrade notes를 확인해 주세요.
Spring AI는 Qdrant 벡터 스토어용 Spring Boot 자동 설정을 제공해요. 활성화하려면 Maven pom.xml에 다음 의존성을 추가해요.
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-vector-store-qdrant</artifactId>
</dependency>
또는 Gradle build.gradle 파일에 이렇게 넣어요.
dependencies {
implementation 'org.springframework.ai:spring-ai-starter-vector-store-qdrant'
}
참고: 스프링 AI BOM은 Dependency Management, Maven Central/Snapshot 저장소 추가는 Artifact Repositories 섹션을 참고해요.
벡터 스토어의 기본값과 설정 옵션은 아래 configuration parameters 목록을 참고해 주세요.
벡터 스토어 구현이 필요한 스키마를 직접 초기화해 줄 수 있지만, 반드시 옵트인해야 해요. 빌더에서 initializeSchema 불리언을 지정하거나 application.properties에 ...initialize-schema=true를 설정하면 돼요.
중요: 이것은 breaking change예요! 이전 버전의 Spring AI에서는 이 스키마 초기화가 기본으로 동작했어요.
또한 설정된 EmbeddingModel 빈이 필요해요. EmbeddingModel 섹션을 참고해 주세요.
이제 애플리케이션에서 QdrantVectorStore를 벡터 스토어로 오토와이어해서 사용할 수 있어요.
@Autowired VectorStore vectorStore;
// ...
List<Document> documents = List.of(
new Document("Spring AI rocks!! Spring AI rocks!! Spring AI rocks!! Spring AI rocks!! Spring AI rocks!!", Map.of("meta1", "meta1")),
new Document("The World is Big and Salvation Lurks Around the Corner"),
new Document("You walk forward facing the past and you turn back toward the future.", Map.of("meta2", "meta2")));
// Add the documents to Qdrant
vectorStore.add(documents);
// Retrieve documents similar to a query
List<Document> results = vectorStore.similaritySearch(SearchRequest.builder().query("Spring").topK(5).build());
설정 프로퍼티
Qdrant에 연결하고 QdrantVectorStore를 사용하려면 인스턴스 접근 정보를 제공해야 해요. Spring Boot의 application.yml로 간단히 설정할 수 있어요.
spring:
ai:
vectorstore:
qdrant:
host: <qdrant host>
port: <qdrant grpc port>
api-key: *** api key>
collection-name: <collection name>
content-field-name: <content field name>
use-tls: false
initialize-schema: true
spring.ai.vectorstore.qdrant.*로 시작하는 프로퍼티가 QdrantVectorStore를 구성해요.
| Property | Description | Default Value |
|---|---|---|
spring.ai.vectorstore.qdrant.host |
The host of the Qdrant server | localhost |
spring.ai.vectorstore.qdrant.port |
The gRPC port of the Qdrant server | 6334 |
spring.ai.vectorstore.qdrant.api-key |
The API key to use for authentication | - |
spring.ai.vectorstore.qdrant.collection-name |
The name of the collection to use | vector_store |
spring.ai.vectorstore.qdrant.content-field-name |
The name of the field storing document content in Qdrant payloads. Useful when integrating with existing collections that use different field names (e.g., "page_content", "text", "content"). | doc_content |
spring.ai.vectorstore.qdrant.use-tls |
Whether to use TLS(HTTPS) | false |
spring.ai.vectorstore.qdrant.initialize-schema |
Whether to initialize the schema | false |
수동 설정 (Manual Configuration)
Spring Boot 자동 설정 대신 Qdrant 벡터 스토어를 수동으로 구성할 수도 있어요. 그러려면 spring-ai-qdrant-store를 프로젝트에 추가해야 해요.
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-qdrant-store</artifactId>
</dependency>
또는 Gradle build.gradle 파일에 이렇게 넣어요.
dependencies {
implementation 'org.springframework.ai:spring-ai-qdrant-store'
}
참고: 스프링 AI BOM을 빌드 파일에 추가하는 방법은 Dependency Management 섹션을 참고해요.
Qdrant 클라이언트 빈을 만들어요.
@Bean
public QdrantClient qdrantClient() {
QdrantGrpcClient.Builder grpcClientBuilder =
QdrantGrpcClient.newBuilder(
"<QDRANT_HOSTNAME>",
<QDRANT_GRPC_PORT>,
<IS_TLS>);
grpcClientBuilder.withApiKey("<QDRANT_API_KEY>");
return new QdrantClient(grpcClientBuilder.build());
}
그런 다음 빌더 패턴으로 QdrantVectorStore 빈을 만들어요.
@Bean
public VectorStore vectorStore(QdrantClient qdrantClient, EmbeddingModel embeddingModel) {
return QdrantVectorStore.builder(qdrantClient, embeddingModel)
.collectionName("custom-collection") // Optional: defaults to "vector_store"
.contentFieldName("page_content") // Optional: defaults to "doc_content"
.initializeSchema(true) // Optional: defaults to false
.batchingStrategy(new TokenCountBatchingStrategy()) // Optional: defaults to TokenCountBatchingStrategy
.build();
}
// This can be any EmbeddingModel implementation
@Bean
public EmbeddingModel embeddingModel() {
return new OpenAiEmbeddingModel(OpenAiEmbeddingOptions.builder().apiKey(System.getenv("OPENAI_API_KEY")).build());
}
기존 컬렉션 작업 (Working with Existing Collections)
Spring AI를 기존 Qdrant 컬렉션과 통합할 때는 이미 사용 중인 스키마에 맞게 콘텐츠 필드 이름을 구성해야 할 수 있어요.
기본적으로 QdrantVectorStore는 문서 콘텐츠를 doc_content라는 필드에 저장해요. 하지만 기존 컬렉션은 page_content, text, content 같은 다른 명명 규칙을 쓸 수도 있어요.
커스텀 콘텐츠 필드 이름 사용
기존 컬렉션 스키마에 맞게 콘텐츠 필드 이름을 구성할 수 있어요.
프로퍼티로:
spring:
ai:
vectorstore:
qdrant:
collection-name: my_existing_collection
content-field-name: page_content # Match existing schema
프로그래밍 방식으로:
@Bean
public VectorStore vectorStore(QdrantClient qdrantClient, EmbeddingModel embeddingModel) {
return QdrantVectorStore.builder(qdrantClient, embeddingModel)
.collectionName("my_existing_collection")
.contentFieldName("text") // Use existing field name
.initializeSchema(false) // Don't recreate existing schema
.build();
}
메타데이터 필터링 (Metadata Filtering)
Qdrant 스토어에서도 일반적이고 이식 가능한 metadata filters를 활용할 수 있어요.
예를 들어 텍스트 표현 언어로 필터링할 수 있고,
vectorStore.similaritySearch(
SearchRequest.builder()
.query("The World")
.topK(TOP_K)
.similarityThreshold(SIMILARITY_THRESHOLD)
.filterExpression("author in ['john', 'jill'] && article_type == 'blog'").build());
Filter.Expression DSL로 프로그래밍 방식으로도 필터링할 수 있어요.
FilterExpressionBuilder b = new FilterExpressionBuilder();
vectorStore.similaritySearch(SearchRequest.builder()
.query("The World")
.topK(TOP_K)
.similarityThreshold(SIMILARITY_THRESHOLD)
.filterExpression(b.and(
b.in("author", "john", "jill"),
b.eq("article_type", "blog")).build()).build());
참고: 이 (이식 가능한) 필터 표현식들은 Qdrant 고유의 filter expressions로 자동 변환돼요.
네이티브 클라이언트 접근
Qdrant 벡터 스토어 구현은 getNativeClient() 메서드를 통해 내부의 네이티브 Qdrant 클라이언트(QdrantClient)에 접근할 수 있게 해 줘요.
QdrantVectorStore vectorStore = context.getBean(QdrantVectorStore.class);
Optional<QdrantClient> nativeClient = vectorStore.getNativeClient();
if (nativeClient.isPresent()) {
QdrantClient client = nativeClient.get();
// Use the native client for Qdrant-specific operations
}
네이티브 클라이언트는 VectorStore 인터페이스로 노출되지 않는 Qdrant 고유 기능과 연산에 접근할 수 있게 해 줘요.