Framework integrations
polign_db works as a vector store in LangChain and LlamaIndex. Each
integration is a small Python package built on the
polign client, so it talks to the same server and
needs nothing extra on the server side.
| Framework | Package | Class |
|---|---|---|
| LangChain | langchain-polign | langchain_polign.PolignVectorStore |
| LlamaIndex | llama-index-vector-stores-polign | llama_index.vector_stores.polign.PolignVectorStore |
Both need a running server. For a first try, start one on your machine:
polign-server -store fs:/var/lib/polign
It listens on http://localhost:23000. Get started
covers installing the binary and pointing it at a bucket.
LangChain
pip install langchain-polign
from langchain_openai import OpenAIEmbeddings from langchain_polign import PolignVectorStore store = PolignVectorStore( embedding=OpenAIEmbeddings(), collection="docs", url="http://localhost:23000", ) store.add_texts( ["cats purr", "dogs bark"], metadatas=[{"lang": "en", "score": 0.9}, {"lang": "en", "score": 0.4}], ) store.similarity_search("purring", k=1, filter={"score": {"$gte": 0.5}}) store.similarity_search_with_relevance_scores("barking", k=2) store.max_marginal_relevance_search("animals", k=2, fetch_k=10) store.delete(filter={"lang": "fr"}) # or store.delete(ids=[...]) retriever = store.as_retriever(search_kwargs={"k": 4, "filter": {"lang": "en"}})
filter is the same metadata language as the
Python client: a plain mapping is equality,
and $eq, $ne, $in, $gt,
$gte, $lt, $lte, $exists,
$and, $or, and $not build richer predicates.
similarity_search_with_score returns the distance, where smaller is closer.
similarity_search_with_relevance_scores turns it into a score between 0 and 1.
The package passes LangChain's standard vector store test suite. Source and the full
API are in the
langchain-polign README.
LlamaIndex
pip install llama-index-vector-stores-polign
from llama_index.core import StorageContext, VectorStoreIndex from llama_index.vector_stores.polign import PolignVectorStore store = PolignVectorStore(collection_name="docs", url="http://localhost:23000") index = VectorStoreIndex.from_documents( documents, storage_context=StorageContext.from_defaults(vector_store=store) ) index.as_retriever(similarity_top_k=5).retrieve("what purrs?") index.delete_ref_doc("document-id") # removes every chunk of that document # reopen later without re-indexing index = VectorStoreIndex.from_vector_store(store)
LlamaIndex MetadataFilters are translated for you. Supported operators are
EQ, NE, GT, GTE, LT,
LTE, IN, NIN, ANY, ALL,
CONTAINS, and IS_EMPTY, combined with AND,
OR, and NOT. TEXT_MATCH is not supported.
| Query mode | What runs |
|---|---|
DEFAULT | Vector search. |
TEXT_SEARCH, SPARSE | BM25 keyword search over the node text. |
HYBRID | Vector and BM25 search combined on the server. Set alpha to weight the vector side; leave it unset for rank fusion. |
MMR | Nearest nodes re-ranked for variety. |
Source and the full API are in the llama-index-vector-stores-polign README.
Keyword and hybrid search
Both packages store the document text in the metadata key text. That is the
field the server's keyword index reads, so keyword and hybrid search work without setup.
In LangChain, call them directly:
store.lexical_search("brown fox", k=5) # keyword only
store.hybrid_search("brown fox", k=5, alpha=0.6) # vector and keyword, weighted
store.hybrid_search("brown fox", k=5) # vector and keyword, rank fusion
In LlamaIndex, pick the TEXT_SEARCH or HYBRID query mode.
Keyword search needs a server started with -store. A new document becomes
searchable by keyword once the server has written it to the bucket, about half a minute
with default settings. Vector search sees it right away.
What gets stored
- The document or node id becomes the record id, so adding the same id again replaces it.
- Metadata that is a string, number, boolean, or a flat list of those is stored as is and can be filtered on.
- Nested objects and empty values are saved as text and restored when you read them back. They cannot be filtered on.
- A collection is created by the first write and takes its size from the first vector.
Limits
- Removing a whole collection needs the server's collection API
(
-byo-store). Without it, delete by filter, or callclear()in LlamaIndex, which removes every record. - MMR fetches the candidate vectors in one extra request, because search results do not include vectors.
- The LlamaIndex async methods run the client on a worker thread.
Source & license
Both packages are open source under the Apache License 2.0 and live next to the client in github.com/Polign/polign. Bug reports and pull requests go there.
Anything that can call Python can use the Python client directly, and every other language can use the HTTP API.