# Milvus User Guide

Milvus is a high-performance, open-source **vector database** built for scale. It stores
the vector embeddings produced by AI models alongside scalar metadata, and lets you run
similarity search, filtered search, full-text search, and hybrid search over billions of
vectors with low latency. Written in Go and C++ with hardware acceleration for CPU and GPU,
Milvus powers applications such as retrieval-augmented generation (RAG), semantic search,
recommendation systems, image and video search, and anomaly detection.

This guide shows you how to install Milvus, connect to it, model your data, ingest vectors,
build indexes, and run searches. It is organized by user journey: start with **Quick Start**,
deploy with **Installation**, then work through **Everyday Usage**, **Search Workflows**, and
**Advanced Features**. Deep architecture, the complete configuration reference, deployment
topologies, and security hardening live in the companion **Admin Guide**.

> [!NOTE]
> Milvus exposes three client surfaces for the same server: the **gRPC API** (default port
> `19530`), a **RESTful API** (`/v2/vectordb/...` on the same port), and official SDKs for
> Python (`pymilvus`), Go (shipped in this repository under `client/`), Java, and Node.js.
> Examples in this guide use Python (`pymilvus`) and the in-repository Go SDK.

---

## 1. Quick Start

The fastest way to try Milvus is **Milvus Lite**, an embedded build that runs inside your
Python process and persists to a local file — no server, no Docker.

=== "Python (Milvus Lite)"

    ```bash
    pip install -U pymilvus
    ```

    ```python
    from pymilvus import MilvusClient

    # A local file name turns on Milvus Lite (embedded, no server).
    client = MilvusClient("milvus_demo.db")

    client.create_collection(
        collection_name="demo_collection",
        dimension=768,  # dimension of the vectors you will store
    )

    # Insert data: each row needs an "id", a "vector", and any extra fields.
    res = client.insert(collection_name="demo_collection", data=data)

    # Search with one or more query vectors.
    res = client.search(
        collection_name="demo_collection",
        data=query_vectors,           # a list of one or more query vectors
        limit=2,                      # top-K results to return
        output_fields=["text", "subject"],
    )
    ```

=== "Python (remote server)"

    ```python
    from pymilvus import MilvusClient

    client = MilvusClient(
        uri="http://localhost:19530",
        token="root:Milvus",          # default credentials, change in production
    )
    ```

=== "Go (in-repo SDK)"

    ```go
    import (
        "context"
        "github.com/milvus-io/milvus/client/v2/milvusclient"
    )

    ctx := context.Background()
    cli, err := milvusclient.New(ctx, &milvusclient.ClientConfig{
        Address:  "localhost:19530",
        Username: "root",
        Password: "Milvus",
    })
    if err != nil {
        // handle error
    }
    defer cli.Close(ctx)
    ```

