The best vector database is the one that answers your whole query, and finding the nearest vectors is only the first part of it. A retrieval step for RAG or semantic search usually also has to filter on fields such as the tenant or the product, rank exact keywords like an error code or a function name, and sometimes count or group what it found. This post compares ten vector databases on those needs: Pinecone, Milvus, Qdrant, Weaviate, Chroma, pgvector, MongoDB Atlas Vector Search, Elasticsearch, OpenSearch and SereneDB.
We build SereneDB. Every claim about the other nine links to their own documentation, with the version it describes, and every claim about SereneDB links to ours and to a query you can run at the end of the post.
Available solutions reference
| Database | What it is | Filter inside the vector search | BM25 + vectors in one query | SQL with aggregates | Indexes your files and tables in place | License |
|---|---|---|---|---|---|---|
| Pinecone | Vector database behind an HTTP API | Yes | Partly: RRF in SQL through pg_pinecone | Partly: SQL through pg_pinecone | No | Proprietary |
| Milvus | Open-source vector database | Yes | Yes | Partly: aggregation API, no SQL | Partly: Parquet, Lance, Vortex and Iceberg | Apache 2.0 |
| Qdrant | Open-source vector search engine | Yes | Yes | No | No | Apache 2.0 |
| Weaviate | Vector database with vectorizer modules | Yes | Yes | Partly: aggregation API, no SQL | No | BSD-3-Clause core |
| Chroma | Embeddable retrieval database | Yes | Partly: Chroma Cloud only | No | No | Apache 2.0 |
| pgvector | Vector extension for PostgreSQL | After the index scan | Partly: ts_rank, not BM25 | Yes | No | PostgreSQL |
| MongoDB Vector Search | Vector stage in MongoDB pipelines | Yes | Yes | Partly: pipeline, no SQL vectors | No | SSPL v1 |
| Elasticsearch | Lucene search engine with vector fields | Yes | Yes | Partly: aggregations, no SQL vectors | No | AGPLv3, SSPL or ELv2 core; x-pack ELv2 only |
| OpenSearch | Lucene search engine with vector fields | Yes | Yes | Partly: aggregations; experimental SQL vectors without GROUP BY | No | Apache 2.0 |
| SereneDB | Search analytics database with Postgres SQL | Yes | Yes | Yes | Yes | Apache 2.0 |
How we compared them
We compared the ten databases on ten questions. They come from what people search for next to "best vector database" and from what AI assistants look up when they answer it: hybrid BM25 search, metadata filtering and the license.
- Index types and quantization. Which approximate nearest neighbor (ANN) indexes it builds, such as HNSW or IVF, and how it compresses the vectors.
- Distance metrics. Cosine, Euclidean (L2), inner product and others.
- Filtering inside the vector search. Whether a filter on other fields is applied while the index is searched, or only to the results afterwards, when a selective filter can leave fewer than k rows.
- Keyword relevance next to the vectors. Whether it ranks full text with BM25 and can fuse that ranking with vector similarity, for example with reciprocal rank fusion (RRF), in one query.
- Query interface. SQL or its own API, and whether Postgres drivers work.
- Analytics over the hits. Whether the same query can group, count, sum or join the results.
- External sources. Whether it can index files you already have, such as Parquet or Iceberg on S3, or tables in another database, without a pipeline that copies them in first.
- Embeddings inside the database. Whether it can call an embedding model for you.
- License. Whether the engine is open source, and under which license.
- LangChain. Whether there is an integration for the framework most RAG tutorials start from.
The list below is grouped by architecture, not ranked: which database fits depends on what your query needs besides the nearest vectors. We don't rank by speed either, because speed depends on your vectors, your filters and the recall you need. Where we publish a benchmark, we link it with its method.
Every cell below comes from the vendors' documentation as we read it on 2026-11-05, for the versions listed under References; later releases may differ.
Vector database comparison table
The figure sums up five columns of the available solutions reference; the three tables below give every cell with its source. A cell says "not documented" when the vendor's docs don't cover it.
Indexes and filters
Keywords, query language and analytics
| Database | BM25 + vectors in one query | Query interface | Aggregates over the hits |
|---|---|---|---|
| Pinecone | Partly: RRF in SQL through pg_pinecone; the API ranks by one scoring type per request, with RRF in the client | HTTP API and SDKs; SQL through pg_pinecone | None in the API; joins in SQL through pg_pinecone |
| Milvus | Yes: BM25 as sparse vectors, fused by RRF or weights | REST, gRPC and SDKs; no SQL | Bucketed count, sum, avg, min, max over the ANN candidates; exact group-by aggregates over filtered rows, without vector ranking |
| Qdrant | Yes: BM25 as sparse vectors since 1.10, on full-text indexes since 1.20, fused by RRF or DBSF | REST, gRPC and SDKs; no SQL | Groups of hits; facet counts over filtered points |
| Weaviate | Yes: BM25F in a hybrid query | gRPC client libraries and REST; no SQL | Aggregate API over search results, one group-by property |
| Chroma | Chroma Cloud only: BM25 sparse vectors fused with dense ones by RRF | Client methods, in process in Python or over HTTP; no SQL | None; the Search API keeps the top k hits per group, Chroma Cloud only |
| pgvector | ts_rank, not BM25; RRF written in SQL | SQL over the Postgres protocol | SQL: GROUP BY, joins |
| MongoDB Vector Search | Yes: BM25 $search with $rankFusion | Aggregation pipeline from MongoDB drivers; its SQL Interface doesn't run vector search | lookup and other stages after $vectorSearch |
| Elasticsearch | Yes: BM25 and kNN fused by the RRF retriever with an Enterprise subscription, or by a score sum on the free license | Query DSL and ES|QL with KNN | Aggregations over kNN hits |
| OpenSearch | Yes: BM25 and kNN in a hybrid query | Query DSL; SQL vectorSearch(), experimental, without GROUP BY over it | Aggregations over hybrid hits |
| SereneDB | Yes: BM25 and vectors fused with RRF in one SQL query | SQL over the Postgres protocol | SQL: GROUP BY, joins, window functions |
External sources, embeddings and license
The 10 vector databases, by architecture
The list runs from engines built for vectors alone, through vector search added to a database or search engine you may already run, to one engine for the whole query. Each entry says what the database is, what its docs show it does well, when to pick it and what you run next to it for the rest of the query.
Vector-native engines with their own API. Five engines built around vector search, each queried through its own API and SDKs.
Pinecone
Pinecone is a vector database you use through a versioned HTTP API and SDKs for Python, Node.js and Go. A document index holds dense vectors, sparse vectors, BM25-indexed text fields and filterable metadata side by side, and each search picks one of them to rank by. Facts below are for API version 2026-07 and pg_pinecone 0.11.0.
- BM25 full-text search with Lucene query syntax, phrases, fuzzy terms and n-gram substrings.
- Filters narrow the candidates before ranking.
- Integrated embedding inside the request, so an application can send plain text both ways, and hosted reranking as a separate call.
- pg_pinecone, an Apache 2.0 Postgres extension, exposes the same search from SQL, and its reference fuses a BM25 ranking and a vector ranking with RRF in one statement.
Pick it when your application already runs on Pinecone's API or SDKs.
What you run next to it: an API request commits to one scoring type, so a BM25 ranking and a vector ranking are fused in your application, as Pinecone's own RRF guide does, or in Postgres through pg_pinecone. Counts or sums over the hits need Postgres or another database, and data comes in by upsert or by bulk import from object storage. We compare the two in detail on SereneDB vs Pinecone.
Milvus
Milvus is an open-source vector database under Apache 2.0. It stores dense, sparse and binary vectors next to scalar, JSON and text fields in typed collections, and you query it through SDKs for Python, Java, Go, Node.js, C++, C# and Rust or its REST and gRPC APIs. Facts below are for Milvus 3.0.5.
- Index types from IVF and HNSW to DiskANN, ScaNN and GPU indexes, with scalar, product and RaBitQ quantization.
- BM25 from raw text, stored as sparse vectors and fused with dense results in one hybrid_search call by RRF or weights.
- Filters run before the ANN search by default.
- External collections index Parquet, Lance, Vortex or Iceberg data on S3, GCS, Azure or OSS where it is, once Storage V3 is turned on, and search aggregation counts and sums the ANN candidates into buckets.
Pick it when your stack already runs on Milvus collections and its SDKs.
What you run next to it: Milvus has no SQL, so joins with your other tables happen elsewhere. Search aggregation works on the ANN candidates rather than on every match and can't be combined with a hybrid search in the same request; exact group-by aggregation runs on filtered rows without a vector ranking. Tables in another database are copied in first.
Qdrant
Qdrant is an open-source vector search engine under Apache 2.0. It stores points, each with one or more vectors and a JSON payload, and you query them through one Query API over REST or gRPC, with SDKs for Python, TypeScript, Rust, Go, .NET and Java. Facts below are for Qdrant 1.20.0.
- Filterable HNSW: payload indexes add graph edges so filters apply while the graph is walked, with ACORN for combinations of strict filters.
- BM25 on full-text payload indexes since 1.20, as well as BM25 as sparse vectors, fused with dense vectors by RRF, weighted RRF or DBSF in one request.
- Dense, sparse and multivector vectors on one point, and scalar, product, binary and TurboQuant quantization.
Pick it when your application already runs on Qdrant's Query API or one of its SDKs.
What you run next to it: Qdrant has no SQL. It groups hits by a field and counts filtered points with its Facet API, but sums and joins over the hits need another database, and data comes in by upsert or snapshot rather than being searched where it lives. We compare the two in detail on SereneDB vs Qdrant.
Weaviate
Weaviate is a vector database that keeps objects with typed properties and one or more named vectors in collections. Its client libraries for Python, TypeScript, Go, Java and C# talk gRPC, and it can call an embedding model itself. The core engine is under BSD-3-Clause; since 1.40, released in October 2026, three Enterprise features sit under the separate, commercial Weaviate License and need a license key. Facts below are for Weaviate 1.40.3.
- BM25F keyword search and vector search fused in one hybrid query, with relative-score or ranked fusion and an alpha weight.
- Pre-filtering: the filter builds an allow-list before the HNSW search, with ACORN as the default strategy.
- Vectorizer integrations embed objects on import and query text at search time.
- The Aggregate API counts and sums the results of a vector or hybrid search, grouped by one property.
Pick it when your application already uses Weaviate's client libraries or its vectorizer modules.
What you run next to it: Weaviate has no SQL, so aggregates beyond what the Aggregate API returns, and joins with your other tables, happen elsewhere. Data comes in by batch import.
Chroma
Chroma is an open-source retrieval database under Apache 2.0. It runs inside a Python process, in memory or on a local path, or as a server reached over HTTP, with clients for Python, TypeScript and Rust. Each record carries an embedding, metadata and a document text. Facts below are for Chroma 1.5.9.
- In-process Python clients with nothing to set up, and a default local model that embeds text when you give no embedding function.
- One query call combines vector similarity, a metadata filter and a document substring or regex filter.
- HNSW settings and the distance metric per collection.
Pick it when you are prototyping in Python and want vector search inside the process.
What you run next to it: single-node Chroma matches document text with substring and regex filters but doesn't rank it with BM25; hybrid search, sparse vectors and grouping come with Chroma's Search API, which is available in Chroma Cloud only. Counts and joins over the hits happen in your code.
Vector search inside a database or search engine you may already run. Four systems where vectors sit next to data you already keep there.
pgvector
pgvector is an open-source PostgreSQL extension under the PostgreSQL License. It adds vector types, distance operators and HNSW and IVFFlat indexes, so embeddings sit in ordinary tables next to the rest of each row and you query them in plain SQL over any Postgres driver. Facts below are for pgvector 0.8.7.
- Joins,
WHERE,GROUP BYand PostgreSQL's full-text search share one statement with the vector search. - Six distance functions, L1, Hamming and Jaccard among them, and half-precision, binary and sparse vectors.
- Iterative index scans keep scanning until a filtered query has enough rows or reaches a scan limit.
Pick it when you already run PostgreSQL and the query is the nearest vectors plus filters and joins on tables you already have.
What you run next to it: PostgreSQL ranks full text with ts_rank and ts_rank_cd, not BM25, and pgvector's README fuses keyword and vector results by hand, with RRF written in SQL. With an approximate index the filter is applied after the index scan. Foreign tables can be scanned but not given a vector index, and core PostgreSQL has no Parquet or Iceberg reader.
MongoDB Vector Search
MongoDB Vector Search, formerly Atlas Vector Search, adds approximate and exact
nearest-neighbor search over embeddings in MongoDB documents. You define a
vectorSearch index on a collection and query it with a
$vectorSearch
stage at the head of an aggregation pipeline. Facts below are for MongoDB 9.0.
- Pre-filters on indexed fields, applied before the HNSW graph is walked.
- BM25 keyword
search in
$search, fused with$vectorSearchby [scoreFusion` in one pipeline. - Later pipeline stages such as
$groupand$lookupwork on the hits. - Scalar and binary quantization, and Automated Embedding with Voyage AI models, generally available on Atlas and in preview on self-managed deployments.
Pick it when your documents already live in MongoDB.
What you run next to it: within one collection, little: keywords, vectors,
filters and $group fit in one pipeline. What stays outside is SQL over the
hits, since MongoDB's
SQL Interface
doesn't run vector search, and data that isn't in MongoDB yet: files on S3 and
tables in another database are imported first. The server is under
SSPL v1.
Elasticsearch
Elasticsearch is a search and analytics engine built on Apache Lucene. It keeps JSON documents in indices, with vector fields next to text, keyword and numeric fields, and you query them over REST with JSON Query DSL or with ES|QL. Its core source is under a choice of AGPLv3, SSPL v1 or Elastic License 2.0; the x-pack features, ES|QL, the RRF retriever and the inference API among them, are under Elastic License 2.0 only. Facts below are for Elasticsearch 9.5.6.
- A filter inside the
knnclause is applied during the approximate search, so k matching documents come back. - BM25 is the default text scoring, and the RRF and linear retrievers fuse it with kNN in one request with an Enterprise subscription; on the free license a kNN search next to a query sums the two scores.
- Aggregations run over the hits of a kNN query in the same request.
- Float vectors are quantized to int8, int4 or one-bit BBQ, or to 2, 4 or 7 bits with DiskBBQ, and the inference API embeds text in the engine; DiskBBQ and the inference API need an Enterprise subscription.
Pick it when your documents are already indexed in Elasticsearch.
What you run next to it: for one index, little: keywords, vectors, filters and aggregations fit in one request. What stays outside is SQL over Postgres drivers, and data that isn't indexed yet: ES|QL can read Parquet on S3 in an experimental mode, which needs an Enterprise subscription when self-managed, but without kNN or BM25 over it, so files and tables elsewhere are ingested first. We compare the two in detail on SereneDB vs Elasticsearch.
OpenSearch
OpenSearch is a search and analytics engine built on Apache Lucene, under Apache 2.0. It keeps JSON documents in indices, with vector fields next to text, keyword and numeric fields, and you query them over REST with JSON Query DSL; SQL runs k-NN queries through an experimental vectorSearch() function. Facts below are for OpenSearch 3.9.0.
- A filter inside the
knnclause is applied during the approximate search, so k matching documents come back. - BM25 is the default text scoring, and a hybrid query with a normalization or RRF search pipeline fuses it with kNN in one request.
- Aggregations run over the hits of a hybrid query in the same request.
- Scalar, product and binary quantization, and text embedded in the engine through ML Commons.
Pick it when your documents are already indexed in OpenSearch.
What you run next to it: for one index, little: keywords, vectors, filters and aggregations fit in one request. What stays outside is SQL over Postgres drivers, and data that isn't indexed yet: OpenSearch can query S3 tables in place through Spark, but without k-NN or BM25 over them, so files and tables elsewhere are ingested first. We compare the two in detail on SereneDB vs OpenSearch.
One SQL engine for vectors, keywords and analytics. The last entry answers the whole query in one statement.
SereneDB
SereneDB is a real-time search analytics database: one Postgres-compatible
engine that answers hybrid questions, finding the relevant records in
unstructured data and computing over them in the same query. It is open source
under Apache 2.0. An
embedding is a FLOAT[N] column, and its HNSW or IVF index is one more column
of the same inverted index that serves full-text search and filters.
- Indexes: HNSW and IVF, with l2, cosine, inner product and l1 distance and eleven quantizers from 16-bit floats down to one bit per dimension, sq8 by default.
- Filters inside the search: a filter on an indexed column runs inside the
index scan;
EXPLAINon a filtered top-k query shows the filter in the sameIRESEARCH_SCANas the cosine ranking. - Hybrid in one statement: BM25 and vector rankings fused with RRF in one SQL query.
- Analytics over the hits: the hits are rows, so
GROUP BY, joins and window functions apply to them. - External sources: full-text and vector indexes over Parquet, CSV, JSON and Iceberg files on disk or S3, and over tables in Postgres or ClickHouse, with the rows left where they are.
- Postgres protocol: psql, psycopg, JDBC and other Postgres drivers connect as they are; embeddings come from SQL with ai_embed, and langchain-serenedb is a LangChain vector store.
Here is a retrieval step for a support assistant, over the articles table
from Try it yourself: billing articles only, ranked by
the keyword "refund" with BM25 and by closeness to the question's embedding,
the two rankings fused with RRF.
WITH lex AS (
SELECT id, RANK() OVER (ORDER BY s DESC) AS rank FROM (
SELECT id, BM25(articles_idx.tableoid) AS s
FROM articles_idx
WHERE title @@ ts_phrase('refund') AND product @@ 'billing'
ORDER BY s DESC LIMIT 100) l
), vec AS (
SELECT id, RANK() OVER (ORDER BY d) AS rank FROM (
SELECT id, emb <=> [1.0, 0.0, 0.0]::FLOAT[3] AS d
FROM articles_idx
WHERE product @@ 'billing'
ORDER BY d LIMIT 100) v
), fused AS (
SELECT id, SUM(1.0 / (60 + rank)) AS rrf
FROM (SELECT * FROM lex UNION ALL SELECT * FROM vec) b
GROUP BY id
)
SELECT a.id, a.title, round(f.rrf, 4) AS rrf
FROM fused f JOIN articles a USING (id)
ORDER BY f.rrf DESC, a.id
LIMIT 3;
id | title | rrf
----+------------------------------------------+--------
1 | Refund a card payment | 0.0328
5 | Why a refund takes five days | 0.0325
2 | Change the billing address on an invoice | 0.0159
The same index answers the analytics question, how many articles mention a refund and how often they are read, per product:
SELECT product, count(*) AS articles, sum(views) AS views
FROM articles_idx
WHERE title @@ ts_phrase('refund')
GROUP BY product
ORDER BY views DESC;
product | articles | views
---------+----------+-------
billing | 2 | 1800
orders | 1 | 950
Pick it when the query needs two or more of the nearest vectors, keyword relevance, filters and an aggregate; when the data already sits in Parquet, Iceberg or Postgres and you would rather index it than copy it; or when you want Apache 2.0 and the Postgres drivers you already use.
What you run next to it: nothing else for this query. The statement above is the whole retrieval step, with no second system for keywords and no export for the aggregate.
Speed, with the method: on VectorBench, published on 2026-11-05, SereneDB 26.11.1 answered faster than Qdrant 1.20.0 in 32 of the 33 result rows both engines reach over 247 million Cohere Wikipedia vectors, by 1.3× to 14×, with the same HNSW settings on the same hardware. Keyword ranking runs on IResearch, which you can compare with Lucene and Tantivy on the open Search Benchmark Game.
Also worth a look
Three more engines that come up in the same answers:
- LanceDB is a library that runs inside a Python, TypeScript or Rust application and stores tables in the open Lance columnar format; one hybrid query merges BM25 and vector results, with RRF by default. Its open-source edition is under Apache 2.0 (docs, version 0.41.0).
- Vespa indexes tensor fields with HNSW, ranks text with BM25 as a rank feature and combines both in one YQL query through a rank profile; it is under Apache 2.0 (docs, version 8.781.11).
- Redis indexes vectors in hashes or JSON documents with FLAT, HNSW or
SVS-VAMANA, and
FT.HYBRIDfuses a BM25 text query with a vector query in one command; Redis 8 is under a choice of RSALv2, SSPL v1 or AGPLv3 (docs, version 8.10.3).
Dedicated vector database or vector search in the database you already run?
Stay with a dedicated vector database when your application already runs on its API and the query needs nothing but the nearest vectors. Once the query also needs keyword relevance, filters on fields that live in your main database, or numbers computed over the hits, search in the engine that holds the data saves you a sync pipeline and one or two more systems.
Here's what a dedicated vector store asks of you in that case:
- A copy of your data. Each embedding goes in with every field a filter will need, and the copy has to follow every insert, update and delete in the source, through change data capture, replication or a batch job.
- A second system for keywords when its keyword ranking doesn't cover your queries, and a merge step in the application when the two rankings have to be combined.
- A third system for numbers. Counting the hits by product or summing a metric over them means exporting the results to a database that can do it.
- One permission model per system, each kept in step with the others.
Search in the engine that holds the data keeps one copy, one query language and one permission model. In SereneDB the data doesn't even have to move in first: an index can be built over the Parquet, CSV, JSON or Iceberg files you already have, or over a table in Postgres or ClickHouse, and CREATE SUBSCRIPTION applies a Postgres publication's inserts, updates and deletes to SereneDB tables, whatever indexes they carry. Our posts A demo trilogy: Vectorizer and Hybrid search and Search where your data lives walk through both.
How to choose a vector database (for RAG too)
Start from what you already run and from what the query needs besides the nearest vectors:
- Your application already calls a vendor's vector API. Stay with it, and add only what the query lacks.
- You are prototyping in a Python notebook. An embedded engine such as Chroma or LanceDB runs inside the process, with nothing to set up.
- You already run Postgres. pgvector adds vectors to your tables. When the same tables also need BM25 ranking, SereneDB speaks the Postgres protocol and can index a Postgres table where it is.
- You already run Elasticsearch, OpenSearch or MongoDB. Their vector search sits next to the documents you already index.
- The query needs the nearest vectors, keyword relevance and metadata filters at once, as most RAG retrieval does: pick an engine that fuses BM25 and vector rankings in one query. The comparison table shows which do.
- It also counts or groups the hits, or the data sits in Parquet or Iceberg on S3. The table shows which engine answers that in one statement.
- Open source is a requirement. See the license column.
Whatever you pick, test recall and latency on your own vectors and your own queries before you commit. Try it yourself below is a starting point for SereneDB.
How vector databases work
A vector database stores embeddings, arrays of floats that a model computes from text, images or code so that similar items get nearby vectors, and finds the vectors nearest to a query vector. Comparing the query with every stored vector is exact but slow at millions of rows, so vector databases build an approximate nearest neighbor (ANN) index, which trades a little recall, the share of the true nearest neighbors a search returns, for speed.
Two index families dominate:
- HNSW links every vector to its nearest neighbors in a layered graph. A query walks the graph from a coarse top layer down to the bottom one, keeping a beam of the best candidates. A wider beam raises recall and costs time.
- IVF splits the vectors into clusters around centroids. A query compares itself with the centroids first, then scans only the vectors of the closest few clusters. Scanning more clusters raises recall and costs time.
Quantization stores each vector in fewer bits, from 16-bit floats down to one bit per dimension, so more of the index fits in memory. It costs some recall, which a second pass over the best candidates at full precision wins back.
Filtering is where vector databases differ most. A filter applied after the search can leave fewer than k results when it is selective; a filter applied during the search keeps walking until it finds k rows that pass. Keyword relevance is the other split: BM25 ranks exact terms such as an error code that embeddings tend to blur, which is why most RAG pipelines fuse the two rankings.
FAQ
What are the top 10 vector databases?
This post compares ten. Pinecone, Milvus, Qdrant, Weaviate and Chroma are built around vector search. pgvector, MongoDB Vector Search, Elasticsearch and OpenSearch add vector search to a database or search engine you may already run. SereneDB answers vectors, BM25 keywords, filters and SQL aggregates in one query. The comparison table shows what each one documents.
How do vector databases work?
A vector database stores embeddings and finds the ones nearest to a query vector. Instead of comparing the query with every vector, it searches an approximate nearest neighbor index, usually an HNSW graph or IVF clusters, which trades a little recall for speed. Quantization shrinks the stored vectors, and filters narrow the search to rows that match other fields.
Which vector database is best for RAG?
The one that retrieves by meaning and by exact keyword, with filters, in one query, because RAG questions mix both: "refund for order 4182" needs the embedding for the intent and the exact order number. Milvus, Qdrant, Weaviate, LanceDB, Vespa, Redis, MongoDB Vector Search, Elasticsearch, OpenSearch and SereneDB fuse BM25 and vector rankings in one query, and SereneDB also aggregates over the hits in the same SQL. Then pick by what you already run, and test recall on your own data.
What is the best open-source vector database?
It depends on what else the query needs. Milvus, Qdrant, Chroma, LanceDB, Vespa and OpenSearch are under Apache 2.0, pgvector under the PostgreSQL License, Weaviate's core under BSD-3-Clause, and Elasticsearch's core and Redis 8 can be used under AGPLv3. When the same query also needs BM25 ranking, filters and aggregates over the hits, SereneDB, under Apache 2.0, answers it in one SQL statement.
Do I need a dedicated vector database, or can my SQL database do vector search?
Not necessarily. pgvector adds HNSW and IVFFlat indexes to PostgreSQL, and SereneDB is a Postgres-compatible engine with HNSW and IVF next to BM25 and SQL analytics. A dedicated vector database fits when your application already runs on its API and the query needs only the nearest vectors. Once it also needs keywords, filters on your own tables or aggregates, search in the engine that holds the data saves a sync pipeline.
Which vector databases support hybrid search with BM25 and metadata filters?
Per their docs on 2026-11-05, Milvus, Qdrant, Weaviate, LanceDB, Vespa, Redis, MongoDB Vector Search, Elasticsearch, OpenSearch and SereneDB fuse BM25 and vector rankings in one query and apply filters during the search. Pinecone's API ranks a request by BM25 or by vectors, not both, and pg_pinecone fuses the two with RRF in SQL. pgvector's hybrid search pairs PostgreSQL's ts_rank with RRF written in SQL. Single-node Chroma filters document text without ranking it, and hybrid search is in Chroma Cloud's Search API.
Try it yourself
Start SereneDB in Docker and connect with psql, or any Postgres client:
docker run --rm -d --name serenedb -e SERENEDB_HOST_AUTH_METHOD=trust \
-p 127.0.0.1:7890:7890 serenedb/serenedb:26.11.2
psql -h 127.0.0.1 -p 7890 -U postgres
Create a table of support articles with a three-dimensional embedding, and one inverted index over its title (full text), its product (a filter) and its embedding (HNSW, cosine):
CREATE TABLE articles (
id INTEGER PRIMARY KEY,
title VARCHAR,
product VARCHAR,
views INTEGER,
emb FLOAT[3]
);
CREATE TEXT SEARCH DICTIONARY en AS
split_text(case := 'lower')
| normalize_tokens('en_US.UTF-8', accent := false)
| stem_words('en_US.UTF-8')
WITH (frequency, position);
CREATE INDEX articles_idx ON articles
USING inverted (id, title en, product, emb hnsw (metric = 'cosine'))
INCLUDE (views);
INSERT INTO articles VALUES
(1, 'Refund a card payment', 'billing', 1200, [0.90, 0.10, 0.00]),
(2, 'Change the billing address on an invoice', 'billing', 800, [0.60, 0.40, 0.00]),
(3, 'Request a refund for a cancelled order', 'orders', 950, [0.80, 0.20, 0.10]),
(4, 'Rotate an API key', 'security', 400, [0.00, 0.10, 0.90]),
(5, 'Why a refund takes five days', 'billing', 600, [0.85, 0.05, 0.10]),
(6, 'Export orders to CSV', 'orders', 300, [0.20, 0.80, 0.10]);
VACUUM (REFRESH_TABLE) articles;
Then run the hybrid query from the SereneDB entry and the aggregate after it. The last step indexes a Parquet file in place: it writes the table to a file, points a view at the file and builds the same kind of index over the view, so the rows stay in the file.
COPY (SELECT * FROM articles) TO '/tmp/articles.parquet' (FORMAT parquet);
CREATE VIEW lake AS
SELECT title, product, emb::FLOAT[3] AS emb
FROM read_parquet('/tmp/articles.parquet');
CREATE INDEX lake_idx ON lake
USING inverted (title en, product, emb hnsw (metric = 'cosine'));
SELECT title
FROM lake_idx
WHERE title @@ ts_phrase('refund')
ORDER BY emb <=> [1.0, 0.0, 0.0]::FLOAT[3]
LIMIT 2;
title
------------------------------
Refund a card payment
Why a refund takes five days
A Parquet file stores the embedding as a variable-length list, so the view
casts it to FLOAT[3], the fixed-size type a vector index needs. The same view
works over s3:// paths and globs; see
Indexing External Data.
Tested with SereneDB 26.11.2 on 2026-11-05.
References
Vendor documentation read on 2026-11-05, for the versions below:
- Pinecone, API 2026-07: architecture, full-text search, RRF; pg_pinecone 0.11.0 reference.
- Milvus 3.0.5: index types, full-text search, external collections, release notes.
- Qdrant 1.20.0: indexing, hybrid queries, release.
- Weaviate 1.40.3: vector indexes, filtering, hybrid search.
- Chroma 1.5.9: collection configuration, full-text search.
- LanceDB 0.41.0: indexing, hybrid search, Embedded and Enterprise.
- Vespa 8.781.11: HNSW, BM25, hybrid search.
- Redis 8.10.3: vectors, FT.HYBRID, licenses.
- pgvector 0.8.7: README; PostgreSQL 18 text search ranking.
- MongoDB 9.0: $vectorSearch, hybrid search.
- Elasticsearch 9.5.6: dense_vector, filtered kNN.
- OpenSearch 3.9.0: k-NN methods and engines, hybrid search.
- SereneDB 26.11.2: vector search, hybrid search, indexing external data.