Comparison

TopK vs. Elasticsearch

Elasticsearch added vectors on top of Lucene. TopK was built for them, and speaks the same API.

Compared throughout against Elasticsearch Serverless, the closest managed equivalent.

Same client, different engine

TopK is a search engine for accuracy-critical AI applications: hybrid search, multi-vector retrieval, custom ranking and managed inference in one API. Elasticsearch is a search and analytics engine on Apache Lucene, covering full-text and vector search alongside log and security analytics. Both separate storage from compute, so the differences that decide a retrieval workload are the ones below.

 TopKElasticsearch Serverless
EngineVector-nativeLucene, with vector search added on
First-stage rankingToken-level MaxSim, whole corpusDense kNN; MaxSim reranks the shortlist
Vector index tuningAutomatically selects the best parametersHas to be tuned manually
Ways inElasticsearch API, Postgres wire, native SDKsElasticsearch API
DeploymentManaged, bring your own cloudManaged only

Multi-vector retrieval runs end to end

Multi-vector retrieval, also called late interaction, retrieves better than dense or hybrid approaches, and it has always been too expensive to run across a whole corpus. In most systems it reranks a candidate set that something cheaper picked, so a document the first stage misses cannot be recovered by the second. Elastic says so itself: its rank_vectors field is there for “second order ranking documents with max-sim similarity.”

Reranking can only reorder what the first stage already found.

Rerank over dense

knn retrieves candidates

one vector per document

rank_vectors rescore

MaxSim over the shortlist

A miss in stage one is final

MaxSim as first stage

SMVE retrieves

token level, whole corpus

Full MaxSim refines

exact ranking on candidates

No candidate set to miss

TopK encodes each document’s token embeddings into a sparse vector whose dot product approximates MaxSim, so token-level scoring runs as first-stage retrieval and exact MaxSim refines only the shortlist. The encoder is Iso-ModernColBERT; the SMVE research has the method and the latency numbers. If your first stage already scores at token level, you may not need a reranker at all.

Accuracy and speed, measured

Both systems ran the same corpus and the same query set on an open source harness, so you can re-run every number here against your own cluster.

Recall, filtered search

Share of the true top-k returned. Higher is better.

TopKElasticsearch
0.900.951.00
0.976
0.938
0.969
0.937
0.961
0.953
100k1M10M

Dense knn, identical corpus and query set on both sides. recall@10 against exact-search ground truth.

p99 latency under concurrency

1M documents, knn. Lower is better.

TopKElasticsearch
050100124816328 ms at 1 clients9 ms at 2 clients12 ms at 4 clients18 ms at 8 clients36 ms at 16 clients122 ms at 32 clients8 ms at 1 clients9 ms at 2 clients11 ms at 4 clients14 ms at 8 clients18 ms at 16 clients29 ms at 32 clients122 ms29 ms

concurrent clients

Dense knn, interleaved runs against Elasticsearch Serverless 9.6.0 at its default Search Power.

52.88%
nDCG@10 on BEIR, end to end with embedding included
TopK semantic index

Averaged over all 15 BEIR datasets, measured on production clusters with ingestion, embedding and indexing included.

The latency and throughput figures come from topk-bench.

Three interfaces, one collection

The Elasticsearch API is one of three ways into the same collection, not a separate product. Your application keeps its Elasticsearch client. Your analysts connect over the Postgres wire protocol with no Elastic driver. Your pipelines use the native SDKs and reach scoring expressions the DSL does not expose. One copy of the data, multiple use cases.

The same semantic query, three ways in.

Elasticsearch client

{
"query": {
"semantic": {
"field": "content",
"query": "political control"
}
},
"size": 10
}

Postgres

SELECT title,
semantic_similarity(
content, 'political control'
) AS score
FROM books
ORDER BY score DESC
LIMIT 10;

Python / Javascript / Rust

client.collection("books").query(
select(
"title",
score=fn.semantic_similarity(
"content", "political control"
),
)
.sort(field("score"), asc=False)
.limit(10)
)

What the Elasticsearch interface covers

CapabilityTopKES ServerlessNotes
Beyond the Elasticsearch API
Multi-vector retrievalMaxSim runs first-stage over the whole corpus; rank_vectors only reranks what dense search already found.
Embedding without provisioned computePriced per token with nothing allocated; Serverless bills ML VCU-hours for as long as a model is up.
Schemaless documentsNew fields are queryable with no mapping change; Elasticsearch infers a mapping and then freezes it.
Optimized vector indexDistance metric is the only choice; graph parameters and element type are fixed at mapping time.
Postgres wire protocolpsql, psycopg and BI tools against the same collection; Elasticsearch has no wire-protocol equivalent.
Parity, request for request
knn vector searchFloat, byte and bit vectors.
semantic_text and semanticTopK's semantic_index is powered by end-to-end multi-vector retrieval.
Hybrid rankingSeveral retrievers fused in one request, by weighted sum or rank.rrf.
Indices and documentsIndex, update, delete, _mget, _msearch, _count, refresh.
Subset, or not yet
Query DSLTwelve clauses, including match, multi_match, term, range, bool and semantic.
Field typesThe common types plus dense_vector, rank_vectors and semantic_text. No geo.
Aggregationsterms, sum, avg, min, max, value_count.
PaginationUp to 10,000 results, the same default window Elasticsearch ships. No search_after or point-in-time for deeper paging.
AliasesA reindex is a client-side cutover; Elasticsearch swaps an alias atomically.
Mapping updatesA schema change means a new collection; Elasticsearch takes PUT _mapping in place.
HighlightingTopK returns matching documents but no keyword-in-context snippets.
supported partial not available

Choosing between them

Elasticsearch has fifteen years behind it and a Lucene core older still. Some work still belongs there.

Choose Elasticsearch when

  • You need observability and security analytics beside search.
  • You already run Elasticsearch and the cluster has headroom.
  • Open source is a requirement, or you need to run it yourself and control the upgrade cadence.

Choose TopK when

  • Your retrieval feeds an agent, and what the first stage misses is gone for good.
  • Filters are in every query, and you cannot trade recall to get them.
  • Every agent task fans out into dozens of retrievals.
  • Your data cannot leave your own cloud.

Switching is one line

You change the endpoint URL. Official Elasticsearch clients connect unchanged, your mappings load as they are, and queries inside the supported surface run as written — so you can point a second client at TopK and compare on your own judgments before deciding anything.

elasticsearch-py
from elasticsearch import Elasticsearch
es = Elasticsearch(
"https://aws-us-east-1-elastica.es.topk.io",
api_key=API_KEY,
)
es.search(
index="books",
query={"match": {"title": "standing desk"}},
)

The official Elasticsearch clients work as they are, 9.x included. Point the client back at Elasticsearch and you are exactly where you started.

For the corpus you already have indexed, topk import reads an index straight from a live cluster and writes a TopK collection, no dump in between.

$ topk import https://my-cluster.es.eu-central-1.aws.elastic.cloud books

Keep both systems live while you compare on your own traffic. If you would rather not do it alone, talk to us — we are happy to help with the migration, and we want to hear where it gets hard.

Tell us what you are running

We are talking to teams and consultancies running Elasticsearch in production about what they index, what it costs, and where it hurts. If you would rather just try it, every account starts with $10 in free credits.