You can integrate Atlas Vector Search with LangChain to perform hybrid search. In this tutorial, you complete the following steps:
Set up the environment.
Use Atlas as a vector store.
Create an Atlas Vector Search and Atlas Search index on your data.
Run hybrid search queries.
Pass the query results into your RAG pipeline.
Work with a runnable version of this tutorial as a Python notebook.
Prerequisites
To complete this tutorial, you must have the following:
An Atlas account with a cluster running MongoDB version 6.0.11, 7.0.2, or later (including RCs). Ensure that your IP address is included in your Atlas project's access list. To learn more, see Create a Cluster.
A Voyage AI API key. To learn more, see API Key and Python Client.
An OpenAI API Key. You must have an OpenAI account with credits available for API requests. To learn more about registering an OpenAI account, see the OpenAI API website.
An environment to run interactive Python notebooks such as Colab.
Set Up the Environment
Set up the environment for this tutorial.
Create an interactive Python notebook by saving a file
with the .ipynb
extension. This notebook allows you to
run Python code snippets individually, and you'll use
it to run the code in this tutorial.
To set up your notebook environment:
Set environment variables.
Run the following code to set the environment variables for this tutorial. Provide your API keys and Atlas cluster's SRV connection string.
import os os.environ["VOYAGE_API_KEY"] = "<voyage-api-key>" os.environ["OPENAI_API_KEY"] = "<openai-api-key>" ATLAS_CONNECTION_STRING = "<connection-string>"
Note
Your connection string should use the following format:
mongodb+srv://<db_username>:<db_password>@<clusterName>.<hostname>.mongodb.net
Use Atlas as a Vector Store
You must use Atlas as a vector store for your data. You can instantiate a vector store by using an existing collection in Atlas.
Load the sample data.
If you haven't already, complete the steps to load sample data into your Atlas cluster.
Note
If you want to use your own data, see LangChain Get Started or How to Create Vector Embeddings to learn how to ingest vector embeddings into Atlas.
Instantiate the vector store.
Paste and run the following code in your notebook
to create a vector store instance
named vector_store
from the sample_mflix.embedded_movies
namespace in Atlas. This code uses the
from_connection_string
method to create the MongoDBAtlasVectorSearch
vector store and specifies the following parameters:
Your Atlas cluster's connection string.
The
voyage-3-large
embedding model from Voyage AI to convert text into vector embeddings.sample_mflix.embedded movies
as the namespace to use.plot
as the field that contains the text.plot_embedding_voyage_3_large
as the field that contains the embeddings.dotProduct
as the relevance score function.
from langchain_mongodb import MongoDBAtlasVectorSearch from langchain_voyageai import VoyageAIEmbeddings # Create the vector store vector_store = MongoDBAtlasVectorSearch.from_connection_string( connection_string = ATLAS_CONNECTION_STRING, embedding = VoyageAIEmbeddings(model = "voyage-3-large", output_dimension = 2048), namespace = "sample_mflix.embedded_movies", text_key = "plot", embedding_key = "plot_embedding_voyage_3_large", relevance_score_fn = "dotProduct" )
Create the Indexes
Note
To create Atlas Vector Search or Atlas Search indexes, you must have Project Data Access Admin
or higher access to the Atlas project.
To enable hybrid search queries on your vector store, create an Atlas Vector Search and Atlas Search index on the collection. You can create the indexes by using either the LangChain helper methods or the PyMongo Driver method:
Create the Atlas Vector Search index.
Run the following code to create
a vector search index that indexes the
plot_embedding_voyage_3_large
field in the collection.
# Use helper method to create the vector search index vector_store.create_vector_search_index( dimensions = 2048 # The dimensions of the vector embeddings to be indexed )
Create the Atlas Search index.
Run the following code in your notebook to create a
search index
that indexes the plot
field in the collection.
from langchain_mongodb.index import create_fulltext_search_index from pymongo import MongoClient # Connect to your cluster client = MongoClient(ATLAS_CONNECTION_STRING) # Use helper method to create the search index create_fulltext_search_index( collection = client["sample_mflix"]["embedded_movies"], field = "plot", index_name = "search_index" )
Create the Atlas Vector Search index.
Run the following code to create
a vector search index that indexes the
plot_embedding_voyage_3_large
field in the collection.
from pymongo import MongoClient from pymongo.operations import SearchIndexModel # Connect to your cluster client = MongoClient(ATLAS_CONNECTION_STRING) collection = client["sample_mflix"]["embedded_movies"] # Create your vector search index model, then create the index vector_index_model = SearchIndexModel( definition={ "fields": [ { "type": "vector", "path": "plot_embedding_voyage_3_large", "numDimensions": 2048, "similarity": "dotProduct" } ] }, name="vector_index", type="vectorSearch" ) collection.create_search_index(model=vector_index_model)
Create the Atlas Search index.
Run the following code to create a
search index
that indexes the plot
field in the collection.
1 # Create your search index model, then create the search index 2 search_index_model = SearchIndexModel( 3 definition={ 4 "mappings": { 5 "dynamic": False, 6 "fields": { 7 "plot": { 8 "type": "string" 9 } 10 } 11 } 12 }, 13 name="search_index" 14 ) 15 collection.create_search_index(model=search_index_model)
The indexes should take about one minute to build. While they build, the indexes are in an initial sync state. When they finish building, you can start querying the data in your collection.
Run a Hybrid Search Query
Once Atlas builds your indexes, you can run hybrid search queries on your data.
The following code uses the MongoDBAtlasHybridSearchRetriever
retriever to perform a hybrid search
for the string time travel
. It also
specifies the following parameters:
vectorstore
: The name of the vector store instance.search_index_name
: The name of the Atlas Search index.top_k
: The number of documents to return.fulltext_penalty
: The penalty for full-text search.The lower the penalty, the higher the full-text search score.
vector_penalty
: The penalty for vector search.The lower the penalty, the higher the vector search score.
The retriever returns a list of documents sorted by the sum of the full-text search score and the vector search score. The final output of the code example includes the title, plot, and the different scores for each document.
To learn more about hybrid search query results, see About the Query.
from langchain_mongodb.retrievers.hybrid_search import MongoDBAtlasHybridSearchRetriever # Initialize the retriever retriever = MongoDBAtlasHybridSearchRetriever( vectorstore = vector_store, search_index_name = "search_index", top_k = 5, fulltext_penalty = 50, vector_penalty = 50, post_filter=[ { "$project": { "plot_embedding": 0, "plot_embedding_voyage_3_large": 0 } } ]) # Define your query query = "time travel" # Print results documents = retriever.invoke(query) for doc in documents: print("Title: " + doc.metadata["title"]) print("Plot: " + doc.page_content) print("Search score: {}".format(doc.metadata["fulltext_score"])) print("Vector Search score: {}".format(doc.metadata["vector_score"])) print("Total score: {}\n".format(doc.metadata["fulltext_score"] + doc.metadata["vector_score"]))
Title: Timecop Plot: An officer for a security agency that regulates time travel, must fend for his life against a shady politician who has a tie to his past. Search score: 0.019230769230769232 Vector Search score: 0.018518518518518517 Total score: 0.03774928774928775 Title: A.P.E.X. Plot: A time-travel experiment in which a robot probe is sent from the year 2073 to the year 1973 goes terribly wrong thrusting one of the project scientists, a man named Nicholas Sinclair into a... Search score: 0.018518518518518517 Vector Search score: 0.018867924528301886 Total score: 0.0373864430468204 Title: About Time Plot: At the age of 21, Tim discovers he can travel in time and change what happens and has happened in his own life. His decision to make his world a better place by getting a girlfriend turns out not to be as easy as you might think. Search score: 0 Vector Search score: 0.0196078431372549 Total score: 0.0196078431372549 Title: The Time Traveler's Wife Plot: A romantic drama about a Chicago librarian with a gene that causes him to involuntarily time travel, and the complications it creates for his marriage. Search score: 0.0196078431372549 Vector Search score: 0 Total score: 0.0196078431372549 Title: Retroactive Plot: A psychiatrist makes multiple trips through time to save a woman that was murdered by her brutal husband. Search score: 0 Vector Search score: 0.019230769230769232 Total score: 0.019230769230769232
Pass Results to a RAG Pipeline
You can pass your hybrid search results into your RAG pipeline to generate responses on the retrieved documents. The sample code does the following:
Defines a LangChain prompt template to instruct the LLM to use the retrieved documents as context for your query. LangChain passes these documents to the
{context}
input variable and your query to the{query}
variable.Constructs a chain that specifies the following:
The hybrid search retriever you defined to retrieve relevant documents.
The prompt template that you defined.
An LLM from OpenAI to generate a context-aware response. By default, this is the
gpt-3.5-turbo
model.
Prompts the chain with a sample query and returns the response. The generated response might vary.
from langchain_core.output_parsers import StrOutputParser from langchain_core.prompts import PromptTemplate from langchain_core.runnables import RunnablePassthrough from langchain_openai import ChatOpenAI # Define a prompt template template = """ Use the following pieces of context to answer the question at the end. {context} Question: Can you recommend some movies about {query}? """ prompt = PromptTemplate.from_template(template) model = ChatOpenAI() # Construct a chain to answer questions on your data chain = ( {"context": retriever, "query": RunnablePassthrough()} | prompt | model | StrOutputParser() ) # Prompt the chain query = "time travel" answer = chain.invoke(query) print(answer)
Certainly! Here are some movies about time travel from the context provided: 1. **Timecop (1994)** Genre: Action, Crime, Sci-Fi Plot: A law enforcement officer working for the Time Enforcement Commission battles a shady politician with a personal tie to his past. IMDb Rating: 5.8 2. **A.P.E.X. (1994)** Genre: Action, Sci-Fi Plot: A time-travel experiment gone wrong thrusts a scientist into an alternate timeline plagued by killer robots. IMDb Rating: 4.3 3. **About Time (2013)** Genre: Drama, Fantasy, Romance Plot: A young man discovers he can time travel and uses this ability to improve his life, especially his love life, but learns the limitations and challenges of his gift. IMDb Rating: 7.8 4. **The Time Traveler's Wife (2009)** Genre: Drama, Fantasy, Romance Plot: A Chicago librarian with a gene causing him to involuntarily time travel struggles with its impact on his romantic relationship and marriage. IMDb Rating: 7.1 5. **Retroactive (1997)** Genre: Action, Crime, Drama Plot: A woman accidentally time-travels to prevent a violent event, but her attempts to fix the situation lead to worsening consequences due to repeated time cycles. IMDb Rating: 6.3 Each movie covers time travel with unique perspectives, from action-packed adventures to romantic dramas.