How the VectorDbContext Class Implements Qdrant Vector Database Operations

The VectorDbContext class in NekoImageGallery serves as a complete abstraction layer over Qdrant, handling client initialization, collection lifecycle, CRUD operations, and hybrid search with RRF fusion while translating between domain MappedImage models and Qdrant PointStruct objects.

The VectorDbContext class is the core service in the hv0905/nekoimagegallery repository that manages all vector database interactions. Located in app/Services/vector_db_context.py, this implementation provides a robust async interface to Qdrant, supporting multiple deployment modes and complex multi-vector search strategies.

Client Selection and Connection Management

The class initializes the Qdrant client based on the config.qdrant.mode setting, supporting three distinct deployment scenarios. In app/Services/vector_db_context.py at lines 31-41, a match statement selects between server, local, or in-memory instances:

match config.qdrant.mode:
    case QdrantMode.SERVER:
        self._client = QdrantClient(host=config.qdrant.host, port=config.qdrant.port)
    case QdrantMode.LOCAL:
        self._client = AsyncQdrantClient(path=config.qdrant.path)
    case QdrantMode.MEMORY:
        self._client = AsyncQdrantClient(":memory:")

The selected client is wrapped with retry decorators to ensure resilience against transient network failures. This design allows the gallery application to run against a remote Qdrant cluster, a local persistent instance, or an ephemeral in-memory database for testing.

Collection Lifecycle and Schema Setup

On application startup, the on_load() method triggers check_collection() and initialize_collection() to ensure the target collection exists with the correct schema. The implementation creates a collection with two vector fields at lines 36-46:

  • image_vector: 768-dimensional float vectors using cosine distance for visual similarity
  • text_contain_vector: 768-dimensional float vectors using cosine distance for OCR text content
await self._client.create_collection(
    collection_name=self._config.qdrant.coll,
    vectors_config={
        self.IMG_VECTOR: models.VectorParams(size=768, distance=models.Distance.COSINE),
        self.TEXT_VECTOR: models.VectorParams(size=768, distance=models.Distance.COSINE)
    }
)

This dual-vector architecture enables the application to perform searches based on either visual content or extracted text within the same Qdrant collection.

CRUD Operations for Vector Data

The class provides thin, async wrappers around Qdrant client calls for all data manipulation tasks, handling automatic conversion between MappedImage domain models and Qdrant points.

Retrieval Operations

The retrieve_by_id and retrieve_by_ids methods (lines 53-68) fetch points using client.retrieve and map the returned ScoredPoint objects to MappedImage instances:

points = await self._client.retrieve(
    collection_name=self._config.qdrant.coll,
    ids=[id]
)
return self._get_mapped_image_from_point(points[0])

Insertion and Upsert

The insert_items method (lines 75-84) converts a list of MappedImage objects into models.PointStruct instances and performs batch upserts:

points = [
    models.PointStruct(
        id=item.id,
        payload=item.payload,
        vector={self.IMG_VECTOR: item.image_vector, self.TEXT_VECTOR: item.text_contain_vector}
    )
    for item in items
]
await self._client.upsert(collection_name=self._config.qdrant.coll, points=points)

Deletion and Updates

  • Deletion: delete_items (lines 85-92) uses client.delete with a PointIdsList filter to remove specific IDs
  • Payload Updates: update_payload (lines 94-104) calls client.set_payload to modify metadata without changing vectors
  • Vector Updates: update_vectors (lines 106-110) uses client.update_vectors to refresh embeddings while preserving IDs and payloads

Unified Search Interface with Hybrid RRF Fusion

The query_search method provides the primary search interface, accepting a high-level DbQuery object and supporting both single-criteria and multi-criteria searches. When multiple search bases (vision and OCR) are provided, the implementation performs hybrid RRF (Reciprocal Rank Fusion) using Qdrant's prefetch and fusion capabilities.

The conversion logic at lines 103-127 transforms DbQueryBasis objects into Qdrant NearestQuery or RecommendQuery instances via _convert_basis_to_qdrant_query. For hybrid searches (lines 141-154), the method constructs Prefetch objects for each criterion and combines them with a FusionQuery:

prefetches = [
    models.Prefetch(query=vision_query, using=self.IMG_VECTOR),
    models.Prefetch(query=text_query, using=self.TEXT_VECTOR)
]
results = await self._client.query_points(
    collection_name=self._config.qdrant.coll,
    prefetch=prefetches,
    query=models.FusionQuery(fusion=models.Fusion.RRF)
)

Metadata Filtering

The _get_filters_by_filter_param method (lines 95-162) translates optional FilterParams into Qdrant models.Filter objects, supporting range queries, exact matches, text contains, and multi-value any-matches on image metadata fields.

Data Mapping Between Domain Models and Qdrant Points

The class maintains clean separation between the application's domain logic and Qdrant's transport layer through dedicated conversion helpers at lines 49-69:

  • _get_vector_from_img_data: Extracts specific vector fields from MappedImage
  • _get_point_from_mapped_image: Serializes complete MappedImage instances to PointStruct
  • _get_mapped_image_from_point: Deserializes ScoredPoint responses back to MappedImage with score attribution

Additional utility methods include scroll_points and get_counts for pagination and collection statistics, plus vector_name_for_basis (lines 85-93) which maps SearchBasisEnum values (vision, ocr) to the corresponding vector field names.

Summary

  • Multi-mode client support: The class automatically configures Qdrant clients for server, local file, or in-memory operation based on configuration
  • Dual-vector schema: Creates and manages collections with separate 768-dimensional cosine-similarity vectors for images and text content
  • Complete CRUD coverage: Provides async methods for retrieve, upsert, delete, payload update, and vector update operations
  • Hybrid search capability: Implements RRF fusion for multi-modal searches combining vision and text embeddings with optional metadata filtering
  • Domain abstraction: Handles all translation between MappedImage models and Qdrant PointStruct objects

Frequently Asked Questions

How does VectorDbContext handle Qdrant connection failures?

The implementation wraps the underlying Qdrant client with retry decorators that automatically retry transient failures. Additionally, the match statement at initialization (lines 31-41) allows the application to switch between server, local, and in-memory modes without code changes, providing fallback options for different deployment environments.

What vector similarity metric does NekoImageGallery use?

The collection schema defined in initialize_collection uses cosine distance for both vector fields. The image_vector and text_contain_vector fields are configured with models.Distance.COSINE at lines 36-46, making this suitable for normalized embedding vectors from modern vision-language models.

Can I search using both image content and OCR text simultaneously?

Yes. The query_search method accepts a DbQuery containing multiple criteria in the criteria dictionary. When both SearchBasisEnum.vision and SearchBasisEnum.ocr bases are provided, the class automatically constructs prefetch queries for each vector field and applies RRF fusion (lines 141-154) to combine results into a unified ranked list.

How are image metadata and payloads managed separately from vectors?

The MappedImage class separates payload (metadata dictionary) from image_vector and text_contain_vector (numpy arrays). The update_payload method (lines 94-104) calls client.set_payload to modify metadata without touching vectors, while update_vectors (lines 106-110) updates embeddings via client.update_vectors without affecting payloads.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →