Esclarecendo Equívocos sobre a Velocidade de Inserção de Dados no Milvus
Muitos usuários que dependem do LangChain ou do LlamaIndex por suas etapas de API convenientes e mais curtas podem pensar que "Inserir dados no Milvus é lento." No entanto, essa percepção muitas vezes decorre de uma superficialização das etapas detalhadas do processo.
As etapas ocultas
Ao usar LangChain ou LlamaIndex, essas bibliotecas convertem dados não estruturados (como textos, imagens ou sons) em vetores usando modelos de embedding. Em seguida, elas inserem esses vetores no Milvus Lite. As bibliotecas simplificam esse processo complexo ao lidar com várias etapas nos bastidores para você.
Essa abstração pode criar a ilusão de que o processo de inserção de dados leva muito tempo.
O vilão do tempo: geração de embeddings
O tempo médio gasto gerando embeddings a partir de dados não estruturados é significativamente maior do que o tempo necessário para inserir dados no Milvus. A lentidão percebida muitas vezes se deve ao processo computacionalmente intensivo de transformar os dados em representações vetoriais, em vez da etapa de inserção de dados.
Para ilustrar a diferença entre os tempos de geração de embeddings e de inserção de dados, mostrarei um exemplo neste blog em que o tempo médio de embedding é de aproximadamente 5 segundos. Em contraste, o tempo médio de inserção no banco de dados vetorial Milvus é de apenas cerca de um décimo de segundo. O código completo está no meu GitHub.
Em outras palavras, cerca de 97% do tempo de "inserção no Milvus" observado no LangChain ou no LlamaIndex é gasto na geração de embeddings, enquanto cerca de 3% é gasto na etapa real de inserção no banco de dados.
Mostrei em um blog anterior como se conectar ao Milvus Lite usando LlamaIndex ou LangChain.
Nas seções a seguir, abordarei:
Exemplo de código LlamaIndex para inserir dados no Milvus
Exemplo de código LangChain para inserir dados no Milvus
Exemplo de código da API Pymilvus para inserir dados no Milvus
Exemplo de código LlamaIndex para inserir dados no Milvus
Aqui está um exemplo de código em LlamaIndex.
from llama_index.core import (
ServiceContext,
StorageContext,
VectorStoreIndex,
)
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
from llama_index.vector_stores.milvus import MilvusVectorStore
import time
# Define the embedding model.
service_context = ServiceContext.from_defaults(
# LlamaIndex local: translates to the same location as default HF cache.
embed_model="local:BAAI/bge-large-en-v1.5",
)
# Create a Milvus collection from the documents and embeddings.
EMBEDDING_DIM = 1024
vectorstore = MilvusVectorStore(
uri="./milvus_llamaindex.db",
dim=EMBEDDING_DIM,
# Override LlamaIndex default values for Milvus.
consistency_level="Eventually",
drop_old=True,
index_params = {
"metric_type": "COSINE",
"index_type": "AUTOINDEX",
"params": {},}
)
storage_context = StorageContext.from_defaults(
vector_store=vectorstore
)
llamaindex = VectorStoreIndex.from_documents(
lli_docs[:1],
storage_context=storage_context,
service_context=service_context
)
Exemplo de código LangChain para inserir dados no Milvus
Aqui está um exemplo de código em LangChain.
from langchain_milvus import Milvus
from langchain_huggingface import HuggingFaceEmbeddings
from langchain.text_splitter import RecursiveCharacterTextSplitter
import time
# Define the embedding model.
model_name = "BAAI/bge-large-en-v1.5"
model_kwargs = {'device': 'cpu'}
encode_kwargs = {'normalize_embeddings': True}
embed_model = HuggingFaceEmbeddings(
model_name=model_name,
model_kwargs=model_kwargs,
encode_kwargs=encode_kwargs
)
EMBEDDING_DIM = embed_model.dict()['client'].get_sentence_embedding_dimension()
# Define the chunking strategy.
text_splitter = RecursiveCharacterTextSplitter(chunk_size=512, chunk_overlap=51)
# Create a Milvus collection from the documents with chunking and embeddings.
start_time = time.time()
docs = text_splitter.split_documents(docs)
vectorstore = Milvus.from_documents(
documents=docs,
embedding=embed_model,
connection_args={"uri": "./milvus_demo.db"},
# Override LangChain default values for Milvus.
consistency_level="Eventually",
drop_old=True,
index_params = {
"metric_type": "COSINE",
"index_type": "AUTOINDEX",
"params": {},}
)
Exemplo de código da API Pymilvus para inserir dados no Milvus
Usando chamadas da API Pymilvus diretamente, vamos mostrar o que realmente está acontecendo nos bastidores daqueles códigos curtos e convenientes do LangChain e do LlamaIndex.
Os exemplos acima usaram páginas da documentação do Milvus baixadas diretamente da Internet. Para mostrar a diferença entre tempos de embedding e tempos de inserção, usarei abaixo um modelo de embedding multimodal de código aberto para 1) gerar embeddings de imagens e textos e 2) inserir os vetores densos no Milvus.
import pymilvus
import requests
from io import BytesIO
# Run this in small batches to avoid memory issues.
BATCH_SIZE = 10
# Batch embed text and images and insert data into Milvus.
batch_embedding_times = []
batch_insert_times = []
for i in range(0, 300, BATCH_SIZE):
batch_images = []
batch_texts = []
batch_urls = []
for j in range(BATCH_SIZE):
if i + j < len(image_texts):
text = image_texts[i + j]
url = image_urls[i + j]
with Image.open(f"./images/{url}.jpg") as img:
batch_images.append(img.copy())
batch_texts.append(text)
batch_urls.append(url)
# STEP 1. EMBEDDING INFERENCE FOR TEXT AND IMAGES.
start_time = time.time()
image_embeddings, text_embeddings = embedding_model(
batch_images=batch_images,
batch_texts=batch_texts)
end_time = time.time()
# print(f"Embedding time for batch size {len(batch_images)}: ", end="")
# print(f"{np.round(end_time - start_time, 2)} seconds")
batch_embedding_times.append(end_time - start_time)
# STEP 2. INSERT CHUNK LIST INTO MILVUS OR ZILLIZ.
chunk_dict_list = []
# Create chunk dict_list.
for chunk, img_url, img_embed, text_embed in zip(
batch_texts,
batch_urls,
image_embeddings, text_embeddings):
chunk_dict = {
'chunk': chunk,
'image_filepath': img_url,
'text_vector': text_embed,
'image_vector': img_embed
}
chunk_dict_list.append(chunk_dict)
start_time = time.time()
try:
col.insert(data=chunk_dict_list)
except:
print(f"Insert error: {img_url}")
end_time = time.time()
# print(f"Insert time for {len(chunk_dict_list)} vectors: ", end="")
# print(f"{np.round(end_time - start_time, 4)} seconds")
batch_insert_times.append(end_time - start_time)
col.flush()
# Calculate the average embedding time.
average_time = np.mean(batch_embedding_times)
print(f"Average embedding time: {round(average_time,2)} seconds")
# Calculate the average insert time.
average_time = np.mean(batch_insert_times)
print(f"Average insert time: {round(average_time,2)} seconds")
Aqui está a saída dos tempos de embedding em lote.
Aqui está a saída dos tempos de inserção de dados em lote no Milvus.
O tempo médio de embedding foi de ~5 segundos, e o tempo médio de inserção no banco de dados vetorial Milvus foi de cerca de um décimo de segundo. Isso se traduz em cerca de 97% do tempo total gasto realizando a geração de embeddings, enquanto cerca de 3% foi gasto na inserção no banco de dados.
Como você pode ver, a etapa de embedding é a que leva mais tempo!
Recursos e Leituras Adicionais
Continue lendo

Expanding Our Global Reach: Zilliz Cloud Launches in Azure Central India
Zilliz Cloud expands to Azure Central India. This new region helps customers meet compliance, reduce latency, and optimize cloud costs when building AI applications.

Democratizing AI: Making Vector Search Powerful and Affordable
Zilliz democratizes AI vector search with Milvus 2.6 and Zilliz Cloud for powerful, affordable scalability, cutting costs in infrastructure, operations, and development.

How to Use Anthropic MCP Server with Milvus
MCP + Milvus: Streamline AI agent development with standardized data access, eliminating integration hassles while enhancing context and flexibility.



