인덱싱

인덱싱 (Indexing)

Qdrant의 핵심 특징 중 하나는 벡터 인덱스와 전통적 인덱스를 효과적으로 결합한다는 점이에요. 벡터 검색이 필터와 함께 잘 동작하려면 벡터 인덱스만으로는 부족하거든요. 쉽게 말하면, 벡터 인덱스는 벡터 검색을 빠르게 하고, 페이로드(payload) 인덱스는 필터링을 빠르게 해요.

인덱스들은 세그먼트(segment)마다 독립적으로 존재하지만, 인덱스 자체의 파라미터는 컬렉션 전체에 대해 설정돼요.

모든 세그먼트가 자동으로 인덱스를 갖는 건 아니에요. 인덱스의 필요성은 옵티마이저 설정이 결정하는데, 보통 저장된 포인트 수에 따라 달라져요.

출처: Qdrant 공식 문서 — indexing

페이로드 인덱스 (Payload Index)

Qdrant의 페이로드 인덱스는 일반적인 문서 지향 데이터베이스의 인덱스와 비슷해요. 특정 필드와 타입에 대해 만들어지고, 해당 필터링 조건으로 포인트를 빠르게 요청하는 데 사용돼요. 이 인덱스는 필터 카디널리티를 정확하게 추정하는 데도 쓰여서, 쿼리 플래닝이 검색 전략을 고르는 데 도움을 줘요.

인덱스를 만드는 데는 추가적인 컴퓨팅 자원과 메모리가 필요하므로, 어떤 필드를 인덱싱할지 고르는 일이 중요해요. Qdrant는 이 선택을 대신 해주지 않고 사용자에게 맡겨요.

다음 필드 타입들이 페이로드 인덱싱을 지원해요:

  • keywordkeyword 페이로드용. Match 필터링 조건에 영향. 선택적으로 접두사 매칭(prefix matching) 활성화 가능.
  • integerinteger 페이로드용. MatchRange 필터링 조건에 영향.
  • floatfloat 페이로드용. Range 필터링 조건에 영향.
  • boolbool 페이로드용. Match 필터링 조건에 영향 (v1.4.0부터 사용 가능).
  • geogeo 페이로드용. Geo Bounding BoxGeo Radius 필터링 조건에 영향.
  • datetimedatetime 페이로드용. Range 필터링 조건에 영향 (v1.8.0부터 사용 가능).
  • textkeyword / string 페이로드에 사용 가능한 특수 인덱스. 전문 검색(Full Text search) 필터링 조건에 영향. text 인덱스 설정에 대해 더 알아보기.
  • uuidkeyword와 비슷하지만 UUID 값에 최적화된 특수 타입. Match 필터링 조건에 영향 (v1.11.0부터 사용 가능).

페이로드 인덱스는 추가 메모리와 디스크 공간을 차지하므로, 필터링 조건에 실제로 쓰는 필드에만 적용하는 걸 권장해요. 필터링할 필드가 많고 메모리 한도가 모두 인덱싱할 수 없는 수준이라면, 검색 결과를 가장 많이 제한하는 필드를 고르는 게 좋아요. 일반적으로 페이로드 값이 가질 수 있는 서로 다른 값이 많을수록 인덱스가 더 효율적으로 쓰여요.

페이로드 인덱스 만들기

