Milvus - DrAlzahraniProjects/csusb_fall2024_cse6550_team4 GitHub Wiki

Milvus Documentation

Last edited by csusb_fall2024_cse6550_team4


Table of Contents

  1. Installation
  2. Configuration
  3. Implementation
  4. Usage
  5. Troubleshooting

1. Installation

This section outlines the steps to set up Milvus and the project environment using Docker.


Step 1: Build and Deploy the Milvus Environment

  1. Navigate to the Project Repository:
    Clone the repository or navigate to the project folder:

    git clone https://github.com/DrAlzahraniProjects/csusb_fall2024_cse6550_team4.git  
    cd csusb_fall2024_cse6550_team4  
    
  2. Build the Docker Image: Use the provided Dockerfile to build the project environment:

    docker build -t team4_chatbot . 
    

    1

    Figure shows the milvus installation command in the docker file. Screenshot 2024-12-05 183515

  3. Run the Docker Container: Start the container with the following command:

    docker run -d -p 19530:19530 -p 5004:5004 -p 6004:6004 --name chatbot team4_chatbot
    

2

  1. Verify Milvus Deployment:

    Ensure Milvus is active by executing the following command inside the container:

    docker exec -it chatbot bash  
    python -c "from pymilvus import connections; connections.connect(); print('Milvus connected')"  
    

Screenshot 2024-12-05 183840 Screenshot 2024-12-05 183928

Figure shows how the statement imports the Milvus integration module from the langchain-milvus package.

2. Configuration

Connecting to Milvus

To establish communication with Milvus, we use the pymilvus library in our project. The connection logic is defined in the bot.py file within the initialize_milvus function.

Here’s the relevant code snippet for connecting to Milvus:

from pymilvus import connections

def initialize_milvus(uri: str = MILVUS_URI):
    """
    Initialize the vector store for the RAG model

    Args:
        uri (str, optional): Path to the local Milvus db. Defaults to MILVUS_URI.

    Returns:
        vector_store: The vector store created
    """
    embeddings = get_embedding_function()
    vector_store = None

    # Connect to Milvus
    connections.connect("default", uri=uri)

    # Your collection setup and data handling logic goes here...
    print("Vector store initialization complete.")
    return vector_store

Key Steps:

Establishing the Connection: The connections.connect method connects to the Milvus server using the URI defined in the environment (MILVUS_URI). Screenshot 2024-12-05 185711

Embedding Initialization: The function calls get_embedding_function() to configure embeddings for vector storage. Screenshot 2024-12-05 185753

Vector Store Handling: The function sets up or retrieves the vector store used for managing document embeddings.

Screenshot 2024-12-05 185814

Confirmation: A log message confirms successful initialization of the Milvus vector store.

3

Figure shows how Milvus is initialized and connection is established.

Connection of milvus in jupyter notebook

Screenshot 2024-12-06 173619

3. Implementation

1. Creating the Collection and Embedding Setup:

The initialize_milvus function initializes the vector store for the chatbot, which includes the collection setup and document insertion. It connects to the Milvus database, checks if the collection exists, and either loads it or creates a new one.

Screenshot 2024-12-05 190652

def create_vector_store(docs, embeddings, uri):
    """
    Initializes or loads a vector store from Milvus, adding documents for similarity search.

    Args:
        docs (list): A list of documents to be stored in the vector store.
        embeddings : A function or model that generates embeddings for the documents.
        uri (str): Path to the local Milvus db.

    Returns:
        vector_store: The vector store created or loaded.
    """
    # Connect to the Milvus database
    connections.connect("default", uri=uri)

    # Check if the collection already exists
    if utility.has_collection("research_paper_chatbot"):
        print("Collection already exists. Loading existing Vector Store.")
        vector_store = Milvus(
            collection_name="research_paper_chatbot",
            embedding_function=get_embedding_function(),
            connection_args={"uri": uri}
        )
    else:
        # Create a new vector store and drop any existing one
        vector_store = Milvus.from_documents(
            documents=docs,
            embedding=embeddings,
            collection_name="research_paper_chatbot",
            connection_args={"uri": uri},
            drop_old=True,
        )
        print("Vector Store Created")
    return vector_store

