Report this

What is the reason for this report?

Weaviate vs. OpenSearch vs. pgvector

Published on June 3, 2026
Andrew Dugan

By Andrew Dugan

Senior AI Technical Content Creator II

Weaviate vs. OpenSearch vs. pgvector

Introduction

When your application needs search, the obvious choices are tools you may already run, such as OpenSearch for full-text search or PostgreSQL with the pgvector extension for applications already built on relational data. Both can store and query vectors, but neither was designed with vectors as the primary data structure. OpenSearch added vector search as a plugin on top of an inverted-index engine. pgvector adds nearest-neighbor search as a SQL operator, which is useful when a vector is one column among many, but it is not built for semantic search at the center of your product.

Weaviate takes the opposite stance. The HNSW (Hierarchical Navigable Small World) vector index is the core data structure, and BM25 keyword search and hybrid search are built on top of it rather than added afterward. The practical result is that semantic search, keyword search, and the blend of both are each a single API call. DigitalOcean Managed Weaviate provisions, backs up, and patches the cluster for you, so you get those capabilities without the operational overhead.

To make the comparison concrete, this article loads the same corpus of podcast transcripts into all three DigitalOcean managed services and compares them on what actually distinguishes them for search. Those dimensions are the quality of the results (vector vs keyword vs hybrid retrieval), the amount of search logic that lives in your application, ingest speed, and index size. Raw query speed is not a focus. At this scale all three respond comparably fast, fast enough that speed is not a deciding factor.

Key Takeaways

  • Hybrid search wins on quality for every engine, and only Weaviate runs it as a single API call. Combining vector and keyword retrieval beat either alone in all three systems, with Weaviate’s hybrid scoring highest (hit@10 0.725, followed by OpenSearch at 0.685 and Postgres at 0.665). On OpenSearch and pgvector, hybrid requires two separate queries plus a rank-fusion step you write and maintain.
  • Vector-search quality is set by the embeddings, not the database. With each engine’s candidate-list depth aligned, all three scored within hit@10 0.575–0.600 on the same vectors.
  • The operational edges differ by engine. Weaviate ingested fastest because its HNSW and BM25 indexes build together in a single pass, while pgvector was the most compact (a 1.87 GB index vs OpenSearch’s 2.91 GB) but needs deliberate query construction for its keyword search to perform.

Methodology

For the dataset, we used a corpus of podcast-episode transcripts with 4,886 unique episodes and chunked into ~500-token passages, producing 100,000 documents, each carrying the passage text plus episode metadata. Embeddings were generated once with OpenAI’s text-embedding-3-small (1,536 dimensions) and cached, so the embedding step is identical for all three systems.

All three ran as DigitalOcean Managed Databases, queried from a DigitalOcean Droplet.

Service Engine / Index
Managed Weaviate HNSW (vector) + BM25 (keyword), native hybrid
Managed OpenSearch k-nearest neighbors (k-NN) Lucene HNSW + inverted index
Managed PostgreSQL + pgvector HNSW (vector_cosine_ops) + GIN tsvector

Two kinds of index appear throughout this table and the rest of the article. HNSW (Hierarchical Navigable Small World) is a graph-based index for vector search. It links each embedding to its near neighbors in a layered graph, so the engine finds the vectors closest to a query by hopping through the graph rather than comparing against all 100,000, which makes it fast but approximate. An inverted index is the classic keyword-search structure. It maps every word to the list of passages that contain it, much like the index at the back of a book maps terms to pages, and BM25 is the standard formula for ranking those matches by how rare a word is and how concentrated it is in a passage. Postgres fills the same two roles with pgvector’s HNSW implementation for vectors and a GIN (Generalized Inverted Index) over tsvector, its native full-text type, for keywords.

This is not a controlled hardware benchmark. The instances were not spec-matched, so it deliberately avoids head-to-head speed claims. The focus is result quality and the engineering differences that persist regardless of hardware, namely how each system retrieves and how much search logic you must write.