필드에 페이로드 인덱스를 만들려면:

 PUT /collections/{collection_name}/index
 {
   "field_name": "name_of_the_field_to_index",
   "field_schema": "keyword"
 }
 client . create_payload_index (
     collection_name = " {collection_name} " ,
     field_name = "name_of_the_field_to_index" ,
     field_schema = models . PayloadSchemaType . KEYWORD ,
 )
 client . createPayloadIndex ( "{collection_name}" , {
   field_name : "name_of_the_field_to_index" ,
   field_schema : "keyword" ,
 });
 use qdrant_client :: qdrant :: { CreateFieldIndexCollectionBuilder , FieldType };
 client . create_field_index (
     CreateFieldIndexCollectionBuilder :: new ( "{collection_name}" , "name_of_the_field_to_index" , FieldType :: Keyword , )
         . wait ( true ),
 ) . await ? ;
 import io.qdrant.client.grpc.Collections.PayloadSchemaType ;
 client . createPayloadIndexAsync ( "{collection_name}" , "name_of_the_field_to_index" , PayloadSchemaType . Keyword , null , true , null , null );
 using Qdrant.Client ;
 var client = new QdrantClient ( "localhost" , 6334 );
 await client . CreatePayloadIndexAsync (
     collectionName : "{collection_name}" ,
     fieldName : "name_of_the_field_to_index" );
 import (
     "context"
     "github.com/qdrant/go-client/qdrant"
 )
 client , err := qdrant . NewClient ( & qdrant . Config { Host : "localhost" , Port : 6334 , })
 client . CreateFieldIndex ( context . Background (), & qdrant . CreateFieldIndexCollection {
     CollectionName : "{collection_name}" ,
     FieldName : "name_of_the_field_to_index" ,
     FieldType : qdrant . FieldType_FieldTypeKeyword . Enum (),
 })

중첩 필드를 지정할 때는 점 표기법(dot notation)을 쓸 수 있어요. nested filter 지정 방식과 비슷해요.

페이로드 키 자체가 열려 있는(open-ended) 경우, 각 키를 따로 인덱싱하는 방식은 확장되지 않아요. 키들을 고정 필드 아래의 값으로 재구성하고 컬렉션 설정 시점에 인덱싱하세요. 관련 모델링 패턴은 무작위 형태의 페이로드 인덱싱을 참고해요.

페이로드 인덱스는 데이터를 넣기 전에 만들어야 해요. Qdrant의 필터 가능한 HNSW 인덱스는 페이로드 인덱스가 먼저 만들어진 후에야 필터 인지 엣지(filter-aware edges)를 활용할 수 있어요. 데이터를 이미 넣은 뒤 페이로드 인덱스를 만들었다면, 새 페이로드 인덱스를 활용하려면 HNSW 인덱스를 다시 구축해야 해요.

인덱스되지 않은 필드로 필터링하는 쿼리 차단하기

인덱스되지 않은 필드로 필터링하는 쿼리는 느릴 뿐만 아니라, 클러스터 리소스를 불필요하게 소모해서 다른 검색 쿼리의 지연 시간까지 악화시킬 수 있어요. Qdrant는 이를 막기 위해 인덱스되지 않은 필드로 필터링하는 쿼리를 차단하는 옵션을 제공해요. 여기서 얻는 이점:

  • Fail-fast 동작 — 성능을 떨어뜨릴 쿼리가 API 경계에서 거부되어, 설정이 잘못된 인덱스가 지연 스파이크가 아니라 오류로 표면화됨.
  • 성능 보장 — 성공하는 모든 쿼리가 인덱스에 의해 뒷받침되어, 인덱스되지 않은 필드에 대한 실수 필터가 프로덕션에 도달하는 것을 방지.
  • 운영 가시성 — 엄격 모드가 없으면 인덱스 누락이 오랫동안 눈에 띄지 않을 수 있음. 쿼리가 여전히 (느리지만) 결과를 반환하니까.

인덱스되지 않은 필드로 필터링하는 쿼리를 차단하려면 strict mode를 켜고 unindexed_filtering_retrievefalse로 설정하세요. 그러면 검색 쿼리가 인덱스되지 않은 필드로 필터링하려 할 때 Qdrant가 오류를 반환해요. Qdrant Cloud에서는 이 설정이 기본적으로 모든 컬렉션에 적용돼요.

자세한 내용은 인덱스되지 않은 페이로드로 검색 비활성화를 참고하세요.

파라미터화된 인덱스 (Parameterized Index)

