벡터

벡터 (Vectors)

벡터(또는 임베딩)는 Qdrant 벡터 검색 엔진의 핵심 개념이에요. 벡터는 벡터 공간에서 객체들 간의 유사도를 정의해요.

벡터 공간에서 두 벡터가 비슷하다면, 그것이 나타내는 객체들이 어떤 면에서 비슷하다는 뜻이에요.

예를 들어 이미지 컬렉션이 있다고 해볼게요. 각 이미지를 벡터로 표현할 수 있어요. 두 이미지가 비슷하면 그 벡터도 벡터 공간에서 서로 가까이 있게 돼요.

객체의 벡터 표현을 얻으려면 객체에 **벡터화 알고리즘(vectorization)**을 적용해야 해요. 보통 이 알고리즘은 객체를 고정 크기 벡터로 변환하는 신경망이에요.

이 신경망은 보통 비슷한/비슷하지 않은 객체들의 쌍(pairs)이나 세 쌍(triplets)으로 학습되므로, 특정 유형의 유사도를 인식하는 법을 배워요.

벡터의 이 성질을 이용하면 데이터를 여러 방식으로 탐색할 수 있어요. 예를 들어 비슷한 객체를 검색하거나, 객체를 클러스터링하는 식이에요.

출처: Qdrant 공식 문서 — vectors

벡터 유형 (Vector Types)

현대 신경망은 다양한 모양과 크기의 벡터를 출력할 수 있고, Qdrant는 대부분을 지원해요. Qdrant가 지원하는 가장 흔한 벡터 유형들을 살펴볼게요.

Dense Vectors

가장 흔한 벡터 유형이에요. 단순한 숫자 리스트로, 고정 길이를 가지며 각 요소는 부동 소수점 수예요. 모양은 이렇게 생겼어요:

 // 실제 dense vector의 일부
 [
     -0.013052909,
     0.020387933,
     -0.007869,
     -0.11111383,
     -0.030188112,
     -0.0053388323,
     0.0010654867,
     0.072027855,
     -0.04167721,
     0.014839341,
     -0.032948174,
     -0.062975034,
     -0.024837125,
     ....
 ]

대부분의 신경망이 dense vector를 만들기 때문에 추가 처리 없이 Qdrant에서 바로 쓸 수 있어요. 대부분의 임베딩 모델과 호환되지만, Qdrant는 다음 검증된 임베딩 제공자(verified embedding providers)로 테스트됐어요.

Sparse Vectors

Sparse vector는 특수한 벡터 유형이에요. 수학적으로는 dense vector와 같지만, 0이 아주 많아서 특수 형식으로 저장돼요.

Qdrant의 sparse vector는 고정 길이가 없어요. 벡터 삽입 시 동적으로 할당되기 때문이에요. Sparse vector의 비-영(non-zero) 값 개수는 현재 u32 데이터 타입 범위(4294967295)로 제한돼요.

Sparse vector를 정의하려면 비-영 요소들과 그 인덱스를 제공해야 해요:

 // 비-영 요소가 4개인 sparse vector
 {
     "indexes": [1, 3, 5, 7],
     "values": [0.1, 0.2, 0.3, 0.4]
 }

Qdrant의 sparse vector는 특수 저장소에 보관되고 별도 인덱스에서 인덱싱되므로, dense vector와 설정이 달라요.

Sparse vector가 있는 컬렉션을 만들려면:

 PUT /collections/{collection_name}
 {
     "sparse_vectors": {
         "text": { }
     }
 }
 from qdrant_client import QdrantClient, models

 client = QdrantClient(url="http://localhost:6333")

 client.create_collection(
     collection_name="{collection_name}",
     vectors_config={},
     sparse_vectors_config={
         "text": models.SparseVectorParams(),
     },
 )
 import { QdrantClient } from "@qdrant/js-client-rest";

 const client = new QdrantClient({ host: "localhost", port: 6333 });

 client.createCollection("{collection_name}", {
   sparse_vectors: {
     text: { },
   },
 });
 use qdrant_client::Qdrant;
 use qdrant_client::qdrant::{
     SparseVectorParamsBuilder, SparseVectorsConfigBuilder,
 };

 let client = Qdrant::from_url("http://localhost:6334").build()?;

 let mut sparse_vector_config = SparseVectorsConfigBuilder::default();
 sparse_vector_config.add_named_vector_params("text", SparseVectorParamsBuilder::default());

 client
     .create_collection(
         CreateCollectionBuilder::new("{collection_name}")
             .sparse_vectors_config(sparse_vector_config),
     )
     .await?;