To measure retrieval quality, we randomly sampled 200 passages from the dataset and had an LLM (large language model) generate a natural-language question specific to each one. We then used those generated questions as our search queries to see whether the passage that produced each question appeared in the top ten results. A hit means the source passage came back in the top ten (hit@10), and we also recorded its mean reciprocal rank (MRR), which scores higher the closer the passage is to the top of the list. Recall@10 is measured against an exact brute-force nearest-neighbor search over the same vectors. Index size is the on-disk footprint after the full load.

For index configuration, Weaviate and pgvector use HNSW with default parameters, while OpenSearch uses the k-NN plugin with the Lucene HNSW engine and cosine similarity. Vectors are pre-computed and identical across systems. To keep the engines comparable, all three were configured the way a practitioner would configure each for English text. Weaviate’s keyword operator is technically BM25F, which can weight multiple fields, but searching a single content field reduces it to standard BM25, the same algorithm OpenSearch runs. OpenSearch uses the english analyzer (stopword removal and stemming, matching what Postgres’s english config and Weaviate’s tokenization already do) and was force-merged after loading, per the k-NN plugin’s guidance. The HNSW candidate-list depth (ef_search) was aligned at 100 for all three engines, which is Weaviate’s default.

Ingest and Loading

Embeddings were pre-computed, so loading performed the same job in all three systems, inserting 100,000 passages and building a vector index plus a keyword index over them. Since the instances were not spec-matched, the exact times don’t transfer to your hardware, but the ordering (Weaviate fastest, then Postgres, then OpenSearch) follows from how each engine builds its indexes, and that does transfer.

  • Weaviate ingests and indexes in a single pass. As each object arrives over its gRPC batch endpoint, the HNSW graph node and the BM25 inverted-index entry are created together, so when the load finishes the collection is fully searchable. There is no separate indexing step to run, schedule, or wait for.
  • Postgres separates loading from indexing. Bulk inserts (execute_values) land rows quickly, then the HNSW and GIN indexes are built as explicit follow-up steps. On this corpus of small passages the index builds were brief. On larger corpora the HNSW build becomes the dominant cost, and it’s a step you own. You order it, monitor it, and remember it on every reload.
  • OpenSearch pays its indexing cost repeatedly during the load. Its k-NN structures are rebuilt as segments merge throughout ingestion, so index maintenance is interleaved with the bulk load and re-paid throughout it, making it the slowest of the three here. Tuning (larger segments, deferred refresh) can recover some of that time, which is again logic that lives on your side.

The pattern to take away is that the difference isn’t raw insert speed, it’s where the index-building work happens, whether inline and invisible (Weaviate), as a deliberate post-load step (Postgres), or amortized across the load itself (OpenSearch).

Hybrid Search: One Call vs. Two

Hybrid search, which blends semantic (vector) and keyword (BM25) relevance, is both the highest-quality approach (as the quality section shows) and where the architectural differences between these systems are most visible. The real cost is what your application has to own.

Weaviate runs hybrid search natively in one call. It queries the HNSW and BM25 indexes together, fuses them with Reciprocal Rank Fusion (RRF), and returns one ranked list. The alpha parameter controls the blend (0 = pure keyword, 1 = pure vector).

results = collection.query.hybrid(
    query=query_text,
    vector=query_vector,
    alpha=0.5,
    limit=10,
)

OpenSearch has no native hybrid query in this configuration. You issue a vector query and a keyword query, then fuse the ranked lists in your application.

knn = client.search(index="passages", body={
    "size": 50, "query": {"knn": {"embedding": {
        "vector": query_vector, "k": 50,
        "method_parameters": {"ef_search": 100}}}}})
bm25 = client.search(index="passages", body={
    "size": 50, "query": {"match": {"transcript_text": query_text}}})

def rrf(*result_lists, k=60):            # you write, test, and maintain this
    scores = {}
    for results in result_lists:
        for rank, hit in enumerate(results):
            scores[hit["_id"]] = scores.get(hit["_id"], 0) + 1 / (k + rank + 1)
    return sorted(scores, key=scores.get, reverse=True)[:10]

results = rrf(knn["hits"]["hits"], bm25["hits"]["hits"])

pgvector has no hybrid primitive either, so the same two-ranking fusion is expressed in SQL.

