Det här är tillfällen då vanlig textsökning inte räcker till. Så här kan det se ut i praktiken:
- En supportsajt ger inga träffar när en användare skriver "startar inte" i stället för den exakta frasen som används i hjälpartikeln.
- En e-handel hittar inget när en kund söker på "något varmt för vintern" eftersom inga produktbeskrivningar innehåller de exakta orden.
- En kunskapsbas missar rätt dokument eftersom användaren formulerade sin fråga annorlunda än hur dokumentet är skrivet.
Semantisk sökning löser detta. Den förstår betydelsen och avsikten bakom en fråga i stället för att matcha exakta ord.
Den här guiden visar hur du implementerar semantisk sökning i MongoDB med Python och den kostnadsfria inbäddningsmodellen nomic-embed-text-v1.
Obs: nomic-embed-text-v1 är ungefär 0,27 GB när den laddas i minnet, så se till att din dator har minst 1 GB ledigt RAM innan du kör något skript i den här guiden. Första körningen hämtar modellen från Hugging Face, så räkna med extra tid beroende på din internetanslutning. Alla efterföljande körningar läser modellen från din lokala cache. CPU-inferens är avsevärt långsammare än GPU-inferens. På maskiner utan dedikerat GPU körs modellen på CPU och använder RAM i stället för VRAM, så generering av inbäddningar kan ta längre tid.
I den här guiden lär du dig:
- Vad vektorinbäddningar är och hur de representerar betydelse
- Hur du genererar och lagrar inbäddningar i MongoDB
- Hur du skapar ett MongoDB Vector Search-index
- Hur du omvandlar en användarfråga till en vektor
- Hur du kör en
$vectorSearch-aggregeringspipeline och tolkar resultaten
Du hittar all källkod för den här guiden i GitHub-repot.
Textsökning vs semantisk sökning
Textsökning matchar dokument som innehåller de exakta orden i din fråga. Semantisk sökning matchar dokument som bär samma betydelse som din fråga, även om de använder helt andra ord.
Tabellen nedan visar vad respektive metod returnerar för sökfrågan "hjärtproblem":
| Dokumenttext | Textsökning | Semantisk sökning | Varför textsökning returnerar det |
|---|---|---|---|
| "...hjärtproblem hos vuxna..." | Ja | Ja | Innehåller de exakta orden "hjärtproblem" |
| "...kardiologiska tillstånd och symtom..." | Nej | Ja | Innehåller inte de exakta orden "hjärtproblem" |
| "...riskfaktorer för hjärtsjukdom..." | Nej | Ja | Innehåller inte de exakta orden "hjärtproblem" |
| "...bröstsmärta och andfåddhet..." | Nej | Ja | Innehåller inte de exakta orden "hjärtproblem" |
Begrepp inom semantisk sökning
Tre begrepp är centrala för semantisk sökning i MongoDB. De hjälper dig att förstå varför varje steg i den här guiden fungerar som det gör.
Vektorinbäddningar
En inbäddningsmodell omvandlar text till en vektor, det vill säga en lista med tal av fast längd. Varje tal i vektorn representerar en dimensions av betydelse.
Två texter med liknande innebörd ger vektorer som är numeriskt nära varandra. "kardiologiska tillstånd" och "hjärtproblem" hamnar nära varandra i vektorrummet, även om de inte delar några ord. Den närheten är det som gör semantisk sökning möjlig.
Den här guiden använder inbäddningsmodellen nomic-embed-text-v1, som är gratis, öppen källkod och körs helt lokalt på din maskin. Modellen laddas automatiskt ned från Hugging Face första gången du kör skriptet och sparas lokalt för kommande körningar. Modellen producerar 768 tal per indata.
Vektorsökningsindex
Ett vektorsökningsindex talar om för MongoDB vilket fält som innehåller inbäddningarna, hur många dimensioner som förväntas och vilken likhetsfunktion som ska användas för jämförelse. Du måste skapa det här indexet innan du kan köra några $vectorSearch-frågor.
$vectorSearch-aggregeringssteget
$vectorSearch är aggregeringssteget som kör sökningen. Det tar emot en frågevektor, söker i det indexerade fältet och returnerar dokument rangordnade efter semantisk likhet. Du kan kedja ihop det med $project och andra steg precis som i vilken annan aggregationspipeline som helst.
Då sätter vi igång.
Förutsättningar
Innan du börjar, se till att du har följande på plats:
- Python 3.8 eller senare installerat
- Ett MongoDB Atlas-konto med ett M0 (gratisnivå) kluster konfigurerat
pymongo4.7 eller senare,sentence-transformersocheinopsinstallerade i Python- Grundläggande kännedom om Python och MongoDB-kollektioner
- Din Atlas-anslutningssträng, tillgänglig i Atlas-gränssnittet under **Database > Connect > Drivers**
- Din IP-adress är tillåten i Atlas innan du kör några skript. Gå till **Security > Network Access** i Atlas-gränssnittet och lägg till din aktuella IP-adress.
Ställ in ditt projekt
Skapa en mapp för ditt projekt och navigera till den i terminalen:
mkdir mongodb-semantic-search
cd mongodb-semantic-search
Skapa och aktivera en virtuell miljö för att isolera projektets beroenden:
python -m venv venv
source venv/bin/activate
På Windows aktiverar du den virtuella miljön med:
venv\Scripts\activate
Installera nu de nödvändiga paketen:
pip install pymongo sentence-transformers einops
Du skapar en Python-fil för varje steg i den här guiden. Alla filer läggs i mappen mongodb-semantic-search.
Skapa filen med inbäddningshjälpmedel
Skapa en fil med namnet embedding_utils.py. Den här filen innehåller båda inbäddningsfunktionerna som används i guiden:
from sentence_transformers import SentenceTransformer
# Load the free, open-source embedding model.
# The model downloads from Hugging Face on first run and saves locally.
# trust_remote_code=True is required by this model:
model = SentenceTransformer("nomic-ai/nomic-embed-text-v1", trust_remote_code=True)
def get_embedding(text, precision="float32"):
# Use this function when embedding text you plan to store in MongoDB:
return model.encode(text, precision=precision).tolist()
def get_query_embedding(text, precision="float32"):
# Use this function when embedding a user's search query:
return model.encode(text, precision=precision).tolist()
Varning: trust_remote_code=True tillåter modellen att köra modellspecifik Python-kod som laddas ned från Hugging Face till din maskin. Om modellens källkod på Hugging Face komprometteras eller uppdateras med skadliga ändringar körs den koden automatiskt i din miljö. Var försiktig innan du använder den här parametern i en produktionsmiljö.
Generera och lagra vektorinbäddningar
Skapa en fil med namnet generate_embeddings.py. Den här filen importerar inbäddningsfunktionen från embedding_utils.py, genererar en vektor för varje dokuments textfält och lagrar hela dokumentet, inklusive inbäddningen, i MongoDB:
from embedding_utils import get_embedding
from pymongo import MongoClient
# Replace the placeholder with your Atlas connection string:
mongodb_client = MongoClient(
"mongodb+srv://<USERNAME>:<PASSWORD>@<HOST>/",
appname="devrel-tutorial-python-semantic-search"
)
collection = mongodb_client["sample_db"]["documents"]
# Sample data:
sample_documents = [
{
"title": "MongoDB Atlas",
"text": "MongoDB Atlas is a fully managed cloud database."
},
{
"title": "Vector Search",
"text": "Vector search finds results based on semantic meaning."
},
{
"title": "Nomic AI",
"text": "nomic-embed-text-v1 is a free, open-source embedding model."
},
]
docs_to_insert = []
for doc in sample_documents:
embedding = get_embedding(doc["text"])
docs_to_insert.append({
"title": doc["title"],
"text": doc["text"],
# The vector lives alongside your original data in the same document:
"embedding": embedding
})
# Drop the collection before each run to avoid inserting duplicate documents:
collection.drop()
result = collection.insert_many(docs_to_insert)
print(f"Inserted {len(result.inserted_ids)} documents with embeddings.")
mongodb_client.close()
I koden ovan tar collection.drop() bort alla dokument och index i kollektionen före varje körning. Om du kör generate_embeddings.py igen utan den här raden infogas dubbletter, vilket gör att $vectorSearch returnerar samma dokument flera gånger. Att droppa kollektionen tar också bort vektorsökningsindexet, så du måste köra create_vector_index.py igen varje gång du kör generate_embeddings.py på nytt.
Kör skriptet:
python generate_embeddings.py
Du får följande utdata i terminalen:
<All keys matched successfully>
Inserted 3 documents with embeddings.
Varje dokument i MongoDB innehåller nu både originaltexten och dess 768-dimensionella vektor i fältet embedding. Vektorn ligger sida vid sida med dina data i samma dokument, så ingen separat lagring eller uppslag behövs vid frågetillfället.
Skapa ett MongoDB Vector Search-index
Skapa en fil med namnet create_vector_index.py. Den här filen definierar och skapar ett vektorsökningsindex på fältet embedding så att MongoDB kan köra $vectorSearch-frågor mot din kollektion.
Indexdefinitionen kräver tre fält:
path: fältet som innehåller inbäddningarna (embeddingi den här guiden)numDimensions: måste matcha modellens utdata-storlek (768förnomic-embed-text-v1)similarity: jämförelsefunktionen (cosineär korrekt för den här modellen)
Värdet för numDimensions måste exakt matcha din inbäddningsmodell. Om det inte stämmer misslyckas skapandet av indexet:
from pymongo.mongo_client import MongoClient
from pymongo.operations import SearchIndexModel
import time
# Replace the placeholder with your Atlas connection string:
mongodb_client = MongoClient(
"mongodb+srv://<USERNAME>:<PASSWORD>@<HOST>/",
appname="devrel-tutorial-python-semantic-search"
)
# Point to the same database and collection you used in the previous step:
database = mongodb_client["sample_db"]
collection = database["documents"]
# Define the vector search index.
# The three required fields tell MongoDB what to index and how to compare vectors:
search_index_model = SearchIndexModel(
definition={
"fields": [
{
"type": "vector",
"path": "embedding", # The field name from generate_embeddings.py
"numDimensions": 768, # nomic-embed-text-v1 always outputs 768 dimensions
"similarity": "cosine" # Recommended similarity function for this model
}
]
},
name="vector_index",
type="vectorSearch"
)
result = collection.create_search_index(model=search_index_model)
print("New search index named " + result + " is building.")
# Poll every five seconds until the index is ready to accept queries:
print("Polling to check if the index is ready. This may take up to a minute.")
predicate = lambda index: index.get("queryable") is True
while True:
indices = list(collection.list_search_indexes(result))
if len(indices) and predicate(indices[0]):
break
time.sleep(5)
print(result + " is ready for querying.")
mongodb_client.close()
Kör skriptet:
python create_vector_index.py
Du får följande utdata i terminalen:
New search index named vector_index is building.
Polling to check if the index is ready. This may take up to a minute.
vector_index is ready for querying.
Indexet kan ta upp till en minut att byggas. Pollningsloopen kontrollerar var femte sekund och avslutas först när MongoDB bekräftar att indexet går att fråga mot. Gå inte vidare förrän du ser "vector_index is ready for querying."
Omvandla din sökfråga till en vektor
Skapa en fil med namnet generate_query_vector.py. Den här filen importerar funktionen get_query_embedding() från filen embedding_utils.py. Kör generate_query_vector.py för att verifiera att inbäddningsmodellen läses in korrekt och producerar en 768-dimensionell vektor:
- Den definierar funktionen
get_query_embedding()som nästa steg importerar. - Du kan köra den fristående för att verifiera att modellen fungerar korrekt.
Du måste använda samma modell här som i första steget. En annan modell producerar vektorer som ligger i ett annat numeriskt rum, vilket gör jämförelser meningslösa:
from embedding_utils import get_query_embedding
user_query = "I need an automated, scalable system for serious information storage"
query_vector = get_query_embedding(user_query)
print(f"Query: '{user_query}'")
print(f"Vector dimensions: {len(query_vector)}")
print(f"First 5 values: {query_vector[:5]}")
Kör skriptet:
python generate_query_vector.py
Du får utdata liknande detta:
<All keys matched successfully>
Query: 'I need an automated, scalable system for serious information storage'
Vector dimensions: 768
First 5 values: [0.0025914530269801617, 0.09862980246543884, -0.023092379793524742, -0.0171672236174345, -0.05548065900802612]
I utdata ovan bekräftar Vector dimensions: 768 att modellens utdata matchar dina lagrade inbäddningar.
Kör en $vectorSearch-fråga
Skapa en fil med namnet run_vector_search.py. Den här filen importerar funktionen get_query_embedding() från filen embedding_utils.py och omvandlar en användares sökterm till en vektor. run_vector_search.py kör en $vectorSearch-aggregeringspipeline och skriver ut resultaten rangordnade efter semantisk likhet:
from embedding_utils import get_query_embedding
from pymongo import MongoClient
# Replace the placeholder with your Atlas connection string:
mongodb_client = MongoClient(
"mongodb+srv://<USERNAME>:<PASSWORD>@<HOST>/",
appname="devrel-tutorial-python-semantic-search"
)
collection = mongodb_client["sample_db"]["documents"]
# Generate a query vector from the user's search input:
user_query = "I need an automated, scalable system for serious information storage"
query_vector = get_query_embedding(user_query)
# Define the $vectorSearch aggregation pipeline:
pipeline = [
{
"$vectorSearch": {
"index": "vector_index", # The index created in create_vector_index.py
"path": "embedding", # The field that holds your stored vectors
"queryVector": query_vector, # The vector generated from the user's query
"numCandidates": 150, # How many neighbors MongoDB considers
"limit": 3 # How many results to return
}
},
{
"$project": {
"_id": 0,
"title": 1,
"text": 1,
"score": {
"$meta": "vectorSearchScore" # Relevance score for each result
}
}
}
]
results = collection.aggregate(pipeline)
print(f"\nTop results for query: '{user_query}'\n")
for doc in results:
print(f"Title: {doc['title']}")
print(f"Text: {doc['text']}")
print(f"Score: {doc['score']:.4f}")
print()
mongodb_client.close()
I koden ovan styr två parametrar sökbeteendet:
numCandidatesanger storleken på den initiala sökmängd som MongoDB granskar innan resultaten snävas in. Ett högre värde förbättrar recall men tar något längre tid.limitanger hur många resultat du får tillbaka. I den här guiden ärlimitsatt till 3 och numCandidates till 150. En vanlig startpunkt är att sättanumCandidatestill 10–15 gånger ditt limit.
Kör nu skriptet:
python run_vector_search.py
Du får utdata liknande detta:
<All keys matched successfully>
Top results for query: 'I need an automated, scalable system for serious information storage.'
Title: MongoDB Atlas
Text: MongoDB Atlas is a fully managed cloud database.
Score: 0.7211
Title: Nomic AI
Text: nomic-embed-text-v1 is a free, open-source embedding model.
Score: 0.6818
Title: Vector Search
Text: Vector search finds results based on semantic meaning.
Score: 0.6642
"MongoDB Atlas" får högst poäng trots att frågan "I need an automated, scalable system for serious information storage" inte delar några ord med "MongoDB Atlas is a fully managed cloud database." Sökningen returnerar det eftersom deras vektorer ligger nära varandra i betydelse: "...ett automatiserat, skalbart system för informationslagring" mappar semantiskt till "...en fullt hanterad molndatabas". En textsökning på samma fråga skulle ge noll träffar, eftersom inga exakta frågeord förekommer i något dokument. Det är semantisk sökning som fungerar som avsett.
Viktigast att komma ihåg
- MongoDB Vector Search körs på ett M0-kluster på gratisnivån. Ingen betald plan krävs.
- Du måste använda samma inbäddningsmodell både för att generera lagrade inbäddningar och för att generera frågevektorer. Att blanda modeller ger meningslösa resultat.
- Värdet
numDimensionsi din indexdefinition måste exakt matcha utdata-storleken för din inbäddningsmodell.nomic-embed-text-v1producerar alltid 768 dimensioner. input_type="document"optimerar inbäddningar för lagring.input_type="query"optimerar dem för hämtning. Använd rätt typ i varje steg.numCandidatesstyr storleken på det söknät som MongoDB kastar ut innan det snävas in till de slutligalimit-resultaten. Ett högre värde förbättrar recall på bekostnad av frågetiden.vectorSearchScorerangordnar resultat efter semantisk likhet. Resultaten behöver inte innehålla några av frågans exakta ord. Poängintervall varierar per modell och dataset, men följande gränser är en bra start förnomic-embed-text-v1med cosinuslikhet:- 0,9 och över: Nästan identisk betydelse. Dokumentet och frågan är semantiskt nästan desamma.
- 0,7 till 0,9: Stark relevans. Dokumentet relaterar tydligt till frågans avsikt.
- 0,5 till 0,7: Måttlig relevans. Dokumentet är ämnesrelaterat men använder annan inramning eller kontext.
- Under 0,5: Svag relevans. Sambandet är svagt och resultatet kan vara mindre användbart.
Du hittar all källkod för den här guiden i GitHub-repot.
Fördjupning
- Översikt över MongoDB Vector Search täcker hela funktionaliteten i MongoDB Vector Search, inklusive filtrering och kvantisering.
- Så här gör du hybridsökning visar hur du kombinerar vektorsökning och fulltextsökning i en enda fråga.
- Hur du skapar vektorinbäddningarförklarar hur du genererar vektorinbäddningar för textdata i dina kollektioner med inbäddningsmodeller från Voyage AI, OpenAI och andra leverantörer av öppna modeller.
- Retrieval-Augmented Generation (RAG) med MongoDB visar hur du använder semantisk sökning som hämtningslager i en applikation för retrieval-augmented generation.
Vanliga frågor
Behöver jag en betald Atlas-plan för att implementera semantisk sökning?
Nej. Alla fyra stegen i den här guiden körs på ett M0-kluster på gratisnivån, som är kostnadsfritt.
Vad händer om jag använder en annan inbäddningsmodell för min fråga än för mina lagrade dokument?
Dina resultat blir meningslösa. Vektorerna går inte att jämföra eftersom olika modeller mappar text till olika numeriska rum. Använd alltid samma modell för både indexering och frågor.
Vad är skillnaden mellan `numCandidates` och `limit`?
numCandidates är hur många vektorer MongoDB granskar under sökningen. limit är hur många av toppresultaten som returneras till dig. Ett högre numCandidates-värde förbättrar resultatens kvalitet till priset av något långsammare frågor. En vanlig startpunkt är att sätta numCandidates till 10 till 15 gånger ditt limit.
Kan jag använda semantisk sökning och textsökning tillsammans?
Ja. MongoDB stöder hybridsökning, som kombinerar $vectorSearch och $search i en enda pipeline.
Fungerar semantisk sökning för andra språk än engelska?
Det beror på din inbäddningsmodell. nomic-embed-text-v1 är främst tränad på engelsk text. För flerspråkiga användningsfall, välj en flerspråkig inbäddningsmodell som är tränad på de språk som dina data innehåller.