Skip to main content
Vectors are the core data type in Qdrant, representing embeddings generated by machine learning models. Qdrant supports multiple vector types to accommodate different use cases.

Vector Types

Qdrant supports three main vector types:

Dense Vectors

The most common vector type - fixed-size arrays of floating-point numbers:
from qdrant_client import QdrantClient, models

client = QdrantClient("localhost", port=6333)

# Create collection with dense vectors
client.create_collection(
    collection_name="documents",
    vectors_config=models.VectorParams(
        size=384,  # Vector dimensionality
        distance=models.Distance.COSINE
    )
)

# Insert points with dense vectors
client.upsert(
    collection_name="documents",
    points=[
        models.PointStruct(
            id=1,
            vector=[0.05, 0.61, 0.76, 0.74, ...],  # 384 dimensions
            payload={"text": "example document"}
        )
    ]
)
// From lib/segment/src/data_types/vectors.rs:253-264
pub type VectorElementType = f32;
pub type DenseVector = TypedDenseVector<VectorElementType>;
Dense vectors are ideal for embeddings from models like OpenAI, Cohere, Sentence Transformers, and CLIP.

Sparse Vectors

High-dimensional vectors where most values are zero, stored efficiently:
# Create collection with sparse vectors
client.create_collection(
    collection_name="hybrid_search",
    vectors_config=models.VectorParams(
        size=384,
        distance=models.Distance.COSINE
    ),
    sparse_vectors_config={
        "text": models.SparseVectorParams(
            index=models.SparseIndexParams()
        )
    }
)

# Insert points with sparse vectors
client.upsert(
    collection_name="hybrid_search",
    points=[
        models.PointStruct(
            id=1,
            vector={
                "dense": [0.1, 0.2, 0.3, ...],
                "text": models.SparseVector(
                    indices=[10, 45, 98, 234, 567],  # Non-zero dimensions
                    values=[0.5, 0.3, 0.8, 0.2, 0.4]  # Corresponding values
                )
            },
            payload={"text": "sparse vector example"}
        )
    ]
)
Sparse vectors are perfect for:
  • BM25-style keyword search
  • TF-IDF representations
  • SPLADE embeddings
  • Hybrid dense + sparse search

Multi-Vectors (ColBERT-style)

Multiple dense vectors per point, useful for token-level embeddings:
# Create collection with multi-vector support
client.create_collection(
    collection_name="colbert_search",
    vectors_config={
        "text": models.VectorParams(
            size=128,
            distance=models.Distance.COSINE,
            multivector_config=models.MultiVectorConfig(
                comparator=models.MultiVectorComparator.MAX_SIM
            )
        )
    }
)

# Insert points with multiple vectors
client.upsert(
    collection_name="colbert_search",
    points=[
        models.PointStruct(
            id=1,
            vector={
                "text": [
                    [0.1, 0.2, ...],  # Token 1 embedding
                    [0.3, 0.4, ...],  # Token 2 embedding
                    [0.5, 0.6, ...]   # Token 3 embedding
                ]
            },
            payload={"text": "multi-vector example"}
        )
    ]
)
// From lib/segment/src/types.rs:1542-1546
pub struct MultiVectorConfig {
    /// How to compare multivector points
    pub comparator: MultiVectorComparator,
}
Multi-vectors enable ColBERT-style search where documents are split into multiple token embeddings for fine-grained matching.

Named Vectors

Store multiple vector types in the same point for multimodal search:
# Create collection with named vectors
client.create_collection(
    collection_name="multimodal",
    vectors_config={
        "image": models.VectorParams(
            size=512,
            distance=models.Distance.COSINE
        ),
        "text": models.VectorParams(
            size=384,
            distance=models.Distance.COSINE
        ),
        "audio": models.VectorParams(
            size=256,
            distance=models.Distance.DOT
        )
    }
)

# Insert multimodal points
client.upsert(
    collection_name="multimodal",
    points=[
        models.PointStruct(
            id=1,
            vector={
                "image": [0.1, 0.2, ...],  # 512-dim CLIP image embedding
                "text": [0.3, 0.4, ...],   # 384-dim text embedding
                "audio": [0.5, 0.6, ...]   # 256-dim audio embedding
            },
            payload={
                "title": "Multimodal content",
                "type": "video"
            }
        )
    ]
)

# Search using specific vector
results = client.search(
    collection_name="multimodal",
    query_vector=("image", [0.1, 0.2, ...]),
    limit=10
)
// From lib/segment/src/data_types/vectors.rs:259-260
pub const DEFAULT_VECTOR_NAME: &VectorName = "";
Named vectors are ideal for:
  • Cross-modal search (text-to-image, image-to-text)
  • Multimodal retrieval
  • Multiple embedding models per document
  • A/B testing different embeddings