WITH v AS (SELECT guid, row_number() OVER (ORDER BY embedding <=> %(qv)s) rk
           FROM passages ORDER BY embedding <=> %(qv)s LIMIT 50),
     k AS (SELECT guid, row_number() OVER (ORDER BY ts_rank(tsv, to_tsquery('english', %(q)s)) DESC) rk
           FROM passages WHERE tsv @@ to_tsquery('english', %(q)s) LIMIT 50)
SELECT p.guid,
       COALESCE(1.0/(60+v.rk),0) + COALESCE(1.0/(60+k.rk),0) AS rrf_score
FROM passages p LEFT JOIN v USING (guid) LEFT JOIN k USING (guid)
WHERE v.guid IS NOT NULL OR k.guid IS NOT NULL
ORDER BY rrf_score DESC LIMIT 10;
System How Hybrid Works Network Round Trips Fusion Logic You Maintain
Weaviate Native, one call One None (alpha parameter)
OpenSearch Two queries + client merge Two RRF function in app code
pgvector Two rankings + merge in SQL One RRF expression in every query

Beyond round trips, the two-ranking approach creates a maintenance surface. The fusion logic lives in your code, must be tested, and must stay consistent across every service and language that queries search. With Weaviate, tuning the blend is one float. Everywhere else it is a smoothing constant inside a function you own.

Search Quality: Vector vs Keyword vs Hybrid

Using the 200 generated questions described in the methodology, each engine was scored on whether the source passage appeared in its top 10 (hit@10) and on its mean reciprocal rank (MRR).

Engine Vector (hit@10 / MRR) Keyword Hybrid
pgvector 0.575 / 0.376 0.550 / 0.357 0.665 / 0.446
Weaviate 0.600 / 0.399 0.660 / 0.465 0.725 / 0.504
OpenSearch 0.580 / 0.382 0.635 / 0.475 0.685 / 0.450

Three findings stand out.

  • Hybrid beat both vector and keyword on hit@10 for every engine. This is the single most actionable result. If search quality matters, blend the two modalities.
  • Vector quality is essentially identical across all three engines (hit@10 0.575–0.600), since they hold the same embeddings and, with candidate depth aligned, fetch them with near-equal recall (0.967–0.988). The database does not make the vectors better or worse. It can only succeed or fail at fetching them.
  • Weaviate had the best hybrid and the best overall result (hit@10 0.725, MRR 0.504), reflecting its strong native fusion and BM25.

Postgres full-text search scored 0.04 with plainto_tsquery, which requires every word in a question to match. Rewriting the query to OR its terms (to_tsquery with |) lifted it to 0.550. OpenSearch and Weaviate behave well by default, but with Postgres you must construct the text query deliberately.

What the Numbers Look Like for One Query

Aggregate scores are abstract, so here is what the systems actually return for a real question, “how to handle rejection in sales”. Passages are mid-conversation transcript chunks, so they start mid-sentence.

Vector search returned identical top threes on all three engines because they hold the same embeddings. The strongest answer comes from an interview with Daniel Pink about his sales book To Sell Is Human:

“…gonna get rejected, there’s no question about it. So one of the qualities that I talk about is a quality called buoyancy… every day I face an ocean of rejection. Okay, that’s what sales is like… So buoyancy is how do you stay afloat in that ocean of rejection?”

Your choice of database does not change what semantic search finds. The embedding model does. The database only affects how reliably it fetches the right vectors (recall).

Keyword search agrees at the top for this query, with all three engines ranking the same two passages first, a sales veteran’s story about starting out cold calling door to door and an Art of Charm (Jordan Harbinger) listener question about cold-call anxiety. The divergence shows at the third position, where each engine fills the slot differently, though all stay on topic.

Engine Third Keyword Result
Weaviate the Daniel Pink buoyancy passage above on topic ✓
pgvector 30 Minutes to President’s Club, an SDR (Sales Development Representative) cold-call training story on topic ✓
OpenSearch a solo episode on avoiding new work for fear of rejection on topic ✓

The divergence is not always that gentle. On another of the 200 eval questions, “What should a presenter do if their audience starts leaving during their session?”, only Weaviate returned the source passage the question was generated from, and the other two engines agreed on the same miss.