Functionality:

Vector Store Creation: If the collection (research_paper_chatbot) already exists, it loads the existing vector store. If not, it creates a new collection and stores the documents passed to it.

Screenshot 2024-12-05 190542

Collection Initialization: The vector store is created by the Milvus.from_documents() method, which processes documents and stores them using the embeddings function.

4

Figure shows the creation of vector_store using Milvus.

2. Loading Existing Vector Store:

If the vector store is already initialized, the load_exisiting_db function can be used to load the store from Milvus.

def load_exisiting_db(uri=MILVUS_URI):
    """
    Load an existing vector store from the local Milvus database specified by the URI.

    Args:
        uri (str, optional): Path to the local Milvus db. Defaults to MILVUS_URI.

    Returns:
        vector_store: The vector store created.
    """
    vector_store = Milvus(
        collection_name="research_paper_chatbot",
        embedding_function=get_embedding_function(),
        connection_args={"uri": uri},
    )
    print("Vector Store Loaded")
    return vector_store

5

Figure shows loading of existing vector_store.

3. Document Processing and Insertion:

Documents are split into smaller chunks using split_documents() and then inserted into the vector store.

def split_documents(documents):
    """
    Split the documents into chunks for processing.

    Args:
        documents (list): List of documents to split.

    Returns:
        list: A list of chunks of documents.
    """
    text_splitter = RecursiveCharacterTextSplitter(
        chunk_size=2000,  # Split the text into chunks of 1000 characters
        chunk_overlap=200,  # Overlap the chunks by 300 characters
        is_separator_regex=False,  # Don't split on regex
    )
    docs = text_splitter.split_documents(documents)
    return docs

This function ensures that documents are processed in manageable chunks and then stored in Milvus for efficient retrieval.

Milvus folder in our repository

Screenshot 2024-12-05 195538

4. Usage

Inserting Data into Milvus

Inserting data into the Milvus vector store is done after generating document embeddings. Below is the code snippet used in the project for inserting data into the vector store:

def create_vector_store(docs, embeddings, uri):
    """
    Initializes or loads a vector store in Milvus from documents and embeddings.

    Args:
        docs (list): The documents to be inserted into the vector store.
        embeddings: The model used to generate embeddings for the documents.
        uri (str): The URI of the local Milvus database.

    Returns:
        vector_store: The created or loaded vector store.
    """
    # Ensure the directory exists for the Milvus database
    head = os.path.split(uri)
    os.makedirs(head[0], exist_ok=True)

    # Connect to Milvus
    connections.connect("default", uri=uri)

    # Check if the collection exists; if it does, load it, else create a new one
    if utility.has_collection("research_paper_chatbot"):
        print("Collection already exists. Loading existing Vector Store.")
        vector_store = Milvus(
            collection_name="research_paper_chatbot",
            embedding_function=get_embedding_function(),
            connection_args={"uri": uri}
        )
    else:
        # Create a new vector store and insert documents
        vector_store = Milvus.from_documents(
            documents=docs,
            embedding=embeddings,
            collection_name="research_paper_chatbot",
            connection_args={"uri": uri},
            drop_old=True,  # Drop old collection if it exists
        )
        print("Vector Store Created")
    return vector_store

What This Code Does: It connects to the Milvus instance and checks if the collection (research_paper_chatbot) exists. If not, it creates a new collection and inserts the provided documents (docs), which are processed into embeddings. Important: Make sure your documents are converted into embeddings before passing them to this function.

Screenshot 2024-12-05 190524 Screenshot 2024-12-05 194136

Used milvus in docker file to have milvus ready and build inside the docker image

Screenshot 2024-12-06 174236

Querying Data from Milvus

