Развенчиваем заблуждения о скорости вставки данных в Milvus
Многие пользователи, полагающиеся на LangChain или LlamaIndex из-за их удобных и более коротких шагов API, могут думать, что «Вставка данных в Milvus медленная». Однако такое восприятие часто возникает из-за поверхностного рассмотрения подробных этапов процесса.
Скрытые шаги
При использовании LangChain или LlamaIndex эти библиотеки преобразуют неструктурированные данные (например, тексты, изображения или звуки) в векторы с помощью моделей эмбеддингов. Затем они вставляют эти векторы в Milvus Lite. Библиотеки упрощают этот сложный процесс, выполняя за вас множество шагов за кулисами.
Эта абстракция может создавать иллюзию, что процесс вставки данных занимает много времени.
Пожиратель времени: генерация эмбеддингов
Среднее время, затрачиваемое на генерацию эмбеддингов из неструктурированных данных, значительно превышает время, необходимое для вставки данных в Milvus. Воспринимаемая медлительность часто связана с вычислительно интенсивным процессом преобразования данных в векторные представления, а не с этапом вставки данных.
Чтобы проиллюстрировать разницу между временем генерации эмбеддингов и временем вставки данных, я покажу пример в этом блоге, где среднее время эмбеддинга составляет примерно 5 секунд. Напротив, среднее время вставки в векторную базу данных Milvus составляет всего около одной десятой секунды. Полный код находится на моем GitHub.
Другими словами, около 97% времени "вставки Milvus", наблюдаемого в LangChain или LlamaIndex, тратится на генерацию эмбеддингов, тогда как около 3% уходит на фактический этап вставки в базу данных.
В предыдущем блоге я показал, как подключиться к Milvus Lite с помощью LlamaIndex или LangChain.
В следующих разделах я рассмотрю:
Пример кода LlamaIndex для вставки данных в Milvus
Пример кода LangChain для вставки данных в Milvus
Пример кода Pymilvus API для вставки данных в Milvus
Пример кода LlamaIndex для вставки данных в Milvus
Вот пример кода в 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
)
Пример кода LangChain для вставки данных в Milvus
Вот пример кода в 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": {},}
)
Пример кода Pymilvus API для вставки данных в Milvus
Используя вызовы Pymilvus API напрямую, покажем, что на самом деле происходит за кулисами этих коротких и удобных фрагментов кода LangChain и LlamaIndex.
В приведённых выше примерах использовались веб-страницы документации Milvus, загруженные напрямую из Интернета. Чтобы показать разницу между временем создания эмбеддингов и временем вставки, ниже я использую open-source мультимодальную модель эмбеддингов, чтобы 1) создавать эмбеддинги как для изображений, так и для текстов и 2) вставлять плотные векторы в 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")
Вот вывод времени пакетного создания эмбеддингов.
Вот вывод времени пакетной вставки данных в Milvus.
Среднее время создания эмбеддингов составило ~5 секунд, а среднее время вставки в векторную базу данных Milvus — около одной десятой секунды. Это означает, что около 97% общего времени было затрачено на генерацию эмбеддингов, тогда как около 3% — на вставку в базу данных.
Как видите, этап создания эмбеддингов занимает больше всего времени!
Ресурсы и дополнительная литература
Читать далее

Zilliz Cloud On-Demand Compute: Pay Only for What You Use
The customer case behind Zilliz Cloud On-Demand: how a $10K vector search bill came down to under $500, and the engineering changes that made it possible.

How to Install and Run OpenClaw (Previously Clawdbot/Moltbot) on Mac
Turn your Mac into an AI gateway for WhatsApp, Telegram, Discord, iMessage, and more — in under 5 minutes.

Smarter Autoscaling in Zilliz Cloud: Always Optimized for Every Workload
With the latest upgrade, Zilliz Cloud introduces smarter autoscaling—a fully automated, more streamlined, elastic resource management system.