Engine Top Keyword Result
Weaviate The Art of Charm, a speaking coach handling exactly that. “…with everybody leaving, I would probably say to the organizer… do we need to reschedule my session? Is there something we need to do to handle this?…” the source passage ✓
pgvector a musician on when to stop playing a song that isn’t landing with the crowd wrong domain ✗
OpenSearch the same musician passage wrong domain ✗

Field weighting and analyzer choices, not the BM25 algorithm, decide whether keyword search stays on topic. Keyword search counts words instead of understanding them, so what you let it count matters. Hybrid search fuses the two signals and, for this query, lands all three engines on the same top three, the sales veteran’s cold-calling story, the Daniel Pink buoyancy passage, and the cold-call anxiety question. That is the pattern the aggregate table shows. Vector search is consistent across engines, keyword search is where they diverge, and hybrid is the most reliable for a real query.

Index Size

On-disk footprint after loading all 100,000 documents with 1,536-dimensional embeddings plus passage text and metadata:

System Index Size Notes
PostgreSQL + pgvector 1.87 GB 781 MB HNSW + 42 MB GIN full-text + table
OpenSearch 2.91 GB k-NN graph + inverted index + raw vectors stored in _source
Weaviate not exposed Managed Weaviate does not surface on-disk size via API

pgvector is the most compact, a genuine advantage when vectors are one column in an existing table. OpenSearch’s larger footprint comes partly from retaining the raw embedding array in each document’s _source alongside the k-NN graph. (Weaviate maintains an HNSW graph plus an inverted index, but the managed service does not currently expose a disk figure, so it is omitted rather than estimated.)

When to Use Each

Weaviate is the right choice when semantic search or retrieval-augmented generation (RAG) is the primary workload. Native hybrid search, the highest ingest throughput, and the best retrieval quality in this comparison make it the least-maintenance option when search is central to the product. The alpha parameter replaces an entire fusion function and the application logic around it. DigitalOcean Managed Weaviate provisions in minutes with no index management in your code.

OpenSearch is the right choice when you already run an OpenSearch cluster for full-text search or log analytics and want to add vector search incrementally, or when you need its mature faceting, aggregations, and horizontal scale. It performs respectably, but hybrid search is client-side orchestration, and its k-NN engine choice meaningfully affects recall and tuning, so get that decision right early.

PostgreSQL + pgvector is the right choice when vectors are secondary to a relational schema, such as a passages or products table where ORDER BY embedding <=> $1 is one condition among many WHERE clauses and JOINs, inside a transaction. It was the most compact here, and it keeps vectors consistent with the data they describe. Its trade-offs are keyword search that needs deliberate query construction and hybrid fusion you express yourself in SQL.

Conclusion

All three systems store and query vectors competently, and at this scale they answer about equally fast. The differences that matter show up in the quality of what comes back and in how much search logic you have to build. Hybrid retrieval is the highest-quality approach across the board, pgvector needs deliberate query construction to make keyword search work, OpenSearch needs deliberate analyzer and recall configuration to compete, and Weaviate delivers the top quality with the least code and the best defaults.

For applications where search is a feature alongside relational data, pgvector avoids a new service and keeps vectors close to the data they describe, at the cost of building keyword and hybrid behavior yourself. For applications where search is the product, the operational overhead of implementing hybrid search on OpenSearch or pgvector (two query paths, a fusion function, consistent tuning across every client) adds up, and Weaviate replaces all of it with one call and one parameter, while delivering the best retrieval quality in this comparison.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the author

Andrew Dugan
Andrew Dugan
Author
Senior AI Technical Content Creator II
See author profile

Andrew is an NLP Scientist with 8 years of experience designing and deploying enterprise AI applications and language processing systems.

Category:

Still looking for an answer?

Was this helpful?


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Creative CommonsThis work is licensed under a Creative Commons Attribution-NonCommercial- ShareAlike 4.0 International License.
Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

The developer cloud

Scale up as you grow — whether you're running one virtual machine or ten thousand.

Start building today

From GPU-powered inference and Kubernetes to managed databases and storage, get everything you need to build, scale, and deploy intelligent applications.

Dark mode is coming soon.