fastrag.vector_store#
fastrag.vector_store — the pipeline’s storage backend, read and written.
Re-exports VectorStore, the sink-family
base every concrete vector store implements, and
ChromaVectorStore,
MilvusVectorStore and
OpenSearchVectorStore. Milvus and
OpenSearch also implement LexicalStore
for BM25 search; Chroma does not. Lives at the top level rather than under
fastrag.ingestion: a vector store is queried at read time as well as
written at ingest time, so it is not an ingestion-only concern.
- class fastrag.vector_store.ChromaVectorStore(*, url=None, path=None, collection='fastrag_documents', headers=None, tenant='default_tenant', database='default_database', metric_type='cosine', policy=None)[source]#
Bases:
VectorStoreVectors in a Chroma server, or in an embedded on-disk Chroma database.
Give
urlto talk to a Chroma server through its async HTTP client, orpathto run Chroma in-process against a local directory (its client is synchronous, so calls run in a worker thread). Construction never touches the network or the disk — the client is built in__aenter__.async with ChromaVectorStore(url="http://localhost:8000") as vector_store: async for document in vector_store.save(embedded_documents): ...
filteris a JSON-encoded Chromawhereobject, e.g.'{"source_uri": "https://example.org/docs"}'.scoreis Chroma’s own distance, so lower is better; results are still best first.- Parameters:
url (str | None) – Server endpoint, e.g.
http://localhost:8000. Exclusive withpath.path (str | None) – Directory of an embedded persistent database. Exclusive with
url.collection (str) – Name of the Chroma collection. Created on demand.
headers (Mapping[str, str] | None) – Extra HTTP headers, e.g. an auth token, sent with
url.tenant (str) – Chroma tenant the collection lives in.
database (str) – Chroma database the collection lives in.
metric_type (str) – HNSW distance for a new collection:
cosine,l2orip. An existing collection must already use it.policy (Policy | None) – Execution policy for the terminal step
save()returns.
- async ensure_ready(dimension)[source]#
Create
collectionif absent, or validate its metric and width.Chroma fixes a collection’s width on its first insert rather than at creation, so an existing collection is checked against one stored vector; an empty one accepts any width.
- Parameters:
dimension (int)
- Return type:
None
- async search(embedding, *, k, filter=None)[source]#
Return at most
kdocuments nearestembedding, best first.scoreis Chroma’s distance for the collection’s metric, where lower means closer;rankis the position in Chroma’s already nearest-first order.
- save(upstream, *, skip_existing=False)#
Return a lazy terminal step that indexes
upstream’s documents.Constructing the returned step performs no I/O — evaluating it (
async for document in vector_store.save(upstream):or.run()) is what upserts. Each document is queued into a batcher that checksexisting_ids()and flushes toupsert()onceself.policy.batch_sizedocuments have queued, or after a short window; every document is yielded back once its batch is resolved, withcachedset to whether the store already held it, andDocumentSavedemitted for it.- Parameters:
upstream (PipelineStep[Document]) – Final upstream step yielding embedded documents.
skip_existing (bool) – For an identity-preserving Embedder, check destination ids before embedding. Indexed items bypass vector retrieval and produce cached DocumentEmbedded and DocumentSaved events. Cached events and results may contain only identity/metadata with empty content and no vectors. Custom content filters disable header projection. Use a separate destination for each embedding configuration.
- Return type:
Either way,
recreate_cache(on the store’s policy or the pipeline’s) skips the existence check and upserts every document.
- sync(upstream, *, skip_existing=False)#
Like
save(), then delete every stored documentupstreamdid not yield.After a clean run the store holds exactly the documents the run produced: documents whose source disappeared or changed (a changed chunk gets a new id) are removed. Deletion happens once the upstream is exhausted, so a run that raises or is stopped early deletes nothing. A run with any
ItemFaileddeletes nothing either: a failed item’s documents are missing from the run, not from the source. Either way aDocumentsPrunedevent reports the outcome.The run must cover everything the store should keep — use one store (collection/index) per synced pipeline.
- Parameters:
upstream (PipelineStep[Document]) – Final upstream step yielding embedded documents.
- Return type:
- class fastrag.vector_store.MilvusVectorStore(*, url, collection='fastrag_documents', user=None, password=None, metric_type='COSINE', enable_bm25=False, timeout=30.0, policy=None)[source]#
Bases:
VectorStore,LexicalStoreVectors in a Milvus or Milvus-Lite server.
Choose this when the corpus outgrows in-process search, or when several processes index or query the same data. Construction never touches the network — the
pymilvusclient is built in__aenter__and closed in__aexit__.async with MilvusVectorStore(url=MILVUS_URI) as vector_store: saved_documents = vector_store.save(embedded_documents) async for document in saved_documents: ...
- Parameters:
url (str) – Server endpoint, e.g.
http://localhost:19530.collection (str) – Name of the Milvus collection documents are upserted into. Created automatically, on demand, if absent.
user (str | None) – Username, combined with
passwordinto thetokenMilvus authenticates with.Noneconnects without credentials.password (str | None) – Password paired with
user.metric_type (str) – Distance metric for the vector index.
COSINEsuits embedding models whose vectors are not length-normalized;L2is the other common choice.enable_bm25 (bool) – Create an analyzed content field, BM25 function and sparse index. Requires Milvus 2.5+. Existing dense-only collections must be reindexed into a new collection to use this option.
timeout (float) – Seconds per client operation.
policy (Policy | None) – Execution policy for the terminal step
save()returns.
- async ensure_ready(dimension)[source]#
Create
collectionfordimension-wide vectors if absent.Idempotent: safe to call on every run, including one where the collection already exists. The schema mirrors
Document: id and provenance are columns so they filter without reading the JSON, and the content and metadata live alongside the vector.- Parameters:
dimension (int)
- Return type:
None
- async upsert(documents)[source]#
Insert or replace
documentsbyid, in one request.- Raises:
VectorStoreError – A document is missing its embedding (checked again defensively — the terminal step should already have rejected it), its UTF-8 content exceeds the column cap, or its serialized metadata exceeds the JSON cap.
- Parameters:
- Return type:
None
- async search(embedding, *, k, filter=None)[source]#
Return at most
kdocuments nearestembedding, best first.One
searchcall, requestingsearch_params={"metric_type": self.metric_type}explicitly so the query is scored the same way the collection’s own index was built (ensure_ready()). pymilvus already returns hits best-first for whichever metric that is, so no reordering is needed:scoreis each hit’s owndistancefield, andrankits position in that already-correct order.Queries with
consistency_level="Strong"for read-your-writes: pymilvus’s client-wide default,"Bounded", may not yet reflect anupsert()this same process just issued, and a caller retrieving right after indexing must see it.
- async lexical_search(query, *, k, filter=None)[source]#
Rank text using Milvus’s server-side BM25 function and sparse index.
- async existing_ids(ids)[source]#
Query
collectiononce for which ofidsare already indexed.One
querycall for the whole batch, filtering on the primary key (id in [...]) — never one call per id — so this scales with the number of batchessave()’s terminal step flushes, not with the number of documents in them.Queries with
consistency_level="Strong"for read-your-writes: pymilvus’s client-wide default,"Bounded", may not yet reflect anupsertthis same process just issued — a staleness window here is not an acceptable trade for the latency it would save.
- async all_ids()[source]#
Page through every id in
collection, in id order.AsyncMilvusClienthas noquery_iterator, so this pages the way pymilvus’s own iterator does:iteratorasks the server for each page sorted by primary key, and the next page filters on ids after the last one seen.offsetpaging would stop at Milvus’s 16384-row result window.
- save(upstream, *, skip_existing=False)#
Return a lazy terminal step that indexes
upstream’s documents.Constructing the returned step performs no I/O — evaluating it (
async for document in vector_store.save(upstream):or.run()) is what upserts. Each document is queued into a batcher that checksexisting_ids()and flushes toupsert()onceself.policy.batch_sizedocuments have queued, or after a short window; every document is yielded back once its batch is resolved, withcachedset to whether the store already held it, andDocumentSavedemitted for it.- Parameters:
upstream (PipelineStep[Document]) – Final upstream step yielding embedded documents.
skip_existing (bool) – For an identity-preserving Embedder, check destination ids before embedding. Indexed items bypass vector retrieval and produce cached DocumentEmbedded and DocumentSaved events. Cached events and results may contain only identity/metadata with empty content and no vectors. Custom content filters disable header projection. Use a separate destination for each embedding configuration.
- Return type:
Either way,
recreate_cache(on the store’s policy or the pipeline’s) skips the existence check and upserts every document.
- sync(upstream, *, skip_existing=False)#
Like
save(), then delete every stored documentupstreamdid not yield.After a clean run the store holds exactly the documents the run produced: documents whose source disappeared or changed (a changed chunk gets a new id) are removed. Deletion happens once the upstream is exhausted, so a run that raises or is stopped early deletes nothing. A run with any
ItemFaileddeletes nothing either: a failed item’s documents are missing from the run, not from the source. Either way aDocumentsPrunedevent reports the outcome.The run must cover everything the store should keep — use one store (collection/index) per synced pipeline.
- Parameters:
upstream (PipelineStep[Document]) – Final upstream step yielding embedded documents.
- Return type:
- class fastrag.vector_store.OpenSearchVectorStore(*, url, index='fastrag_documents', user=None, password=None, timeout=30.0, policy=None)[source]#
Bases:
VectorStore,LexicalStorePersist and search documents in an OpenSearch index.
filteris a JSON-encoded Query DSL object, e.g.'{"term": {"source_uri": "https://example.org/docs"}}'. Metadata is retained in_sourcewithout dynamic indexing. HTTPS uses username and password authentication with TLS certificate verification disabled.- Parameters:
- async ensure_ready(dimension)[source]#
Create the index or validate its existing vector and text mappings.
- Parameters:
dimension (int)
- Return type:
None
- async all_ids()[source]#
Page through every id sorted on the
idkeyword, withsearch_after.Returns an empty set when the index does not exist yet.
- async search(embedding, *, k, filter=None)[source]#
Search dense vectors with cosine similarity and optional native filter.
- async lexical_search(query, *, k, filter=None)[source]#
Search the analyzed content field using BM25.
- save(upstream, *, skip_existing=False)#
Return a lazy terminal step that indexes
upstream’s documents.Constructing the returned step performs no I/O — evaluating it (
async for document in vector_store.save(upstream):or.run()) is what upserts. Each document is queued into a batcher that checksexisting_ids()and flushes toupsert()onceself.policy.batch_sizedocuments have queued, or after a short window; every document is yielded back once its batch is resolved, withcachedset to whether the store already held it, andDocumentSavedemitted for it.- Parameters:
upstream (PipelineStep[Document]) – Final upstream step yielding embedded documents.
skip_existing (bool) – For an identity-preserving Embedder, check destination ids before embedding. Indexed items bypass vector retrieval and produce cached DocumentEmbedded and DocumentSaved events. Cached events and results may contain only identity/metadata with empty content and no vectors. Custom content filters disable header projection. Use a separate destination for each embedding configuration.
- Return type:
Either way,
recreate_cache(on the store’s policy or the pipeline’s) skips the existence check and upserts every document.
- sync(upstream, *, skip_existing=False)#
Like
save(), then delete every stored documentupstreamdid not yield.After a clean run the store holds exactly the documents the run produced: documents whose source disappeared or changed (a changed chunk gets a new id) are removed. Deletion happens once the upstream is exhausted, so a run that raises or is stopped early deletes nothing. A run with any
ItemFaileddeletes nothing either: a failed item’s documents are missing from the run, not from the source. Either way aDocumentsPrunedevent reports the outcome.The run must cover everything the store should keep — use one store (collection/index) per synced pipeline.
- Parameters:
upstream (PipelineStep[Document]) – Final upstream step yielding embedded documents.
- Return type:
- class fastrag.vector_store.VectorStore(*, policy=None)[source]#
Bases:
AbstractAsyncContextManager[VectorStore],ABCSink backend for persisting processed and embedded documents.
Opened once per run (
async with MilvusVectorStore(url=...) as vector_store:) and handed the final upstream step viasave(), which returns a lazy terminalPipelineStep— nothing is indexed until that step is evaluated.- Parameters:
policy (Policy | None)
- abstractmethod async ensure_ready(dimension)[source]#
Create the backing collection for
dimension-wide vectors if absent.Idempotent and cheap to call again on a collection that already exists; called once, lazily, before the first upsert, with the vector width taken from the first document flowing through the terminal step.
- Parameters:
dimension (int) – Width of the vectors this run’s documents carry.
- Return type:
None
- abstractmethod async upsert(documents)[source]#
Insert or replace
documentsbyid, in one call.Idempotent: rerunning with the same ids converges rather than duplicating rows. Called with at most
self.policy.batch_sizedocuments at a time — the batcher insave()’s returned step enforces that ceiling, not the caller — and possibly fewer, since documents already reported byexisting_ids()are excluded.
- abstractmethod async existing_ids(ids)[source]#
Return the subset of
idsalready present in the store.Called once per pending batch, never once per document, so the round trips it adds scale with the number of batches. An id returned here is treated as already indexed (skipped, reported
cached=True); an absent id is upserted and reportedcached=False. Skipping a present document is an optimisation, not a correctness requirement — a store unable to answer cheaply may upsert everything, but must then report which ids were genuinely present rather than guessing.
- abstractmethod async search(embedding, *, k, filter=None)[source]#
Return at most
kdocuments nearestembedding, best first.The read-path counterpart to
upsert(), queried byVectorRetrieverand, through it,RerankingRetriever. Never opens the store — the caller (a retriever) holds an already-open one.Stamps two reserved metadata keys on every returned document, alongside its stored
content/metadata(includingsource_uri):score: the backend’s own relevance score, on the backend’s own scale — never comparable across backends or metrics.rank: 0-based position in the returned (best-first) list.
The list is best-first regardless of the configured metric’s raw sort direction, so position 0 is always the best match.
- Parameters:
embedding (Sequence[float]) – Query vector, the same width the store’s collection was created with.
k (int) – Maximum number of documents to return. Fewer come back if the collection holds fewer than
kmatching documents — this is not an error.filter (str | None) – Backend-native filter expression, applied server-side.
Nonereturns theknearest documents unfiltered.
- Return type:
- async all_ids()[source]#
Return the id of every document in the store.
Needed only by
sync(), so a store that does not support it may leave this unimplemented. Returns an empty set when the backing collection does not exist yet.
- async delete(ids)[source]#
Remove the documents with
ids; ids the store does not hold are ignored.Needed only by
sync(), which calls it with at most 1000 ids at a time.
- sync(upstream, *, skip_existing=False)[source]#
Like
save(), then delete every stored documentupstreamdid not yield.After a clean run the store holds exactly the documents the run produced: documents whose source disappeared or changed (a changed chunk gets a new id) are removed. Deletion happens once the upstream is exhausted, so a run that raises or is stopped early deletes nothing. A run with any
ItemFaileddeletes nothing either: a failed item’s documents are missing from the run, not from the source. Either way aDocumentsPrunedevent reports the outcome.The run must cover everything the store should keep — use one store (collection/index) per synced pipeline.
- Parameters:
upstream (PipelineStep[Document]) – Final upstream step yielding embedded documents.
- Return type:
- save(upstream, *, skip_existing=False)[source]#
Return a lazy terminal step that indexes
upstream’s documents.Constructing the returned step performs no I/O — evaluating it (
async for document in vector_store.save(upstream):or.run()) is what upserts. Each document is queued into a batcher that checksexisting_ids()and flushes toupsert()onceself.policy.batch_sizedocuments have queued, or after a short window; every document is yielded back once its batch is resolved, withcachedset to whether the store already held it, andDocumentSavedemitted for it.- Parameters:
upstream (PipelineStep[Document]) – Final upstream step yielding embedded documents.
skip_existing (bool) – For an identity-preserving Embedder, check destination ids before embedding. Indexed items bypass vector retrieval and produce cached DocumentEmbedded and DocumentSaved events. Cached events and results may contain only identity/metadata with empty content and no vectors. Custom content filters disable header projection. Use a separate destination for each embedding configuration.
- Return type:
Either way,
recreate_cache(on the store’s policy or the pipeline’s) skips the existence check and upserts every document.
Modules
The |
|
|
|
|
|
Async OpenSearch storage with BM25 and dense k-NN search over one index. |