Aclarando malentendidos sobre la velocidad de inserción de datos en Milvus
Muchos usuarios que dependen de LangChain o LlamaIndex por sus pasos de API convenientes y más cortos podrían pensar que "Insertar datos en Milvus es lento." Sin embargo, esta percepción a menudo surge de pasar por alto los pasos detallados del proceso.
Los pasos ocultos
Al usar LangChain o LlamaIndex, estas bibliotecas convierten datos no estructurados (como textos, imágenes o sonidos) en vectores mediante modelos de embeddings. Luego insertan estos vectores en Milvus Lite. Las bibliotecas simplifican este proceso complejo al encargarse de múltiples pasos entre bastidores por ti.
Esta abstracción puede crear la ilusión de que el proceso de inserción de datos tarda mucho tiempo.
El devorador de tiempo: generación de embeddings
El tiempo promedio dedicado a generar embeddings a partir de datos no estructurados es significativamente mayor que el tiempo requerido para insertar datos en Milvus. La lentitud percibida a menudo se debe al proceso computacionalmente intensivo de transformar los datos en representaciones vectoriales, más que al paso de inserción de datos.
Para ilustrar la diferencia entre los tiempos de generación de embeddings y de inserción de datos, mostraré un ejemplo en este blog donde el tiempo promedio de embedding es de aproximadamente 5 segundos. En contraste, el tiempo promedio de inserción en la base de datos vectorial Milvus es de solo alrededor de una décima de segundo. El código completo está en mi GitHub.
En otras palabras, alrededor del 97% del tiempo de "inserción en Milvus" observado en LangChain o LlamaIndex se dedica a la generación de embeddings, mientras que alrededor del 3% se dedica al paso real de inserción en la base de datos.
Mostré en un blog anterior cómo conectarse a Milvus Lite usando LlamaIndex o LangChain.
En las siguientes secciones, cubriré:
Ejemplo de código de LlamaIndex para insertar datos en Milvus
Ejemplo de código de LangChain para insertar datos en Milvus
Ejemplo de código de la API de Pymilvus para insertar datos en Milvus
Ejemplo de código de LlamaIndex para insertar datos en Milvus
Aquí hay un ejemplo de código en 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
)
Ejemplo de código de LangChain para insertar datos en Milvus
Aquí hay un ejemplo de código en 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": {},}
)
Ejemplo de código de la API de Pymilvus para insertar datos en Milvus
Usando llamadas a la API de Pymilvus directamente, mostremos qué está ocurriendo realmente entre bastidores en esas codificaciones breves y convenientes de LangChain y LlamaIndex.
Los ejemplos anteriores utilizaron páginas web de la documentación de Milvus descargadas directamente de Internet. Para mostrar la diferencia entre los tiempos de embedding y los tiempos de inserción, usaré a continuación un modelo de embedding multimodal de código abierto para 1) embeber tanto imágenes como textos y 2) insertar los vectores densos en 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")
Aquí está la salida de los tiempos de embedding por lotes.
Aquí está la salida de los tiempos de inserción de datos por lotes en Milvus.
El tiempo promedio de embedding fue de ~5 segundos, y el tiempo promedio de inserción en la base de datos vectorial Milvus fue de aproximadamente una décima de segundo. Esto se traduce en aproximadamente el 97% del tiempo total dedicado a realizar la generación de embeddings, mientras que alrededor del 3% se dedicó a la inserción en la base de datos.
Como puedes ver, ¡el paso de embedding es el que más tarda!
Recursos y lecturas adicionales
Sigue leyendo

Zilliz Cloud Just Landed in Claude Code
The Zilliz Cloud Plugin brings the full power of Zilliz Cloud directly into your Claude Code terminal as natural-language conversations.

Zilliz Cloud Introduces Advanced BYOC-I Solution for Ultimate Enterprise Data Sovereignty
Explore Zilliz Cloud BYOC-I, the solution that balances AI innovation with data control, enabling secure deployments in finance, healthcare, and education sectors.

What is the K-Nearest Neighbors (KNN) Algorithm in Machine Learning?
KNN is a supervised machine learning technique and algorithm for classification and regression. This post is the ultimate guide to KNN.