필드 타입을 고르는 것 외에도, 페이로드 인덱스에 파라미터를 설정해서 저장 방식과 지원할 필터링 조건을 세밀하게 조정할 수 있어요. 사용 가능한 파라미터는 필드 타입에 따라 달라지며 아래 하위 섹션에서 설명해요.

정수 인덱스에서 lookuprange 사용하기

v1.8.0부터 사용 가능

integer 인덱스의 파라미터화 버전은 인덱싱과 검색 성능을 세밀하게 조정할 수 있게 해줘요.

파라미터화된 integer 인덱스는 다음 플래그를 사용해요:

  • lookupMatch 필터를 이용한 직접 조회(direct lookup) 지원.
  • rangeRange 필터 지원.

integer 인덱스는 기본적으로 lookuprange가 모두 true라고 가정해요. 파라미터화된 인덱스를 구성하려면 이 두 필터 중 하나만 true로 설정하세요:

lookup range 결과
true true 정수 인덱스의 기본 동작
true false 파라미터화된 정수 인덱스
false true 파라미터화된 정수 인덱스
false false 정수 인덱스 없음

lookup이나 rangefalse로 설정하면 대규모 컬렉션에서 메모리 사용량을 조정하고 줄이는 데 도움이 될 수 있어요. 둘 중 하나를 false로 설정했을 때 메모리가 개선되는지 시도해 보세요. 개선이 없거나 어떤 종류의 페이로드 필터를 쓰는지 확실하지 않다면, 일반 integer 인덱스를 사용하세요.

참고: "range": false로 두고 여전히 range 필터를 사용하면 상당한 성능 문제가 생길 수 있어요. lookup 파라미터와 해당 필터도 마찬가지예요.

예를 들어, 다음 코드는 range 필터만 지원하는 파라미터화된 정수 인덱스를 설정해요:

 PUT /collections/{collection_name}/index
 {
   "field_name": "name_of_the_field_to_index",
   "field_schema": {
     "type": "integer",
     "lookup": false,
     "range": true
   }
 }
 from qdrant_client import QdrantClient , models
 client = QdrantClient ( url = "http://localhost:6333" )
 client . create_payload_index (
     collection_name = " {collection_name} " ,
     field_name = "name_of_the_field_to_index" ,
     field_schema = models . IntegerIndexParams (
         type = models . IntegerIndexType . INTEGER ,
         lookup = False ,
         range = True ,
     ),
 )
 import { QdrantClient } from "@qdrant/js-client-rest" ;
 const client = new QdrantClient ({ host : "localhost" , port : 6333 });
 client . createPayloadIndex ( "{collection_name}" , {
   field_name : "name_of_the_field_to_index" ,
   field_schema : {
     type : "integer" ,
     lookup : false ,
     range : true ,
   },
 });
 use qdrant_client :: Qdrant ;
 use qdrant_client :: qdrant :: { CreateFieldIndexCollectionBuilder , FieldType , IntegerIndexParamsBuilder , };
 let client = Qdrant :: from_url ( "http://localhost:6334" ). build () ? ;
 client . create_field_index (
     CreateFieldIndexCollectionBuilder :: new ( "{collection_name}" , "name_of_the_field_to_index" , FieldType :: Integer , )
         . field_index_params ( IntegerIndexParamsBuilder :: new ( false , true ). build ()),
 ) . await ? ;

text 인덱스: keyword/string 페이로드에 대한 특수 인덱스로, 토크나이저와 stopwords 설정을 파라미터로 지정할 수 있어요. 예:

 client . create_payload_index (
     collection_name = " {collection_name} " ,
     field_name = "name_of_the_field_to_index" ,
     field_schema = models . TextIndexParams (
         type = "text" ,
         tokenizer = models . TokenizerType . WORD ,
         stopwords = models . StopwordsSet ( languages = [ "english" , "spanish" ], custom = [ "example" ]),
     ),
 )

더 알아보기 (Learn more)