Once data is inserted into the collection, you can query Milvus for relevant documents based on the user's input. Below is the code for querying data from the Milvus collection:

def query_rag(query):
    """
    Entry point for the RAG model to generate an answer to a given query.

    Args:
        query (str): The query string for which an answer is to be generated.
    
    Returns:
        str: The formatted answer with a unique source link (if available).
    """
    # Define the model
    model = ChatMistralAI(model='open-mistral-7b', api_key=MISTRAL_API_KEY, temperature=0.2)
    print("Model Loaded")

    prompt = create_prompt()

    # Load the vector store and create the retriever
    vector_store = load_exisiting_db(uri=MILVUS_URI)
    retriever = ScoreThresholdRetriever(vector_store=vector_store, score_threshold=0.2, k=3)  # Adjust k as needed
    
    try:
        # Set up document and retrieval chains
        document_chain = create_stuff_documents_chain(model, prompt)
        print("Document Chain Created")

        retrieval_chain = create_retrieval_chain(retriever, document_chain)
        print("Retrieval Chain Created")

        # Get relevant documents
        relevant_docs = retriever.get_relevant_documents(query)
        print(f"Relevant Documents: {relevant_docs}")
        
        # Generate response
        response = retrieval_chain.invoke({"input": query})
        response_text = response.get("answer", "No answer found.")

        # Collect unique links
        unique_links = set()
        for doc in relevant_docs:
            metadata = doc.metadata if hasattr(doc, "metadata") else {}
            source = metadata.get("source", "Unknown").split("/")[-1]
            page = metadata.get("page", "Unknown")

            # Ensure page is an integer
            try:
                page = int(page)
            except ValueError:
                page = 1  # Default to page 1 if invalid

            # Create a unique link
            if source != "Unknown":
                link = f'<a href="/team4/?view=pdf&file={data_dir}/{source}&page={page}" target="_blank" style="color : white">[more_info]</a>'
                unique_links.add(link)  # Adds only if link is unique

        # Append source links to response text
        if unique_links:
            response_text += f"\n\nSource: {''.join(unique_links)}"

        return response_text

    except HTTPStatusError as e:
        print(f"HTTPStatusError: {e}")
        if e.response.status_code == 429:
            return "I am currently experiencing high traffic. Please try again later."
        return f"HTTPStatusError: {e}"

What This Code Does: The function first retrieves relevant documents from Milvus based on the query input. The ScoreThresholdRetriever is used to filter out documents that don’t meet the relevance score. After retrieving the documents, the chatbot generates a response using the ChatMistralAI model and appends unique source links (e.g., PDF document references) to the response.

Screenshot 2024-12-05 190554 Screenshot 2024-12-05 195538

5. Troubleshooting

Faced problem while connecting to milvus vector database

Screenshot 2024-12-06 175515

Unable to load the milvus database locally

Screenshot 2024-12-06 175848

Milvus search failed raise error:"syncTimestamp Failed"

Screenshot 2024-12-06 180820

Connection Issues

If you encounter connection errors, confirm that the Milvus server is running and accessible at the specified host and port. You can verify this with the following command:

docker ps

Screenshot 2024-12-05 200206

This command checks if the Milvus container is active. Ensure that the container’s status and port mappings are correct.

Milvus Error When Using Collection Search: Connection Refused and Collection Not Loaded Screenshot 2024-12-05 201916

Import Errors

If you experience import errors with pymilvus, make sure it is correctly installed:

pip install pymilvus

This command reinstalls the necessary library to resolve import issues.

Debugging Tips

  • Check Collection Information: Use print statements to review the collection schema and configuration, ensuring the setup is accurate.
print("Collection info:", collection.schema)
  • Verify Insertions: After adding data to the collection, confirm the entity count to ensure that all data was inserted correctly.
print("Total entities:", collection.num_entities)
  • Reinstall Libraries: If issues persist, reinstalling pymilvus and updating dependencies can help resolve compatibility problems and ensure stable operation.
pip install --upgrade pymilvus