mempalace.backends.qdrant
Source: mempalace/backends/qdrant.py
Qdrant REST backend for MemPalace.
Qdrant is an opt-in external-service backend. Chroma remains the default; this adapter only runs when the user explicitly selects qdrant via config, env, or CLI/MCP flag. Embeddings are still produced locally by MemPalace through the core embedding wrapper before vectors are sent to Qdrant.
Classes
class QdrantCollection(BaseCollection)
__init__
def __init__(self, *, backend: 'QdrantBackend', client: _QdrantRESTClient, config: _QdrantConfig, palace: PalaceRef, collection_name: str, remote_collection: str)get_stored_embedder_identity
def get_stored_embedder_identity(self)set_embedder_identity
def set_embedder_identity(self, identity) -> Noneadd
def add(self, *, documents, ids, metadatas = None, embeddings = None)upsert
def upsert(self, *, documents, ids, metadatas = None, embeddings = None)update
def update(self, *, ids, documents = None, metadatas = None, embeddings = None)query
def query(self, *, query_texts = None, query_embeddings = None, n_results = 10, where = None, where_document = None, include = None) -> QueryResultget
def get(self, *, ids = None, where = None, where_document = None, limit = None, offset = None, include = None) -> GetResultget_all_metadata
def get_all_metadata(self, where: Optional[dict] = None) -> list[dict]Return every matching record's metadata in one cursor pass (#1796).
Overrides the default offset-paginated implementation, which would call self.get(limit=, offset=) in a loop -- and since self.get() is backed by a full _scroll_all() materialization, each page of that loop would re-walk the entire collection from the start just to discard everything outside its slice (O(n^2) over collection size).
Delegates to self._rows(), the same single-scroll-plus-local-filter helper that backs get()/delete(). With ids=None and where_document=None, _rows() reduces to exactly one _scroll_all() pass followed by an unconditional _matches_where() re-check on every row -- the same filter logic get(), delete(), and lexical_search() already use, so this can't independently drift from those call sites. (Maintainer review on #1832: avoid duplicating the filter dance inline.)
facet_counts
def facet_counts(self, field: str, where: Optional[dict] = None, limit: int = 1000) -> dict[str, int]delete
def delete(self, *, ids = None, where = None)count
def count(self) -> intlexical_search
def lexical_search(self, *, query: str, n_results: int = 10, where: Optional[dict] = None)close
def close(self) -> Nonehealth
def health(self) -> HealthStatusclass QdrantBackend(BaseBackend)
__init__
def __init__(self)get_collection
def get_collection(self, *args, **kwargs) -> QdrantCollectionclose_palace
def close_palace(self, palace: PalaceRef | str) -> Noneclose
def close(self) -> Nonehealth
def health(self, palace: Optional[PalaceRef] = None) -> HealthStatusdetect
def detect(cls, path: str) -> boolcreate_collection
def create_collection(self, palace_path: str, collection_name: str) -> QdrantCollectionget_or_create_collection
def get_or_create_collection(self, palace_path: str, collection_name: str)delete_collection
def delete_collection(self, palace_path: str, collection_name: str) -> None