> [!TIP]
> Milvus Lite is ideal for prototyping, unit tests, and notebooks. When your dataset or
> traffic grows, move to **Standalone** (single container) or a **distributed cluster** with
> no code changes — only the connection URI changes. See [Installation](#2-installation).

> [!IMPORTANT]
> The vector `dimension` is fixed when you create a collection and **cannot be changed**
> afterward. It must exactly match the output dimension of the embedding model you use
> (for example, 768 for many sentence-transformer models, 1536 for OpenAI `text-embedding-3-small`).

---

## 2. Installation

Milvus ships in four deployment shapes. Choose by scale and operational appetite.

| Deployment | What it is | Best for |
|---|---|---|
| **Milvus Lite** | Embedded library inside your Python process; persists to a local file | Prototyping, notebooks, tests, small local data |
| **Standalone** | A single Docker container plus `etcd` and `MinIO` dependencies | Single-machine production, dev/staging, up to tens of millions of vectors |
| **Distributed cluster** | Separately scaled coordinator and worker services on Kubernetes | Billions of vectors, high availability, elastic scale |
| **Zilliz Cloud** | Fully managed Milvus (not part of this repository) | Zero-ops production |

This User Guide focuses on Milvus Lite and Standalone. Cluster topology, sizing, and the full
container/Helm reference are covered in the **Admin Guide**.

### 2.1 Requirements

For the Standalone Docker deployment you need:

- [ ] Docker Engine and the Docker Compose plugin
- [ ] At least 4 CPU cores and 8 GB RAM (more for larger datasets)
- [ ] Sufficient free disk for object storage (vectors, indexes, and logs)

> [!NOTE]
> Standalone runs three containers: `milvus-etcd` (metadata + service discovery),
> `milvus-minio` (object storage for vector and index files), and `milvus-standalone`
> (the Milvus server itself). All three are defined in the official
> `deployments/docker/standalone/docker-compose.yml`.

### 2.2 Install Standalone with Docker Compose

The official Compose file launches the full standalone stack:

```yaml
services:
  etcd:
    container_name: milvus-etcd
    image: quay.io/coreos/etcd:v3.5.25
    environment:
      - ETCD_AUTO_COMPACTION_MODE=revision
      - ETCD_AUTO_COMPACTION_RETENTION=1000
      - ETCD_QUOTA_BACKEND_BYTES=4294967296
      - ETCD_SNAPSHOT_COUNT=50000
    volumes:
      - ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/etcd:/etcd
    command: etcd -advertise-client-urls=http://etcd:2379 -listen-client-urls http://0.0.0.0:2379 --data-dir /etcd

  minio:
    container_name: milvus-minio
    image: minio/minio:RELEASE.2024-05-28T17-19-04Z
    environment:
      MINIO_ACCESS_KEY: minioadmin
      MINIO_SECRET_KEY: minioadmin
    ports:
      - "9001:9001"
      - "9000:9000"
    volumes:
      - ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/minio:/minio_data
    command: minio server /minio_data --console-address ":9001"

  standalone:
    container_name: milvus-standalone
    image: milvusdb/milvus:v3.0-beta
    command: ["milvus", "run", "standalone"]
    security_opt:
      - seccomp:unconfined
    environment:
      MINIO_REGION: us-east-1
      ETCD_ENDPOINTS: etcd:2379
      MINIO_ADDRESS: minio:9000
    volumes:
      - ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/milvus:/var/lib/milvus
    ports:
      - "19530:19530"
      - "9091:9091"
    depends_on:
      - "etcd"
      - "minio"
```

Bring the stack up:

```bash
sudo docker compose up -d
```

```text
Creating milvus-etcd  ... done
Creating milvus-minio ... done
Creating milvus-standalone ... done
```

Verify the server is healthy:

```bash
curl -f http://localhost:9091/healthz
```

```text
OK
```

> [!TIP]
> Port `19530` serves both the gRPC API and the RESTful API for your clients. Port `9091`
> serves the health check (`/healthz`), Prometheus metrics (`/metrics`), and the built-in
> Web UI. The MinIO console is on `9001`.

> [!CAUTION]
> The default credentials baked into a fresh install are username `root` and password
> `Milvus`. Change them before exposing Milvus to any untrusted network. See
> [Authentication](#71-connect-with-authentication) and the Admin Guide security chapter.

### 2.3 The `milvus` binary and server roles

Inside the container, the `milvus` binary is the single entry point for every server role.
Standalone is simply the all-in-one role:

```bash
milvus run standalone
```

The binary accepts the following top-level commands:

| Command | Purpose |
|---|---|
| `milvus run <server type> [flags]` | Start a Milvus server of the given type |
| `milvus stop <server type> [flags]` | Stop a running Milvus server |
| `milvus mck run [flags]` | Run a metadata/data consistency check |
| `milvus mck cleanTrash [flags]` | Clean inconsistent (orphaned) data found by `mck` |
| `milvus dry-run <server type>` | Validate startup without running the server |

The valid **server types** are `standalone`, `mixture`, `mixcoord`, `rootcoord`,
`querycoord`, `datacoord`, `proxy`, `querynode`, `datanode`, `streamingnode`, `cdc`, and
`embedded`. For everyday use you only need `standalone`; the individual roles are for
distributed deployments and are detailed in the Admin Guide.

> [!NOTE]
> The `mck` (Milvus Consistency Check) command is an operator tool that scans `etcd` and
> object storage for orphaned task and segment references. It is covered in the Admin Guide
> under operations; most users never need it.

### 2.4 Stop and remove

```bash
sudo docker compose down                 # stop containers
sudo rm -rf volumes                       # delete persisted data (irreversible)
```

> [!WARNING]
> `rm -rf volumes` permanently deletes all collections, vectors, indexes, and metadata.
> There is no undo. Back up first if the data matters — see the Admin Guide on snapshots
> and RBAC backup.

---

## 3. Core Concepts

A few concepts recur throughout this guide. Skim them now; later sections assume them.

**Collection**
: The top-level container for your data, analogous to a table in a relational database. A
  collection has a fixed **schema** of fields.

**Schema**
: The set of fields in a collection. Exactly one field is the **primary key**. At least one
  field is a **vector field**. Other fields hold scalar metadata.

**Entity**
: A single row — one primary key, one or more vectors, and the scalar field values.

**Field**
: A typed column. Vector fields hold embeddings; scalar fields hold filterable metadata.

**Index**
: A data structure built over a vector or scalar field to accelerate search. You choose an
  **index type** and a **metric type** per vector field.

**Partition**
: A horizontal slice of a collection. Searching a single partition is faster than searching
  the whole collection. A special **partition key** field can auto-route entities to
  partitions.

**Database**
: A namespace that groups collections, enabling multi-tenancy within one Milvus instance.

**Load / Release**
: A collection must be **loaded** into memory (on query nodes) before it can be searched, and
  can be **released** to free memory.

**Consistency level**
: How fresh search results are guaranteed to be — `Strong`, `Bounded` (default), `Session`,
  or `Eventually`. See [Consistency Levels](#82-consistency-levels).

> [!IMPORTANT]
> The lifecycle is always: **create collection → insert data → create index → load → search**.
> You cannot search a collection that has not been loaded, and load requires an index on every
> vector field (or an `AUTOINDEX`).

---

## 4. Data Modeling

### 4.1 Field data types

Milvus supports the following field types (Go SDK names from `client/entity/field.go`; the
Python and REST names are equivalent):

| Category | Types |
|---|---|
| Boolean | `Bool` |
| Integer | `Int8`, `Int16`, `Int32`, `Int64` |
| Floating point | `Float`, `Double` |
| String | `VarChar` (requires `max_length`) |
| Structured | `JSON`, `Array` (typed elements), `Geometry` |
| Dense vectors | `FloatVector`, `Float16Vector`, `BFloat16Vector`, `Int8Vector`, `BinaryVector` |
| Sparse vectors | `SparseFloatVector` |

> [!NOTE]
> The primary key field must be `Int64` or `VarChar`. A collection must have at least one
> vector field and may have several (multi-vector collections enable hybrid search across
> modalities).

### 4.2 Create a collection (quick schema)

For simple cases, let Milvus infer a minimal schema from a dimension and use `AUTOINDEX`:

```python
client.create_collection(
    collection_name="demo_collection",
    dimension=768,                 # creates an Int64 primary key "id" + FloatVector "vector"
    metric_type="COSINE",          # distance metric for search
    consistency_level="Bounded",   # default
)
```

### 4.3 Create a collection (explicit schema)

For production, define every field explicitly:

=== "Python"

    ```python
    from pymilvus import MilvusClient, DataType

    schema = MilvusClient.create_schema(
        auto_id=False,
        enable_dynamic_field=True,
    )
    schema.add_field("id", DataType.INT64, is_primary=True)
    schema.add_field("vector", DataType.FLOAT_VECTOR, dim=768)
    schema.add_field("text", DataType.VARCHAR, max_length=2048)
    schema.add_field("subject", DataType.VARCHAR, max_length=256)

    client.create_collection(
        collection_name="articles",
        schema=schema,
        consistency_level="Bounded",
    )
    ```

=== "Go"

    ```go
    import "github.com/milvus-io/milvus/client/v2/entity"

    schema := entity.NewSchema().
        WithField(entity.NewField().WithName("id").WithDataType(entity.FieldTypeInt64).WithIsPrimaryKey(true)).
        WithField(entity.NewField().WithName("vector").WithDataType(entity.FieldTypeFloatVector).WithDim(768)).
        WithField(entity.NewField().WithName("text").WithDataType(entity.FieldTypeVarChar).WithMaxLength(2048))

    err := cli.CreateCollection(ctx, milvusclient.NewCreateCollectionOption("articles", schema))
    ```

> [!TIP]
> Set `auto_id=True` to have Milvus generate primary keys for you on insert. Set
> `enable_dynamic_field=True` to allow each entity to carry extra, un-declared JSON fields —
> useful when your metadata schema is not fixed.

### 4.4 Dynamic fields

When `enable_dynamic_field=True`, any keys you insert that are not declared in the schema are
stored in a hidden JSON field. You can filter and even index them by JSON path:

```python
index_params.add_index(
    field_name="overview",          # a key inside the dynamic field
    index_type="AUTOINDEX",         # AUTOINDEX or INVERTED for JSON-path indexing
    index_name="overview_index",
    params={
        "json_cast_type": "varchar",
        "json_path": "overview",
    },
)
```

### 4.5 Schema limits

These defaults come from the server configuration and bound what a schema may declare:

| Limit | Default | Config key |
|---|---|---|
| Max name/alias/field-name length | 255 | `proxy.maxNameLength` |
| Max fields per collection | 64 | `proxy.maxFieldNum` |
| Max vector fields per collection | 10 | `proxy.maxVectorFieldNum` |
| Max shards per collection | 16 | `proxy.maxShardNum` |
| Max vector dimension | 32768 | `proxy.maxDimension` |
| Max partitions per collection | 1024 | `rootCoord.maxPartitionNum` |
| Max collections | 65536 | `quotaAndLimits.limits.maxCollectionNum` |
| Max databases | 64 | `rootCoord.maxDatabaseNum` |

> [!WARNING]
> Setting `maxFieldNum` ≥ 64 is strongly discouraged by the project. Wide schemas degrade
> write and query performance. Prefer the dynamic field for sparse, optional metadata.

---

## 5. Ingesting Data

### 5.1 Insert

`Insert` adds new entities. Each row is a mapping of field name to value:

=== "Python"

    ```python
    data = [
        {"id": 1, "vector": [0.1, 0.2, ...], "text": "hello", "subject": "greeting"},
        {"id": 2, "vector": [0.3, 0.1, ...], "text": "world", "subject": "greeting"},
    ]
    res = client.insert(collection_name="articles", data=data)
    print(res["insert_count"])
    ```

=== "Go"

    ```go
    _, err := cli.Insert(ctx, milvusclient.NewColumnBasedInsertOption("articles").
        WithInt64Column("id", []int64{1, 2}).
        WithFloatVectorColumn("vector", 768, [][]float32{vec1, vec2}).
        WithVarcharColumn("text", []string{"hello", "world"}))
    ```

### 5.2 Upsert

`Upsert` inserts new entities or replaces existing ones with the same primary key:

```python
client.upsert(collection_name="articles", data=data)
```

> [!NOTE]
> `Upsert` requires a non-auto primary key (you must supply the key). It is implemented as a
> delete-then-insert, so the replaced entity's old version is removed.

### 5.3 Delete

Delete by primary key list or by a boolean filter expression:

```python
# By primary keys
client.delete(collection_name="articles", ids=[1, 2, 3])

# By filter expression
client.delete(collection_name="articles", filter="subject == 'greeting'")
```

### 5.4 Flush

Insertions are buffered and periodically sealed into persistent segments automatically. Call
`Flush` to force the current buffer to be sealed and persisted immediately:

```python
client.flush(collection_name="articles")
```

> [!CAUTION]
> Do not call `flush` after every small insert. Frequent manual flushes create many tiny
> segments, which hurts search performance until compaction merges them. Let Milvus seal
> segments on its own schedule; flush only when you need a hard durability boundary (for
> example, before a backup). Flush is rate-limited (`quotaAndLimits.flushRate`).

### 5.5 Bulk import

For large offline loads, use the import API rather than streaming inserts. Import ingests
files (Parquet, JSON, or NumPy) already staged in object storage and builds segments in bulk —
far more efficient than row-by-row `Insert` for millions of rows. Import behavior is governed
by `dataCoord.import.*` and `dataNode.import.*` (see the Admin Guide).

> [!TIP]
> Rule of thumb: use `Insert`/`Upsert` for live, incremental writes; use **import** for the
> initial backfill of an existing dataset.

---

## 6. Indexing

A vector index trades a small amount of recall for a large speedup. You must build an index
(or use `AUTOINDEX`) before a collection can be loaded and searched.

### 6.1 Build a vector index

=== "Python"

    ```python
    index_params = client.prepare_index_params()
    index_params.add_index(
        field_name="vector",
        index_type="HNSW",
        metric_type="COSINE",
        params={"M": 16, "efConstruction": 200},
    )
    client.create_index(collection_name="articles", index_params=index_params)
    ```

=== "Go"

    ```go
    idx := index.NewHNSWIndex(entity.COSINE, 16, 200)
    _, err := cli.CreateIndex(ctx, milvusclient.NewCreateIndexOption("articles", "vector", idx))
    ```

### 6.2 Vector index types

The in-repo Go SDK (`client/index/common.go`) defines these index types:

| Index type | Family | Notes |
|---|---|---|
| `FLAT` | Brute force | Exact search, 100% recall, no build needed |
| `IVF_FLAT` | Inverted file | Balanced speed/recall |
| `IVF_SQ8` | Inverted file + scalar quantization | Lower memory |
| `IVF_PQ` | Inverted file + product quantization | Much lower memory, some recall loss |
| `IVF_RABITQ` | Inverted file + RaBitQ | Compact quantized variant |
| `HNSW` | Graph | High recall, high QPS, higher memory |
| `IVF_HNSW` | Hybrid | IVF coarse + HNSW refine |
| `SCANN` | Quantized | Fast, good recall density |
| `DISKANN` | Disk-resident graph | Billion-scale on SSD, lower memory footprint |
| `AUTOINDEX` | Auto | Milvus picks parameters for you |
| `MINHASH_LSH` | LSH | MinHash similarity |
| `BIN_FLAT`, `BIN_IVF_FLAT` | Binary | For `BinaryVector` fields |
| `SPARSE_INVERTED_INDEX`, `SPARSE_WAND` | Sparse | For `SparseFloatVector` (e.g. BM25/SPLADE) |
| `GPU_IVF_FLAT`, `GPU_IVF_PQ`, `GPU_CAGRA`, `GPU_BRUTE_FORCE` | GPU | Require a GPU build |

> [!TIP]
> If you are unsure, use `AUTOINDEX`. For most CPU workloads `HNSW` (best QPS/recall) or
> `IVF_FLAT` (simple, balanced) are safe defaults. For billion-scale data that does not fit
> in RAM, use `DISKANN`. Use `GPU_CAGRA` only on a GPU-enabled Milvus build.

### 6.3 Metric types

The metric must match how your embedding model was trained. Defined in
`client/entity/common.go`:

| Metric | Use for |
|---|---|
| `L2` | Euclidean distance — dense float vectors |
| `IP` | Inner product — dense float vectors |
| `COSINE` | Cosine similarity — dense float vectors (normalized IP) |
| `HAMMING`, `JACCARD`, `TANIMOTO` | Binary vectors |
| `SUBSTRUCTURE`, `SUPERSTRUCTURE` | Chemical substructure search (binary) |
| `BM25` | Full-text search over sparse vectors |
| `MHJACCARD` | MinHash Jaccard |
| `MAX_SIM`, `MAX_SIM_COSINE`, `MAX_SIM_L2`, `MAX_SIM_IP`, `MAX_SIM_HAMMING`, `MAX_SIM_JACCARD` | Multi-vector (late-interaction, e.g. ColBERT/ColPali) |

### 6.4 Scalar indexes

Index scalar fields to speed up filtered search. Types: `STL_SORT` (numeric), `Trie` and
`INVERTED` (string), `BITMAP` (low-cardinality), and `RTREE` (geometry).

```python
index_params.add_index(field_name="subject", index_type="INVERTED")
```

### 6.5 Manage indexes

```python
client.list_indexes(collection_name="articles")
client.describe_index(collection_name="articles", index_name="vector")
client.drop_index(collection_name="articles", index_name="vector")
```

> [!NOTE]
> To change an index, drop it and create a new one. The collection must be **released**
> before you can drop an index that backs a loaded vector field.

---

## 7. Connecting and Loading

### 7.1 Connect with authentication

The Go SDK `ClientConfig` (from `client/milvusclient/client_config.go`) accepts:

| Field | Meaning |
|---|---|
| `Address` | Server address, e.g. `localhost:19530` |
| `Username`, `Password` | Username/password authentication |
| `APIKey` | API key (overrides username/password) |
| `DBName` | Database to use for this connection |
| `EnableTLSAuth` | Enable TLS transport security |
| `DialOptions` | Extra gRPC dial options |
| `RetryRateLimit` | Client-side retry behavior on rate-limit responses |

```go
cli, err := milvusclient.New(ctx, &milvusclient.ClientConfig{
    Address:       "milvus.internal:19530",
    Username:      "root",
    Password:      "Milvus",
    DBName:        "default",
    EnableTLSAuth: true,
})
```

In Python, pass `uri` and `token` (`"<user>:<password>"` or an API key):

```python
client = MilvusClient(uri="https://milvus.internal:19530", token="root:Milvus")
```

> [!NOTE]
> Authentication is only enforced when the server has `common.security.authorizationEnabled`
> set to `true`. A default install accepts any credentials. Turning auth on is an
> administrator task — see the Admin Guide security chapter.

### 7.2 Load and release

Load a collection (or specific partitions) into query-node memory before searching:

```python
client.load_collection(collection_name="articles")
state = client.get_load_state(collection_name="articles")   # check progress
# ... run searches ...
client.release_collection(collection_name="articles")        # free memory
```

```python
client.load_partitions(collection_name="articles", partition_names=["2024"])
client.release_partitions(collection_name="articles", partition_names=["2024"])
client.refresh_load(collection_name="articles")   # reload after new data
```

> [!IMPORTANT]
> Loading consumes RAM proportional to the collection size and index. If a query node hits
> its memory water mark, loads are rejected and writes may be throttled. Release collections
> you are not actively querying, or scale out query nodes (Admin Guide).

---

## 8. Searching

### 8.1 Vector similarity search

`Search` finds the top-K nearest vectors to one or more query vectors:

=== "Python"

    ```python
    res = client.search(
        collection_name="articles",
        data=[query_vector],                # one or more query vectors
        limit=10,                           # top-K
        search_params={"metric_type": "COSINE", "params": {"ef": 64}},
        output_fields=["text", "subject"],  # scalar fields to return
        filter="subject == 'greeting'",     # optional metadata filter
    )
    for hit in res[0]:
        print(hit["id"], hit["distance"], hit["entity"]["text"])
    ```

=== "Go"

    ```go
    resultSets, err := cli.Search(ctx, milvusclient.NewSearchOption("articles", 10, []entity.Vector{
        entity.FloatVector(queryVector),
    }).WithOutputFields("text", "subject").WithFilter("subject == 'greeting'"))
    ```

### 8.2 Consistency levels

Set per collection or per search. Higher consistency costs latency.

| Level | Guarantee |
|---|---|
| `Strong` | Sees every write committed before the search started |
| `Bounded` | **Default.** Sees writes up to a bounded staleness window |
| `Session` | Sees this client's own writes immediately |
| `Eventually` | Lowest latency; may miss the most recent writes |

```python
res = client.search(collection_name="articles", data=[query_vector],
                    limit=3, consistency_level="Strong")
```

> [!TIP]
> Use `Bounded` for most search traffic, `Session` for read-after-write within a user
> session, and `Strong` only when you truly need the latest data (it forces a time-tick sync
> and adds latency).

### 8.3 Filtered (hybrid scalar + vector) search

The `filter` expression is a boolean predicate over scalar fields, evaluated before/with the
vector search. Operators include `==`, `!=`, `>`, `<`, `>=`, `<=`, `in`, `like`, `and`, `or`,
`not`, and JSON/array accessors:

```python
filter='(price < 100) and (category in ["books", "music"]) and (title like "intro%")'
```

### 8.4 Query (scalar retrieval) and Get

`Query` returns entities matching a filter with no vector involved; `Get` fetches by primary
key:

```python
client.query(collection_name="articles", filter="subject == 'greeting'",
            output_fields=["id", "text"], limit=100)

client.get(collection_name="articles", ids=[1, 2, 3], output_fields=["text"])
```

### 8.5 Range search

Return all vectors within a distance band rather than a fixed top-K, via `radius` and
`range_filter` in `search_params`:

```python
search_params = {"metric_type": "COSINE", "params": {"radius": 0.4, "range_filter": 0.8}}
```

### 8.6 Iterators

For paging through large result sets without holding everything in memory, use
`SearchIterator` and `QueryIterator` (Go SDK `client/milvusclient/iterator.go`; Python
`search_iterator`/`query_iterator`). Iterators fetch results in batches.

### 8.7 Grouping search

Return the best hit per group value (deduplicate by a scalar field) using `group_by_field`.
The maximum group count is bounded by `common.groupBy.maxGroups` (default 100000).

---

## 9. Hybrid and Full-Text Search

### 9.1 Multi-vector hybrid search

When a collection has several vector fields (for example, a dense semantic vector and a sparse
keyword vector), `HybridSearch` runs one search per field and fuses the rankings with a
reranker:

```python
from pymilvus import AnnSearchRequest, RRFRanker

dense_req = AnnSearchRequest(data=[dense_vec], anns_field="dense",
                            param={"metric_type": "COSINE"}, limit=20)
sparse_req = AnnSearchRequest(data=[sparse_vec], anns_field="sparse",
                            param={"metric_type": "BM25"}, limit=20)

res = client.hybrid_search(
    collection_name="articles",
    reqs=[dense_req, sparse_req],
    ranker=RRFRanker(),     # or WeightedRanker(...)
    limit=10,
    output_fields=["text"],
)
```

> [!NOTE]
> Hybrid search combines, for example, semantic (dense) and lexical (sparse/BM25) relevance —
> the recommended pattern for RAG retrieval quality. The Go SDK exposes the equivalent
> `HybridSearch` method.

### 9.2 Full-text search with BM25

Milvus supports native full-text search: store text, let Milvus generate sparse BM25 vectors,
and search with the `BM25` metric over a `SparseFloatVector` field indexed with
`SPARSE_INVERTED_INDEX` or `SPARSE_WAND`. Learned sparse embeddings such as SPLADE and BGE-M3
are also supported. Use `RunAnalyzer` to preview how text is tokenized:

```python
client.run_analyzer(text="The quick brown fox", analyzer_params={"type": "english"})
```

### 9.3 Reranking with model providers

Milvus can call external reranker and embedding model providers (configured server-side under
`function.rerank` and `function.textEmbedding`) — including OpenAI, Cohere, VoyageAI, Gemini,
VertexAI, Bedrock, SiliconFlow, TEI, and vLLM. This lets you define embedding/rerank
**functions** on a collection so Milvus generates vectors at insert/search time. Provider
enablement and credentials are administrator settings (Admin Guide).

---

## 10. Organizing Data: Partitions, Databases, Aliases

### 10.1 Partitions

Partitions subdivide a collection so searches can target a slice:

```python
client.create_partition(collection_name="articles", partition_name="2024")
client.list_partitions(collection_name="articles")
client.has_partition(collection_name="articles", partition_name="2024")
client.get_partition_stats(collection_name="articles", partition_name="2024")
client.drop_partition(collection_name="articles", partition_name="2024")
```

Then restrict a search to partitions with `partition_names=["2024"]`.

### 10.2 Partition key

Instead of managing partitions manually, mark a scalar field as the **partition key**. Milvus
hashes its value to auto-route each entity to a partition, giving you tenant isolation and
faster filtered search without manual bookkeeping:

```python
schema.add_field("tenant_id", DataType.VARCHAR, max_length=128, is_partition_key=True)
```

> [!TIP]
> Partition-key isolation is the recommended multi-tenancy strategy when you have many
> tenants in one collection. For a handful of large tenants, use separate collections or
> databases instead.

### 10.3 Databases

Databases are namespaces for collections:

```python
client.create_database(db_name="analytics")
client.use_database(db_name="analytics")
client.list_databases()
client.describe_database(db_name="analytics")
client.drop_database(db_name="analytics")
```

### 10.4 Aliases

An alias is a stable name that points at a collection — handy for zero-downtime reindexing
(build a new collection, then repoint the alias):

```python
client.create_alias(collection_name="articles_v2", alias="articles")
client.alter_alias(collection_name="articles_v3", alias="articles")
client.list_aliases(collection_name="articles_v3")
client.drop_alias(alias="articles")
```

---

## 11. Maintenance Operations You Can Trigger

These are user-callable operations (the heavier background work happens automatically):

| Operation | Method | Effect |
|---|---|---|
| Flush | `flush` | Seal and persist the current insert buffer |
| Compact | `compact` | Merge small segments and purge deleted rows |
| Compaction state | `get_compaction_state` | Check a manual compaction's progress |
| Collection stats | `get_collection_stats` | Row count and storage stats |
| Load state | `get_load_state` | Whether/how much of a collection is loaded |
| Server version | `get_server_version` | The connected server's build version |

```python
client.compact(collection_name="articles")
print(client.get_collection_stats(collection_name="articles"))
```

> [!NOTE]
> Manual `compact` is throttled by `quotaAndLimits.compactionRate`. Automatic compaction
> (`dataCoord.compaction.enableAutoCompaction`) handles routine merging; trigger manual
> compaction only after large deletes.

---

## 12. Snapshots and Replication (Overview)

The in-repo SDK exposes operations that admins typically drive, but which you may encounter:

- **Snapshots** — `create_snapshot`, `list_snapshots`, `restore_snapshot`, and
  `get_restore_snapshot_state` capture and restore a point-in-time view of collection data.
- **Replication / CDC** — `get_replicate_info` and `create_replicate_stream` support
  cross-cluster data replication (Change Data Capture). The `cdc` server role and Milvus CDC
  tool drive synchronization between clusters.

Configuration, topology, and operational guidance for these features are in the Admin Guide.

---

## 13. Access Control (RBAC) for Users

If your administrator has enabled authorization, you authenticate as a user that has been
granted roles. As a user you may be permitted to manage your own credentials and, with
sufficient privilege, users and roles:

```python
client.create_user(user_name="alice", password="S3cret!")
client.update_password(user_name="alice", old_password="S3cret!", new_password="N3wS3cret!")
client.list_users()
client.create_role(role_name="reader")
client.grant_role(user_name="alice", role_name="reader")
client.grant_privilege_v2(role_name="reader", privilege="Search", collection_name="articles")
```

> [!IMPORTANT]
> The full privilege model, privilege groups, and the built-in roles are an administrator
> concern. See the Admin Guide RBAC chapter. By default the `root` user exists with password
> `Milvus` and should be secured immediately.

---

## 14. The Web UI

Milvus ships a built-in Web UI served on the metrics port (`9091`) when
`proxy.http.enableWebUI` is enabled (the default). Browse to `http://<host>:9091/webui` to
inspect collections, segments, query-node distribution, slow queries, and component health
without writing code.

> [!TIP]
> For a richer graphical admin experience, the community tool **Attu** provides a full GUI
> for managing collections, running searches, and viewing data. It is a separate project, not
> part of this repository.

---

## 15. Troubleshooting

Errors below are taken from the Milvus source error catalog. Format: the message, its cause,
and the fix.

### Error: `collection not loaded`

**Cause:** You searched or queried a collection that has not been loaded into memory.
**Solution:** Call `load_collection` (or `load_partitions`) and wait for `get_load_state` to
report loaded, then retry.
**Prevention:** Always load after creating an index and before searching.

### Error: `shard num (%d) exceeds max configuration (%d)`

**Cause:** You requested more shards than `proxy.maxShardNum` (default 16) allows at collection
creation.
**Solution:** Lower the shard count, or raise `proxy.maxShardNum` server-side.
**Prevention:** Most collections need only 1–2 shards; add shards only for very high write
throughput.

### Error: `partition number (%d) exceeds max configuration (%d), collection: %s`

**Cause:** The collection (often via a partition key) exceeded `rootCoord.maxPartitionNum`
(default 1024).
**Solution:** Reduce the number of partition-key values, or raise `maxPartitionNum`.
**Prevention:** Choose a partition key with bounded cardinality.

### Error: `the specified partitions should be greater than 0 if partition key is used`

**Cause:** A partition-key collection was created with a non-positive partition number.
**Solution:** Specify a positive `num_partitions` when creating the collection.

### Error: `collection name [%s] conflicts with an existing alias, please choose a unique name`

**Cause:** You tried to create a collection whose name is already used as an alias.
**Solution:** Pick a different collection name, or drop the conflicting alias first.

### Error: `create duplicate collection with different parameters, collection: %s`

**Cause:** You re-created an existing collection with a different schema.
**Solution:** Drop the existing collection first, or reuse the identical schema.
**Prevention:** Use `has_collection` before creating.

### Error: `PK Field not found`

**Cause:** Your inserted data or query references a primary-key column that the schema does not
define, or you omitted the primary key on a non-`auto_id` collection.
**Solution:** Supply the primary-key field on insert, or set `auto_id=True` at creation.

### Error: `dim not found in params`

**Cause:** A vector field was declared without a `dim` (dimension) parameter.
**Solution:** Add `dim=<N>` to every dense vector field in the schema.

### Error: `ttl needs to be a positive integer`

**Cause:** A collection time-to-live property was set to a non-positive value.
**Solution:** Provide a positive integer (seconds) for the TTL property, or omit it.

### Error: `build index on unsupported data type: %s`

**Cause:** You requested an index type that does not match the field's data type (for example,
a dense index on a binary or sparse vector).
**Solution:** Match the index family to the field type — `BIN_*` for binary, `SPARSE_*` for
sparse, dense indexes for float vectors.

### Error: `request rejected — quota exceeded` / DML denied

**Cause:** A quota or rate limit fired — memory water mark, disk quota, or an enabled rate
limit under `quotaAndLimits.*`.
**Solution:** Free memory (release collections, scale query nodes), reduce request rate, or
raise the relevant quota. Check the server logs for the specific protection that triggered.
**Prevention:** Monitor memory and disk usage; size the cluster for peak load (Admin Guide).

### Connection refused / cannot reach `19530`

**Cause:** The server is not up, ports are not published, or a firewall blocks `19530`.
**Solution:** Verify `curl http://localhost:9091/healthz` returns `OK`, confirm the Compose
`ports` mapping, and check `docker compose logs standalone`.

> [!TIP]
> The Web UI (`:9091/webui`) surfaces slow queries, stuck loads, and unhealthy components and
> is usually the fastest way to diagnose a misbehaving instance.

---

## 16. Frequently Asked Questions

**Q: What is the difference between Milvus Lite, Standalone, and a cluster?**
Milvus Lite is an embedded Python library for prototyping. Standalone is a single-container
server for one machine. A cluster runs coordinators and worker nodes separately on Kubernetes
for billion-scale, highly available workloads. The client code is identical across all three —
only the connection URI changes.

**Q: Do I have to create an index before searching?**
Yes. A collection must have an index on each vector field (or use `AUTOINDEX`) and must be
loaded before search. The lifecycle is create → insert → index → load → search.

**Q: Which index and metric should I use?**
Start with `AUTOINDEX`. For explicit control, `HNSW` gives the best QPS/recall on CPU,
`IVF_FLAT` is a simple balanced choice, and `DISKANN` handles data that does not fit in RAM.
Match the metric to your embedding model: `COSINE` or `IP` for normalized text embeddings,
`L2` for many image embeddings, `BM25` for full-text.

**Q: Can I store more than one vector per entity?**
Yes — up to `proxy.maxVectorFieldNum` (default 10) vector fields per collection. Multi-vector
collections power hybrid search across modalities.

**Q: How fresh are my search results?**
That depends on the consistency level: `Strong` (latest), `Bounded` (default, slight
staleness), `Session` (your own writes), or `Eventually` (fastest, may lag).

**Q: How do I do keyword (full-text) search, not just semantic search?**
Use a `SparseFloatVector` field with the `BM25` metric and a sparse index, or combine dense +
sparse with `HybridSearch`. Milvus can generate BM25 sparse vectors for you from text fields.

**Q: How do I update an entity?**
Use `Upsert` with the same primary key, or `Delete` then `Insert`. There is no in-place field
update for vectors.

**Q: Why did my insert succeed but my search return nothing?**
Either the collection is not loaded, the data was inserted into a partition you are not
searching, or your consistency level is `Eventually` and the write has not yet propagated.
Load the collection, check partitions, and try `consistency_level="Strong"`.

**Q: What embedding models work with Milvus?**
Any model that produces fixed-dimension vectors. Milvus integrates with LangChain, LlamaIndex,
OpenAI, HuggingFace, and others, and `pymilvus[model]` provides convenience wrappers. The
collection's `dimension` must equal the model's output dimension.

**Q: Is there a GUI?**
Yes — the built-in Web UI on port `9091` for diagnostics, and the community **Attu** tool for
full graphical administration.

**Q: How do I back up my data?**
Use snapshots (`create_snapshot`/`restore_snapshot`) and RBAC backup, or the Milvus Backup
tool. See the Admin Guide.

**Q: What does `milvus run standalone` actually start?**
In standalone mode, one process runs all roles together: the coordinator (MixCoord), Proxy,
QueryNode, DataNode, and StreamingNode. This is detailed in the Admin Guide architecture
chapter.

---

## 17. Where to Go Next

- **Admin Guide** — architecture deep dive, the complete `milvus.yaml` configuration
  reference, cluster deployment and sizing, security (TLS, RBAC, quotas), monitoring, backup,
  and upgrades.
- **Official docs** — [milvus.io/docs](https://milvus.io/docs) for tutorials (RAG, semantic
  search, recommendation), SDK references, and integration guides.
- **Community** — Discord and GitHub Discussions for help; GitHub Issues for bugs.

---

_Generated June 2026 from milvus-io/milvus at d9bbbc1. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