생성된 컬렉션에 sparse vector가 있는 포인트를 삽입할 수 있어요:

 from qdrant_client import QdrantClient, models

 client = QdrantClient(url="http://localhost:6333")

 client.upsert(
     collection_name="{collection_name}",
     points=[
         models.PointStruct(
             id=1,
             payload={},  # 필요한 경우 추가 페이로드
             vector={
                 "text": models.SparseVector(
                     indices=[1, 3, 5, 7],
                     values=[0.1, 0.2, 0.3, 0.4]
                 )
             },
         )
     ],
 )
 PUT /collections/{collection_name}/points
 {
     "points": [
         {
             "id": 1,
             "vector": {
                 "text": {
                     "indices": [1, 3, 5, 7],
                     "values": [0.1, 0.2, 0.3, 0.4]
                 }
             }
         }
     ]
 }

이제 sparse vector로 검색을 실행할 수 있어요:

 POST /collections/{collection_name}/points/query
 {
     "query": {
         "indices": [1, 3, 5, 7],
         "values": [0.1, 0.2, 0.3, 0.4]
     },
     "using": "text"
 }
 from qdrant_client import QdrantClient, models

 client = QdrantClient(url="http://localhost:6333")

 result = client.query_points(
     collection_name="{collection_name}",
     query=models.SparseVector(indices=[1, 3, 5, 7], values=[0.1, 0.2, 0.3, 0.4]),
     using="text",
 ).points
 import { QdrantClient } from "@qdrant/js-client-rest";

 const client = new QdrantClient({ host: "localhost", port: 6333 });

 client.query("{collection_name}", {
     query: {
         indices: [1, 3, 5, 7],
         values: [0.1, 0.2, 0.3, 0.4]
     },
     using: "text",
     limit: 3,
 });

Named Vectors

같은 데이터 포인트에 서로 다른 크기와 유형의 벡터 여러 개를 저장할 수 있어요. 서로 다른 특징이나 모달리티(예: 이미지, 텍스트, 비디오)를 나타내기 위해 여러 임베딩으로 데이터를 정의해야 할 때 유용해요.

예를 들어 클러스터링용으로 여러 임베딩을 쓰거나, 하이브리드 검색(dense + sparse)을 위해 이름 붙인 벡터들을 함께 두는 식이에요. 각 벡터는 using 파라미터로 이름을 지정해 검색에 사용할 수 있어요.

벡터 데이터 타입 (Datatypes)

벡터 저장에 사용하는 데이터 타입을 지정할 수 있어요. dense vector는 float32(기본), float16, uint8 등을 지원하고, sparse vector는 인덱스의 데이터 타입을 지정할 수 있어요. 예를 들어 저장 공간을 줄이려면 float16을 쓸 수 있어요:

 PUT /collections/{collection_name}
 {
   "vectors": {
     "size": 128,
     "distance": "Cosine",
     "datatype": "float16" // <-- Dense vector용
   },
   "sparse_vectors": {
     "text": {
       "index": {
         "datatype": "float16" // <-- Sparse vector용
       }
     }
   }
 }
 from qdrant_client import QdrantClient, models

 client = QdrantClient(url="http://localhost:6333")

 client.create_collection(
     collection_name="{collection_name}",
     vectors_config=models.VectorParams(
         size=128,
         distance=models.Distance.COSINE,
         datatype=models.Datatype.FLOAT16
     ),
     sparse_vectors_config={
         "text": models.SparseVectorParams(
             index=models.SparseIndexParams(datatype=models.Datatype.FLOAT16)
         ),
     },
 )
 import { QdrantClient } from "@qdrant/js-client-rest";

 const client = new QdrantClient({ host: "localhost", port: 6333 });

 client.createCollection("{collection_name}", {
   vectors: {
     size: 128,
     distance: "Cosine",
     datatype: "float16"
   },
   sparse_vectors: {
     text: {
       index: {
         datatype: "float16"
       }
     }
   }
 });

더 알아보기 (Learn more)