Semantic search with $vectorSearch
Store embeddings next to your documents and search by meaning with a vector index.
With $vectorSearch you search documents by what they mean, not by the exact words. Vectors are stored as another field
of the document and the index lives on the same nodes as the data: you do not need another database.
This guide uses Python, PyMongo and the all-MiniLM-L6-v2 model from sentence-transformers, which gives 384-dimension
vectors. Any embedding model works; set numDimensions to its size.
Shell
pip install pymongo sentence-transformers1. Store the documents with their vector
Python
from pymongo import MongoClient
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("all-MiniLM-L6-v2") # 384 dimensions
client = MongoClient("mongodb://app:<password>@node-01:27017/?tls=true&tlsCAFile=./ca.pem")
articles = client.kb.articles
docs = [
{"title": "Add a node", "body": "Create an enrollment token and start the binary with --join."},
{"title": "Drain a node", "body": "teseladb admin node drain moves its replicas before you shut it down."},
]
for doc in docs:
doc["embedding"] = model.encode(doc["title"] + ". " + doc["body"]).tolist()
articles.insert_many(docs)2. Create the vector index
Python
from pymongo.operations import SearchIndexModel
articles.create_search_index(SearchIndexModel(
name="vector",
type="vectorSearch",
definition={"fields": [
{"type": "vector", "path": "embedding", "numDimensions": 384, "similarity": "cosine"}
]},
))3. Search by meaning
Python
query = model.encode("how do I take a machine out of the cluster?").tolist()
results = articles.aggregate([
{"$vectorSearch": {"index": "vector", "path": "embedding", "queryVector": query,
"numCandidates": 100, "limit": 3}},
{"$project": {"title": 1, "score": {"$meta": "vectorSearchScore"}}},
])
for r in results:
print(round(r["score"], 3), r["title"])The question does not contain the word «drain», but the closest result is the article that explains it.
4. Filter and tune
- Add a
filterfield to the index ({"type": "filter", "path": "category"}) and passfilterin$vectorSearchto search only one category. - Raise
numCandidatesto improve accuracy at the cost of time, or useexact: trueto compare with every vector. Withexact, the result is the same on any replica. - An inserted document shows up in the search as soon as the write is committed.
Last updated