How to connect vector search pipeline to RAG stack (with langchain)?

Hi,

The MongoDB RAG stack documentation here talks about building from PDFs and files

Vector search also has aggregation-based documentation, where I can create an index on an existing collection and get using an aggregation pipeline.

Is there a way to combine these two? I want a RAG after the vector search using aggregation, can I do this ? I am new to vector searches and RAGs, so any sample code would help.

Thanks

Hey Vishu, thanks for the question!

Can you share a bit more about what you’re trying to do here? $vectorSearch is part of the Aggregation pipeline, so it can absolutely be used in partnership with other aggregation stages. That said, RAG is a architectural pattern, so we would expect you to use MongoDB aggregation as a piece in order to achieve a RAG architecture.

The document you linked is a full tutorial that should help you build a RAG architecture.

1 Like

Thanks @Benjamin_Flast, for getting back. I have done some implementation over my collection. Let me explain
I am storing my embedding in my collection named businessembeddings. I did check the db and embeddings got created fine. the filed where embeddings are stored is named embeddings.

And I created an index:

{
  "fields": [
    {
      "numDimensions": 1536,
      "path": "embeddings",
      "similarity": "euclidean",
      "type": "vector"
    },
    {
      "path": "businessAccount",
      "type": "filter"
    },
    {
      "path": "_id",
      "type": "filter"
    }
  ]
}

And now when I try to retrive using that index I get the error:

Code:

export const asRetriever = (apiKey: string, options: { indexName: string, collectionName: string }) => {
  const mongoClient = connection.getClient()
  const collection = mongoClient.db(dbName).collection(options.collectionName)
  const embeddings = new OpenAIEmbeddings({ openAIApiKey: apiKey })
  const vectorStore = new MongoDBAtlasVectorSearch(embeddings, { collection, indexName: options.indexName })
  return vectorStore.asRetriever()
}

const retriever = asRetriever(RAGConfig.openApiKey, {
      indexName: "product_index",
      collectionName: "businessproducts"
    })
    const llm = new OpenAI({ openAIApiKey: RAGConfig.openApiKey, temperature: 0 })
    const qa = RetrievalQAChain.fromLLM(llm, retriever)
    return await qa.run(query)

MongoServerError: PlanExecutor error during aggregation :: caused by :: embedding is not indexed as knnVectorMongoServerError: PlanExecutor error during aggregation :: caused by :: embedding is not indexed as knnVector

I also tried the following index and got the same error

{
  "mappings": {
    "dynamic": false,
    "fields": {
      "embeddings": {
        "dimensions": 1536,
        "similarity": "cosine",
        "type": "knnVector"
      }
    }
  }
}

FYI, not all documents in my collection has embeddings, as am yet to run a migration over old data. Could this be an issue ?

Can you help?

@Benjamin_Flast Anything on this. its really difficult when some simple tutorials dont work

1 Like

Even I am also facing the same issue
OperationFailure: PlanExecutor error during aggregation :: caused by :: embedding is not indexed as knnVector, full error: {‘ok’: 0.0, ‘errmsg’: ‘PlanExecutor error during aggregation :: caused by :: embedding is not indexed as knnVector’, ‘code’: 8, ‘codeName’: ‘UnknownError’, ‘$clusterTime’: {‘clusterTime’: Timestamp(1704818303, 1), ‘signature’: {‘hash’: b’\x9c\xae\xabc\x89D\x80\xc5PM\xd6\xf9\xfe\xbe\x82\xde\xe87\xd5\x05’, ‘keyId’: 7289444457848504322}}, ‘operationTime’: Timestamp(1704818303, 1)}

Hi Raju and Vishnu,

