> For the complete documentation index, see [llms.txt](https://docs.clore.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.clore.ai/guides/guides_v2-es/rag-y-bases-de-datos-vectoriales/milvus.md).

# Milvus

> **La base de datos vectorial de código abierto más escalable para aplicaciones de IA — diseñada para miles de millones de vectores**

Milvus es una base de datos vectorial de código abierto diseñada específicamente para búsquedas de similitud escalables y aplicaciones de IA. Creado originalmente por Zilliz y donado a la fundación LF AI & Data, Milvus impulsa cargas de trabajo de IA en producción en empresas como NVIDIA, AT\&T, IBM y Salesforce. Es la opción ideal cuando necesitas escalar a miles de millones de vectores.

**GitHub:** [milvus-io/milvus](https://github.com/milvus-io/milvus) — 32K+ ⭐

***

## Milvus vs Qdrant — Cuándo elegir cada uno

| Criterios                    | Milvus                            | Qdrant                |
| ---------------------------- | --------------------------------- | --------------------- |
| Escala                       | Miles de millones de vectores     | Cientos de millones   |
| Arquitectura                 | Distribuido (múltiples servicios) | Binario único         |
| Complejidad de configuración | Más alto                          | Reduce                |
| Soporte para índices GPU     | ✅ FAISS GPU nativo                | Limitado              |
| Multitenencia                | ✅ Particiones + alias             | Basado en colecciones |
| Ingesta por streaming        | ✅ Kafka/Pulsar                    | Limitado              |
| Búsqueda híbrida             | ✅ Denso + disperso                | ✅                     |
| Opción gestionada en la nube | Zilliz Cloud                      | Qdrant Cloud          |

{% hint style="success" %}
**Elige Milvus cuando:** Necesitas escalar a miles de millones de vectores, requieres indexación acelerada por GPU (IVF\_FLAT\_GPU) o necesitas funciones empresariales como multitenencia, ingesta por streaming y control de acceso basado en roles.
{% endhint %}

***

## Arquitectura de Milvus

Milvus en modo standalone (un solo servidor) incluye:

* **milvus** — el servicio principal (proxy, coordinadores de consulta, datos e índices)
* **etcd** — almacenamiento de metadatos y descubrimiento de servicios
* **MinIO** — almacenamiento de objetos para los datos de segmentos

En modo distribuido (clúster), cada componente escala de forma independiente.

***

## Requisitos previos

* Cuenta de Clore.ai con alquiler de GPU
* Docker Compose (normalmente preinstalado)
* Conocimientos básicos de Python
* 16 GB+ de RAM (se recomiendan 32 GB para producción)

***

## Paso 1 — Alquila un servidor GPU en Clore.ai

1. Ve a [clore.ai](https://clore.ai) → **Marketplace**
2. **GPU recomendada:** RTX 4090 o A100 para indexación acelerada por GPU
3. **Alternativa de CPU:** Cualquier servidor con 32 GB+ de RAM para indexación basada en CPU

**Requisitos mínimos:**

* CPU: 8 núcleos
* RAM: 16 GB (se recomiendan 32 GB)
* Disco: 50 GB SSD/NVMe
* GPU: Opcional (solo requerida para tipos de índice GPU)

{% hint style="info" %}
**Tipos de índice GPU en Milvus** (IVF\_FLAT\_GPU, IVFSQ8\_GPU) requieren GPU compatibles con CUDA y aceleran drásticamente la construcción del índice para colecciones grandes. Si planeas indexar 10M+ vectores con frecuencia, la indexación con GPU se amortiza rápidamente.
{% endhint %}

***

## Paso 2 — Despliega Milvus Standalone

**Imagen de Docker:**

```
milvusdb/milvus:v2.4.0
```

Milvus standalone requiere etcd y MinIO. Usa Docker Compose para la configuración más sencilla.

**Puertos:**

```
22
19530
```

* **Puerto 19530:** Puerto SDK/gRPC de Milvus (principal)
* **Puerto 9091:** API REST de Milvus y verificación de estado (interna)

**Variables de entorno:**

```
NVIDIA_VISIBLE_DEVICES=all
NVIDIA_DRIVER_CAPABILITIES=compute,utility
```

***

## Paso 3 — Configúralo con Docker Compose

Conéctate por SSH a tu servidor de Clore.ai y crea el archivo compose:

```bash
ssh root@<ip-del-servidor> -p <puerto-ssh>

# Instala Docker Compose si no está presente
which docker-compose || pip install docker-compose
# O usa el complemento de Docker:
docker compose version

# Crea el directorio del proyecto
mkdir -p /opt/milvus && cd /opt/milvus

# Descarga el archivo compose oficial de Milvus standalone
wget https://github.com/milvus-io/milvus/releases/download/v2.4.0/milvus-standalone-docker-compose.yml \
    -O docker-compose.yml

# Revisa el archivo compose
cat docker-compose.yml
```

### Personaliza docker-compose.yml

```yaml
version: '3.5'

services:
  etcd:
    container_name: milvus-etcd
    image: quay.io/coreos/etcd:v3.5.5
    environment:
      - ETCD_AUTO_COMPACTION_MODE=revision
      - ETCD_AUTO_COMPACTION_RETENTION=1000
      - ETCD_QUOTA_BACKEND_BYTES=4294967296
      - ETCD_SNAPSHOT_COUNT=50000
    volumes:
      - /opt/milvus/etcd:/etcd
    command: etcd -advertise-client-urls=http://127.0.0.1:2379 -listen-client-urls http://0.0.0.0:2379 --data-dir /etcd
    healthcheck:
      test: ["CMD", "etcdctl", "endpoint", "health"]
      interval: 30s
      timeout: 20s
      retries: 3

  minio:
    container_name: milvus-minio
    image: minio/minio:RELEASE.2023-03-13T19-46-17Z
    environment:
      MINIO_ACCESS_KEY: minioadmin
      MINIO_SECRET_KEY: minioadmin
    ports:
      - "9001:9001"
      - "9000:9000"
    volumes:
      - /opt/milvus/minio:/minio_data
    command: minio server /minio_data --console-address ":9001"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
      interval: 30s
      timeout: 20s
      retries: 3

  standalone:
    container_name: milvus-standalone
    image: milvusdb/milvus:v2.4.0
    command: ["milvus", "run", "standalone"]
    security_opt:
      - seccomp:unconfined
    environment:
      ETCD_ENDPOINTS: etcd:2379
      MINIO_ADDRESS: minio:9000
    volumes:
      - /opt/milvus/milvus:/var/lib/milvus
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:9091/healthz"]
      interval: 30s
      start_period: 90s
      timeout: 20s
      retries: 3
    ports:
      - "19530:19530"
      - "9091:9091"
    depends_on:
      - "etcd"
      - "minio"
    deploy:
      resources:
        reservations:
          devices:
            - capabilities: [gpu]  # Habilitar acceso a GPU
```

### Inicia Milvus

```bash
cd /opt/milvus
docker compose up -d

# Espera a que los servicios se inicien (~60 segundos)
sleep 60

# Comprueba que todos los servicios estén sanos
docker compose ps

# Comprueba la salud de Milvus
curl http://localhost:9091/healthz
# Esperado: {"status":"ok"}

# Ver registros
docker compose logs -f standalone --tail 50
```

***

## Paso 4 — Instala el cliente Python

```bash
pip install pymilvus sentence-transformers numpy tqdm

# Verifica la conexión
python3 << 'EOF'
from pymilvus import connections, utility

connections.connect("default", host="localhost", port="19530")
print(f"¡Milvus conectado!")
print(f"Versión: {utility.get_server_version()}")
EOF
```

***

## Paso 5 — Crea una colección

En Milvus, una **colección** es similar a una tabla de base de datos. Tiene un esquema con campos tipados, incluidos campos vectoriales.

```python
from pymilvus import (
    connections,
    FieldSchema,
    CollectionSchema,
    DataType,
    Collection,
    utility
)

# Conectar
connections.connect("default", host="localhost", port="19530")

# Definir esquema
fields = [
    FieldSchema(
        name="id",
        dtype=DataType.INT64,
        is_primary=True,
        auto_id=True           # Generar IDs automáticamente
    ),
    FieldSchema(
        name="text",
        dtype=DataType.VARCHAR,
        max_length=2048        # Longitud máxima del texto
    ),
    FieldSchema(
        name="source",
        dtype=DataType.VARCHAR,
        max_length=256
    ),
    FieldSchema(
        name="category",
        dtype=DataType.VARCHAR,
        max_length=128
    ),
    FieldSchema(
        name="year",
        dtype=DataType.INT32
    ),
    FieldSchema(
        name="embedding",
        dtype=DataType.FLOAT_VECTOR,
        dim=384                # Dimensión de tu modelo de embeddings
    )
]

schema = CollectionSchema(
    fields=fields,
    description="Embeddings de documentos para búsqueda semántica",
    enable_dynamic_field=True  # Permitir añadir campos que no están en el esquema
)

# Crear colección
collection_name = "documents"
if utility.has_collection(collection_name):
    utility.drop_collection(collection_name)

collection = Collection(
    name=collection_name,
    schema=schema,
    using="default"
)
print(f"¡Colección '{collection_name}' creada!")
```

***

## Paso 6 — Crea el índice

Antes de cargar datos para la búsqueda, crea un índice adecuado:

```python
from pymilvus import Collection

collection = Collection("documents")

# Índice HNSW (mejor para la mayoría de los casos de uso, baja latencia)
hnsw_params = {
    "metric_type": "COSINE",     # COSINE, L2 o IP (producto interno)
    "index_type": "HNSW",
    "params": {
        "M": 16,                 # Conectividad del grafo HNSW (8-64)
        "efConstruction": 200    # Profundidad de búsqueda al construir
    }
}

# Índice IVF_FLAT (CPU, bueno para colecciones grandes)
ivf_params = {
    "metric_type": "COSINE",
    "index_type": "IVF_FLAT",
    "params": {
        "nlist": 1024            # Número de clústeres (normalmente la raíz cuadrada del tamaño de los datos)
    }
}

# Índice GPU_IVF_FLAT (requiere GPU CUDA — el más rápido para consultas por lotes)
gpu_ivf_params = {
    "metric_type": "L2",
    "index_type": "GPU_IVF_FLAT",
    "params": {
        "nlist": 1024,
        "cache_dataset_on_device": True
    }
}

# Crear índice en el campo de embeddings
collection.create_index(
    field_name="embedding",
    index_params=hnsw_params,
    index_name="embedding_idx"
)

# Crear un índice escalar para búsquedas filtradas
collection.create_index(field_name="category", index_name="category_idx")
collection.create_index(field_name="year", index_name="year_idx")

print("¡Índices creados!")
collection.load()  # Cargar en memoria para buscar
```

***

## Paso 7 — Inserta datos

```python
from pymilvus import Collection
from sentence_transformers import SentenceTransformer
import tqdm

collection = Collection("documents")
model = SentenceTransformer("all-MiniLM-L6-v2", device="cuda")

# Tus documentos
documents = [
    {
        "text": "Milvus es una base de datos vectorial de código abierto para aplicaciones de IA escalables.",
        "source": "documentación",
        "category": "base de datos",
        "year": 2024
    },
    {
        "text": "HNSW proporciona una búsqueda rápida de vecinos más cercanos aproximados con alto recall.",
        "source": "investigación",
        "category": "algoritmo",
        "year": 2023
    },
    {
        "text": "La indexación acelerada por GPU reduce drásticamente el tiempo de construcción para colecciones vectoriales grandes.",
        "source": "blog",
        "category": "rendimiento",
        "year": 2024
    },
    # Añade aquí miles de documentos más
]

def insert_batch(docs: list, batch_size: int = 1000):
    texts = [d["text"] for d in docs]
    
    # Embeddings acelerados por GPU
    embeddings = model.encode(
        texts,
        batch_size=256,
        show_progress_bar=False,
        normalize_embeddings=True
    )
    
    # Insertar en Milvus
    data = {
        "text": [d["text"] for d in docs],
        "source": [d["source"] for d in docs],
        "category": [d["category"] for d in docs],
        "year": [d["year"] for d in docs],
        "embedding": embeddings.tolist()
    }
    
    result = collection.insert(data)
    return result.insert_count

# Insertar por lotes
BATCH_SIZE = 1000
total_inserted = 0

for i in range(0, len(documents), BATCH_SIZE):
    batch = documents[i:i + BATCH_SIZE]
    count = insert_batch(batch)
    total_inserted += count
    print(f"Insertados {total_inserted}/{len(documents)} documentos")

# Vaciar para asegurar que los datos se persistan y se indexen
collection.flush()
print(f"Total insertados y vaciados: {total_inserted}")
```

***

## Paso 8 — Busca y consulta

### Búsqueda semántica básica

```python
from pymilvus import Collection
from sentence_transformers import SentenceTransformer

collection = Collection("documents")
collection.load()

model = SentenceTransformer("all-MiniLM-L6-v2", device="cuda")

def search(query: str, top_k: int = 10):
    query_embedding = model.encode(
        [query],
        normalize_embeddings=True
    )[0].tolist()
    
    results = collection.search(
        data=[query_embedding],
        anns_field="embedding",
        param={
            "metric_type": "COSINE",
            "params": {"ef": 64}    # Parámetro de tiempo de búsqueda de HNSW (ef >= top_k)
        },
        limit=top_k,
        output_fields=["text", "source", "category", "year"]
    )
    
    return results[0]

# Buscar
hits = search("¿cómo funciona la búsqueda de similitud vectorial?")
for hit in hits:
    print(f"Puntuación: {hit.score:.4f}")
    print(f"Texto: {hit.entity.get('text')[:100]}")
    print(f"Fuente: {hit.entity.get('source')}")
    print()
```

### Búsqueda filtrada

```python
from pymilvus import Collection

collection = Collection("documents")

# Buscar con filtro de metadatos (expresión booleana)
results = collection.search(
    data=[query_embedding],
    anns_field="embedding",
    param={"metric_type": "COSINE", "params": {"ef": 64}},
    limit=10,
    expr='category == "base de datos" and year >= 2023',  # Filtro booleano
    output_fields=["text", "category", "year"]
)
```

### Búsqueda híbrida (densa + dispersa)

```python
# Milvus 2.4+ admite búsqueda híbrida densa+dispersa
from pymilvus import AnnSearchRequest, WeightedRanker, Collection

collection = Collection("documents")

# Solicitud de búsqueda densa
dense_req = AnnSearchRequest(
    data=[dense_embedding],
    anns_field="embedding",
    param={"metric_type": "COSINE", "params": {"ef": 64}},
    limit=20
)

# Solicitud de búsqueda dispersa (requiere un campo de vector disperso)
sparse_req = AnnSearchRequest(
    data=[sparse_embedding],
    anns_field="sparse_embedding",
    param={"metric_type": "IP"},
    limit=20
)

# Combinar con Reciprocal Rank Fusion
results = collection.hybrid_search(
    [dense_req, sparse_req],
    rerank=WeightedRanker(0.7, 0.3),  # 70% densa, 30% dispersa
    limit=10,
    output_fields=["text"]
)
```

***

## Paso 9 — Crea un servicio RAG

```bash
pip install fastapi uvicorn openai

cat > /workspace/milvus_rag.py << 'EOF'
from fastapi import FastAPI
from pydantic import BaseModel
from pymilvus import Collection, connections
from sentence_transformers import SentenceTransformer
from openai import OpenAI
import os

app = FastAPI(title="API RAG de Milvus")

# Inicializar al inicio
connections.connect("default", host="localhost", port="19530")
collection = Collection("documents")
collection.load()
embedder = SentenceTransformer("all-MiniLM-L6-v2", device="cuda")
llm = OpenAI(api_key=os.environ["OPENAI_API_KEY"])

class QueryRequest(BaseModel):
    question: str
    n_results: int = 5

@app.get("/health")
async def health():
    return {"status": "ok", "vectors": collection.num_entities}

@app.post("/search")
async def semantic_search(req: QueryRequest):
    embedding = embedder.encode(
        [req.question],
        normalize_embeddings=True
    )[0].tolist()
    
    results = collection.search(
        data=[embedding],
        anns_field="embedding",
        param={"metric_type": "COSINE", "params": {"ef": 64}},
        limit=req.n_results,
        output_fields=["text", "source", "category"]
    )
    
    return {
        "results": [
            {
                "text": hit.entity.get("text"),
                "source": hit.entity.get("source"),
                "score": hit.score
            }
            for hit in results[0]
        ]
    }

@app.post("/rag")
async def rag(req: QueryRequest):
    embedding = embedder.encode([req.question], normalize_embeddings=True)[0].tolist()
    
    hits = collection.search(
        data=[embedding],
        anns_field="embedding",
        param={"metric_type": "COSINE", "params": {"ef": 64}},
        limit=req.n_results,
        output_fields=["text", "source"]
    )[0]
    
    context = "\n\n".join([
        f"[{hit.entity.get('source')}]: {hit.entity.get('text')}"
        for hit in hits if hit.score > 0.4
    ])
    
    response = llm.chat.completions.create(
        model="gpt-4o-mini",
        messages=[
            {"role": "system", "content": "Responde basándote en el contexto. Sé conciso."},
            {"role": "user", "content": f"Contexto:\n{context}\n\nPregunta: {req.question}"}
        ]
    )
    
    return {"answer": response.choices[0].message.content, "context_used": len(hits)}

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)
EOF

python3 /workspace/milvus_rag.py
```

***

## Paso 10 — Supervisar y gestionar

```python
from pymilvus import connections, utility, Collection

connections.connect("default", host="localhost", port="19530")

# Listar todas las colecciones
print("Colecciones:", utility.list_collections())

# Estadísticas de la colección
col = Collection("documents")
print(f"Cantidad de entidades: {col.num_entities:,}")
print(f"Esquema: {col.schema}")

# Gestión de particiones
col.create_partition("2024_docs")
col.create_partition("2023_docs")

# Insertar con partición
col.insert(data, partition_name="2024_docs")

# Buscar en una partición específica
results = col.search(
    data=[query_vec],
    anns_field="embedding",
    param={"metric_type": "COSINE", "params": {"ef": 64}},
    limit=10,
    partition_names=["2024_docs"]  # Buscar solo en esta partición
)
```

***

## Solución de problemas

### Los servicios no se inician

```bash
# Compruebe los registros del contenedor
docker compose logs etcd
docker compose logs minio
docker compose logs standalone

# Comprobar el espacio en disco
df -h /opt/milvus

# Reiniciar servicios
docker compose restart
```

### Conexión rechazada en 19530

```bash
# Verificar que Milvus está escuchando
netstat -tlnp | grep 19530

# Comprobar el estado
curl http://localhost:9091/healthz

# Dar tiempo para el arranque (90 segundos)
docker compose logs standalone | tail -20
```

### Tiempo de espera agotado para la construcción de índices en colecciones grandes

```python
# Aumentar el tiempo de espera para construcciones de índices grandes
from pymilvus import Collection

collection = Collection("documents")
collection.create_index(
    field_name="embedding",
    index_params=hnsw_params,
    timeout=3600  # tiempo de espera de 1 hora
)
```

### Alto uso de memoria

```bash
# Configurar los límites de memoria de Milvus en docker-compose.yml
# Añadir al servicio standalone:
deploy:
  resources:
    limits:
      memory: 16g
```

***

## Guía de selección del tipo de índice

| Tipo de índice | Ideal para                     | Memoria      | Velocidad | Se requiere GPU |
| -------------- | ------------------------------ | ------------ | --------- | --------------- |
| FLAT           | Pequeño (<1M), búsqueda exacta | Alta         | Lento     | No              |
| IVF\_FLAT      | Medio (1M–10M)                 | Medio        | Bueno     | No              |
| HNSW           | Baja latencia, <100M           | Alta         | Excelente | No              |
| IVF\_SQ8       | Comprimido, grande             | Baja         | Bueno     | No              |
| GPU\_IVF\_FLAT | Consultas por lotes rápidas    | GPU+RAM      | Mejor     | Sí              |
| DISKANN        | Escala de miles de millones    | Bajo (disco) | Bueno     | No              |

***

## Puntos de referencia de rendimiento

| Tamaño de la colección   | Índice         | GPU      | QPS      |
| ------------------------ | -------------- | -------- | -------- |
| 1 millón de vectores     | HNSW           | RTX 3090 | \~8,000  |
| 10 millones de vectores  | IVF\_FLAT      | RTX 4090 | \~2,500  |
| 10 millones de vectores  | GPU\_IVF\_FLAT | A100     | \~12,000 |
| 100 millones de vectores | DISKANN        | A100     | \~1,200  |

***

## Recursos adicionales

* [Documentación de Milvus](https://milvus.io/docs)
* [GitHub de Milvus](https://github.com/milvus-io/milvus)
* [Documentación de PyMilvus](https://milvus.io/api-reference/pymilvus/v2.4.x/About.md)
* [Bootcamp de Milvus](https://github.com/milvus-io/bootcamp) — Aplicaciones de ejemplo
* [Zilliz Cloud](https://cloud.zilliz.com/) — Milvus administrado
* [Comparación de bases de datos vectoriales](https://milvus.io/docs/benchmark.md)
* [Interfaz gráfica de Attu](https://github.com/zilliztech/attu) — Interfaz web para la administración de Milvus

***

*Milvus en Clore.ai es la solución ideal para aplicaciones de IA que necesitan escalar más allá de cientos de millones de vectores. Combinado con la generación de embeddings acelerada por GPU, puedes construir sistemas de búsqueda semántica y RAG de clase mundial a una fracción de los costos de la nube administrada.*

***

## Recomendaciones de GPU para Clore.ai

| Caso de uso                      | GPU recomendada | Costo estimado en Clore.ai |
| -------------------------------- | --------------- | -------------------------- |
| Desarrollo/Pruebas               | RTX 3090 (24GB) | $0.07–0.21/gpu/hr          |
| Búsqueda vectorial de producción | RTX 3090 (24GB) | $0.07–0.21/gpu/hr          |
| Embeddings de alto rendimiento   | RTX 4090 (24GB) | $0.14–0.42/gpu/hr          |

> 💡 Todos los ejemplos de esta guía pueden desplegarse en [Clore.ai](https://clore.ai/marketplace) servidores GPU. Explora las GPUs disponibles y alquila por hora: sin compromisos, acceso root completo.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.clore.ai/guides/guides_v2-es/rag-y-bases-de-datos-vectoriales/milvus.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