Vector Storage Configuration

Control how vectors are stored for optimal performance:
client.create_collection(
    collection_name="optimized",
    vectors_config=models.VectorParams(
        size=768,
        distance=models.Distance.COSINE,
        on_disk=False  # Store in RAM for best performance
    )
)
// From lib/segment/src/types.rs:1492-1513
pub enum VectorStorageType {
    Memory,              // In RAM - fastest
    Mmap,                // Memory-mapped file
    ChunkedMmap,         // Chunked memory-mapped, appendable
    InRamChunkedMmap,    // Locked in RAM, no disk access
    InRamMmap,           // Pre-fetched into RAM on load
}
Fastest option. All vectors stored in RAM. Best for:
  • Small to medium datasets (< available RAM)
  • Maximum query performance
  • Real-time applications
Balanced option. OS manages memory/disk swapping. Best for:
  • Large datasets (> available RAM)
  • Cost-effective deployments
  • Acceptable query latency
Appendable memory-mapped storage. Best for:
  • Growing collections
  • Continuous ingestion
  • Disk-based storage with good performance

Vector Datatype Configuration

Qdrant supports different storage precision levels:
client.create_collection(
    collection_name="compressed",
    vectors_config=models.VectorParams(
        size=768,
        distance=models.Distance.COSINE,
        datatype=models.Datatype.FLOAT16  # Half precision
    )
)
// From lib/segment/src/types.rs:1528-1536
pub enum VectorStorageDatatype {
    Float32,  // Single-precision (default)
    Float16,  // Half-precision
    Uint8,    // Unsigned 8-bit integer
}
DatatypeMemoryPrecisionUse Case
Float324 bytes/dimFullDefault, best accuracy
Float162 bytes/dimHalf50% memory savings, minimal accuracy loss
Uint81 byte/dimLow75% memory savings, requires quantization
Reducing datatype precision saves memory but may reduce search quality. Always benchmark with your data.

Vector Dimensions

Common embedding model dimensions:
ModelDimensionsDistance
OpenAI text-embedding-3-small1536Cosine
OpenAI text-embedding-3-large3072Cosine
Cohere embed-english-v3.01024Cosine
Sentence Transformers (all-MiniLM-L6-v2)384Cosine
CLIP ViT-B/32512Cosine
BGE-large-en-v1.51024Cosine
Vector dimensions must match your embedding model exactly. Qdrant validates this during insertion.

Sparse Vector Configuration

Configure sparse vector indexing:
client.create_collection(
    collection_name="sparse_collection",
    sparse_vectors_config={
        "bm25": models.SparseVectorParams(
            index=models.SparseIndexParams(
                full_scan_threshold=10000,
                on_disk=False
            )
        )
    }
)
// From lib/segment/src/types.rs:1681-1697
pub struct SparseVectorDataConfig {
    pub index: SparseIndexConfig,
    pub storage_type: SparseVectorStorageType,
    pub modifier: Option<Modifier>,
}
Sparse vectors automatically use an inverted index structure optimized for high-dimensional sparse data.

Multi-Vector Comparators

Control how multi-vectors are compared:
// From lib/segment/src/types.rs:1562-1565
pub enum MultiVectorComparator {
    MaxSim,  // Maximum similarity across all vectors
}
MaxSim: Computes similarity between each query vector and each document vector, returns the maximum. This is the ColBERT approach.

Vector Preprocessing

Normalization

For Cosine distance, normalize vectors:
import numpy as np

def normalize_vector(vector):
    """Normalize vector to unit length"""
    norm = np.linalg.norm(vector)
    if norm == 0:
        return vector
    return vector / norm

vector = [0.1, 0.2, 0.3]
normalized = normalize_vector(vector)

client.upsert(
    collection_name="my_collection",
    points=[
        models.PointStruct(
            id=1,
            vector=normalized.tolist(),
            payload={"text": "example"}
        )
    ]
)
Some embedding models return pre-normalized vectors. Check your model’s documentation before normalizing.

Best Practices

Always use the same vector dimensions, distance metric, and normalization as your embedding model was trained with.
For documents longer than your model’s context window, use multi-vectors to preserve fine-grained information.
For large collections, use Float16 datatype and on-disk storage to reduce memory usage.
When working with multiple data types (text, images, audio), use named vectors to keep embeddings organized.

Collections

Learn how collections configure vector storage

Points

Understand how vectors are stored in points

Distance Metrics

Deep dive into distance metrics for vector comparison

Indexing

Explore how vectors are indexed for fast search