Looking closely at the error, it says: “embedding is not indexed as knnVector”. However, in the index-definition, it specifies the field as “embeddings” (not the “s” at the end"). The default name of the embedding field taken while creating the MongoDBAtlasVectorSearch vector store, is “embedding”. I see that there was no “embeddingKey” explicitly specified here:

const vectorStore = new MongoDBAtlasVectorSearch(embeddings, { collection, indexName: options.indexName })

If the name of the field is something other than “embedding” (for instance, it seems to be “embeddings” in your case), then you should specify the field name explicitly with “embeddingKey” param. For an example of this, please refer to the code bit in the documentation here.

Hope this helps.

Thanks,
Harshad

Thank you @Harshad_Dhavale for your timely response. It worked for me.

Which index should I use ?
{
“fields”: [
{
“numDimensions”: 1536,
“path”: “embeddings”,
“similarity”: “euclidean”,
“type”: “vector”
},
{
“path”: “businessAccount”,
“type”: “filter”
},
{
“path”: “_id”,
“type”: “filter”
}
]
}

or the other one. Most documentation mention this as the right one, here the path already specifies which to use and it has ?path: embeddings"

Sure np @Raju_Aralikatti, glad to know the suggestion helped!

Hi @Vishnu_Satis - The default name of the embedding field taken while creating the MongoDBAtlasVectorSearch vector store, is "embedding" . If the name of the vector-embeddings field in your collection is something other than "embedding" (for instance, say it’s named “vectorEmbeddings”) , then you would need to specify that field name explicitly in the code while instantiating MongoDBAtlasVectorSearch vector store, with an embedding key param, as shown in the code bit in the documentation here. And you would use the same field name in the index definition as well. So, if the name of the vector-embeddings field in your collection is "vectorEmbeddings", then in addition to defining that field as the embedding key in your code (refer aforementioned doc for example), you would also specify that path in the index-definition, like this for instance:

...
"fields": [
    {
      "numDimensions": 1536,
      "path": "vectorEmbeddings",
...

Hello.

I am getting a similar problem using python. My embeddings are all saved under a field called wod_embedding_openai:

And I have a search index called wod_vector_index_openai that targets this same field/path:

And here is my Python code:

from langchain_community.vectorstores import MongoDBAtlasVectorSearch
from pymongo.mongo_client import MongoClient
from langchain_openai import OpenAIEmbeddings
import certifi

DB_NAME = "xfitpal"
COLLECTION_NAME = "wods"
mongoUri = os.environ.get("MONGO_ATLAS_DB_URL")
mongoClient = MongoClient(mongoUri, tlsCAFile=certifi.where())
mongoDb = mongoClient[DB_NAME]
wods_collection = mongoDb[COLLECTION_NAME]


vectorStore = MongoDBAtlasVectorSearch(
    wods_collection, OpenAIEmbeddings(openai_api_key=OPENAI_API_KEY), index_name='wod_vector_index_openai'
)

docs = vectorStore.similarity_search('MY_QUERY_GOES_HERE', K=1)

print(docs)

When I run it, I get the error mentioned in one of the comments above:

raise OperationFailure(errmsg, code, response, max_wire_version)
pymongo.errors.OperationFailure: PlanExecutor error during aggregation :: caused by :: embedding is not indexed as knnVector, full error: {'ok': 0.0, 'errmsg': 'PlanExecutor error during aggregation :: caused by :: embedding is not indexed as knnVector', 'code': 8, 'codeName': 'UnknownError', '$clusterTime': {'clusterTime': Timestamp(1706467324, 22),  'operationTime': Timestamp(1706467324, 22)}

Btw, this is giving me a timeout error in a virtual environment set up with Python 3.12. So I have to run it under python 3.11 and that is when I get the above error.

Any ideas? Appreciate any help.

Hi @Akbar_Bakhshi2 - the code snippet that you shared specifies:

vectorStore = MongoDBAtlasVectorSearch(   
     wods_collection, 
     OpenAIEmbeddings(openai_api_key=OPENAI_API_KEY),      
     index_name='wod_vector_index_openai'
)

As I indicated in the earlier response, if the name of the vector-embeddings field in your collection is something other than “embedding” (in your collection, it’s named “wod_embedding_openai”) , then you would need to specify that field name explicitly in the code while instantiating MongoDBAtlasVectorSearch vector store, with an embedding key param. So, you would need to specify the “embedding_key = ‘wod_embedding_openai’”, like this:

vectorStore = MongoDBAtlasVectorSearch(   
     wods_collection, 
     OpenAIEmbeddings(openai_api_key=OPENAI_API_KEY),      
     index_name='wod_vector_index_openai',
     embedding_key = 'wod_embedding_openai'
)
1 Like

Hi @Harshad_Dhavale .
Thank you for the response and explanation. I have made the change as you pointed out and now I am getting another error:

I am not sure what causes this error, but I am a little suspicious that it may be because the way my embeddings are created. I use OpenAI vector embedding as shownbelow to vectorize the text inside the ‘wod’ field in my collection and then save the vector in the ‘embedding’ field.

import os
from dotenv import load_dotenv

from pymongo.mongo_client import MongoClient
from openai import OpenAI

load_dotenv()


mongoUri = os.environ.get("MONGO_ATLAS_DB_URL")
mongoClient = MongoClient(mongoUri)
mongoDb = mongoClient['xfitpal']
wods_collection = mongoDb['wods']

OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY")

client = OpenAI(api_key=OPENAI_API_KEY)
def generate_openai_embeddings(text: str) -> list[float]:
    response = client.embeddings.create(model="text-embedding-ada-002",
    input=text)
    return response.data[0].embedding


for document in wods_collection.find():
    document['embedding'] = generate_openai_embeddings(document['wod'])
    wods_collection.replace_one({'_id': document['_id']}, document)

Any ideas on what I may be doing wrong here? Thanks again for yout help.

Hi, I would like to know if this approach could be use to build real time RAG applications. I’m using mongoDB as sink for Kafka and I would like to use the data store in MongoDB as the vector database for the RAG approach. Thanks in advance.

For anyone having this same problem, you need to use Document like below to create your embeddings:

from langchain.schema import Document

embeddings = OpenAIEmbeddings(openai_api_key=OPENAI_API_KEY)
vectorStore = MongoDBAtlasVectorSearch(
    collection, OpenAIEmbeddings(openai_api_key=OPENAI_API_KEY), index_name='vsearch_index'
)

data = []
for document in collection.find():
    newDoc = Document(page_content=YOUR_TEXT_TO_BE_VECTORIZED, metadata={YOUR_META_DATA})
    data.append(newDoc)

docSearch = MongoDBAtlasVectorSearch.from_documents(
    data, embeddings, collection=YOUR_COLLECTION, index_name='vsearch_index'
)
1 Like

@Laura_Fernandez You can use MongoDB Kafka connector + Vector search - MongoDB Atlas Vector Search Makes Real-Time AI a Reality with Confluent | MongoDB Blog

Thanks @Prakul_Agarwal!! are embeddings calculated in real time in Vector Search?
Thanks

Thanks @Akbar_Sheikh !! But can embeddings be created at real time? I mean, with every document that is inserted in MongoDB?
Thanks again

@Laura_Fernandez You will create the embedding by calling an external service like OpenAI embedding API at the time of insertion of your data. You can also use the “Atlas Triggers” for automating the call to the external embeddings API as described here - How to Do Semantic Search in MongoDB Using Atlas Vector Search | MongoDB

1 Like

same function in my response would work. Your data list will only have the new document info that you want to add. Basically a list with one Document instead of going through the for loop. The MongoDBAtlasVectorSearch.from_documents function will add the new Document to the collection. It won’t overwrite anything.

1 Like