Semantic search and full-text search grew up in different engines. This meant compromising somewhere, until now. Milvus is one engine that is genuinely good at both:
two engines
sync writes ↔ reconcile scores
Two clusters, two scoring models, two write paths and complex fusion logic.
just use elasticsearch
dense_vector kNNone engine · vectors bolted on
RAM-bound HNSW, re-shard to grow. Orfium capped at ~500K references; Rexera cut cost 50% on the way out.
milvus 3.0
one call · nothing to reconcile
One schema, one query, one cluster. Hybrid ranking runs inside the kernel, not in your app tier.
BM25 + Vector search is greater than the sum of its parts.
RAG / AI agents
create_index() · v2.6.4 · config flagsLegal & compliance
§230(c)(1) - document-specificObservability
connection reset by peer, verbatimE-commerce
SKU34632A · brand namesgithub.com/milvus-io/milvus
deployments in the wild
running Milvus in production

Teams that collapsed a two-engine stack onto Milvus:
OpenSearch→Zilliz Cloud
123RFimage search
200M+ stock-asset vectors: infra cost cut >50%, latency halved to sub-50ms
OpenSearch→Zilliz Cloud
Plaudagent memory
10B+ agent-memory chunks per region at <200ms average recall, across 2M+ devices
Elasticsearch→Zilliz Cloud
RexeraRAG + agents
Hybrid search: retrieval accuracy +40%, cost −50% vs Elasticsearch
Elasticsearch→Zilliz Cloud
Orfiumaudio matching
~250M audio vectors; the old ES setup maxed out at ~500K references
Elasticsearch→Milvus
OpusSearchhybrid search
One deployment for semantic + BM25 exact match across 170M+ videos
Elasticsearch→Zilliz Cloud
OpenArtmultimodal search
456M vectors moved with no re-embedding: P99 25s → 300ms, compute cost −85%
Full-text
Search
Efficiency
Schema
Elasticsearch's structural advantage was letting documents be messy. Milvus 3.0 closes that gap too:
missing data
Nullable fields
Scalars and vectors can be null: no sentinel values skewing filters, no dummy embeddings poisoning distance math, no splitting collections when some docs lack an image
vs ES: documents omit fields freely, and that blocked migrations of sparse real-world data. It now moves over as-is
rich metadata
JSON shredding + indexing
Nested JSON shreds into typed columns with path indexes: filters on meta["brand"] run at columnar speed, not per-row blob parsing
vs ES: dynamic mapping indexes every key, but risks mapping explosion, reindex req'd to change a type. Milvus keeps the schema stable
evolving payloads
Dynamic schema
Insert fields you never declared: they land in a hidden JSON field, still filterable and indexable. Payloads evolve with zero migrations, zero downtime
vs ES: schemaless writes are supported in ES but mappings are required to make fields searchable. Milvus improves on this
Cloud-native high performance architecture for ANN, benefits BM25:
Faster
Kernel-side execution
Search, filter, group and aggregate run inside the vector kernel: no shipping candidates to the app tier for post-processing
Cheaper
10× lower memory
RaBitQ 1-bit primary index + SQ8 refinement, at equal recall. Smaller BM25 indices. No Java overhead. No replica requirement. Tiered-storage optional.
Easier
One engine
One schema, hybrid search in a single call: no sync, no score reconciliation. All core features in F/OSS license.
standard + english stem/stop)
Both engines from the last slide, queries & results evaluated side-by-side:
group_by completeness against collapseRun the live demo yourself: github.com/simonhearne/milvus_es_lab
If you rely on these in Elasticsearch, they're on the way:
fuzziness→coming
Typo-tolerant search
Fast, fuzzy BM25 matching with prefix pruning, so typos still find the right results
phrase_prefix→coming
Search-as-you-type
Phrase-prefix matching for typeahead and autocomplete
rescore→coming
Multi-stage reranking
Shape relevance in stages, beyond function_score
bloom→coming
Filters at scale
Bloom-filter support and per-element array matching replace giant OR-chains
Safe harbourThese are forward-looking features, not currently available.
github.com/simonhearne/milvus_es_lab
docker compose up -d
python data/fetch.py # one Parquet, ~370 MB
docker compose exec demo python data/load_milvus.py
docker compose exec demo python data/load_es.py
docker compose exec demo python data/load_multilingual.py
Requires Docker with ≧16 GB RAM
Everything I showed you is reproducible on your laptop.
Join me in two weeks to walk through the migration process to Milvus 3.0.
zilliz.com/event/migrating-from-elasticsearch-opensearch-to-milvus

You could be running a proof of concept in under an hour!