# Hybrid search

Hybrid search combines [vector search](vector-search.md) and [keyword search (BM25)](keyword-search.md) to leverage the strengths of both approaches. This takes into account results' semantic similarity (vector search) and exact keyword relevance (BM25), providing more comprehensive search results.

A hybrid search runs both search types in parallel and combines their scores to produce a final ranking of results. This makes it versatile and robust, suitable for a wide range of search use cases.

## How hybrid search works

In Weaviate, a hybrid search performs the following steps:

1. Executes both searches in parallel:
   - Vector search to find semantically similar content
   - BM25 search to find keyword matches
2. Combines the normalized scores using a [fusion method](#fusion-strategies)
3. Returns results ranked by the combined scores

```mermaid
%%{init: {
  'theme': 'base',
  'themeVariables': {
    'primaryColor': '#4a5568',
    'primaryTextColor': '#2d3748',
    'primaryBorderColor': '#718096',
    'lineColor': '#718096',
    'secondaryColor': '#f7fafc',
    'tertiaryColor': '#edf2f7',
    'fontFamily': 'Inter, system-ui, sans-serif',
    'fontSize': '14px',
    'lineHeight': '1.4',
    'nodeBorder': '1px',
    'mainBkg': '#ffffff',
    'clusterBkg': '#f8fafc'
  }
}}%%

flowchart LR
    %% Style definitions
    classDef systemBox fill:#f8fafc,stroke:#3182ce,stroke-width:1.5px,color:#2d3748,font-weight:bold
    classDef processBox fill:#f8fafc,stroke:gray,stroke-width:0.5px,color:#2d3748,font-weight:bold
    classDef component fill:white,stroke:#a0aec0,stroke-width:1px,color:#2d3748

    %% Main flow
    query["🔍 Query"] --> split["Query Processing"]

    %% Parallel processes
    split --> vector["Vector Search"]
    split --> bm25["BM25 Search"]

    %% Results combination
    vector --> fusion["Score Fusion"]
    bm25 --> fusion
    fusion --> results["📑 Ranked Results"]

    %% Parameters box
    subgraph params["Search Parameters"]
        alpha["Alpha: Balance between<br> vector and keyword scores"]
        fusion_type["Fusion Strategy:<br> rankedFusion or relativeScoreFusion"]
    end

    params --> fusion

    %% Apply styles
    class query,split,vector,bm25,fusion,results component
    class params processBox
    class alpha,fusion_type component

    %% Linkstyle for curved edges
    linkStyle default stroke:#718096,stroke-width:3px,fill:none,background-color:white
```

### Fusion strategies

Weaviate supports two strategies (`relativeScoreFusion` and `rankedFusion`) for combining vector and keyword search scores:

With `relativeScoreFusion` (default from `v1.24`), each object is scored by _normalizing_ the metrics output by the vector search and keyword search respectively. The highest value becomes 1, the lowest value becomes 0, and others end up in between according to this scale. The total score is thus calculated by a scaled sum of normalized vector distance and normalized BM25 score.

With `rankedFusion` (default for `v1.23` and lower), each object is scored according to its position in the results for the given search, starting from the highest score for the top-ranked object and decreasing down the order. The total score is calculated by adding these rank-based scores from the vector and keyword searches.

Generally, `relativeScoreFusion` might be a good choice, which is why it is the default.

The main reason is that `relativeScoreFusion` retains more information from the original searches than `rankedFusion`, which only retains the rankings. More generally we believe that the nuances captured in the vector and keyword search metrics are more likely to be reflected in rankings produced by `relativeScoreFusion`.

We include a concrete example of the two fusion strategies below.

### Fusion example

Let's say that a search returns **five objects** with **document id** (from 0 to 4), and **scores** from **keyword** and **vector search**, **ordered by score**:

| Search Type | (id): score | (id): score | (id): score | (id): score | (id): score |
| ----------- | ----------- | ----------- | ----------- | ----------- | ----------- |
| Keyword     | (1): 5      | (0): 2.6    | (2): 2.3    | (4): 0.2    | (3): 0.09   |
| Vector      | (2): 0.6    | (4): 0.598  | (0): 0.596  | (1): 0.594  | (3): 0.009  |

#### Ranked fusion

The score depends on the rank of each result and is computed according to `1/(RANK + 60)`, resulting in:

| Search Type | (id): score   | (id): score   | (id): score   | (id): score   | (id): score   |
| ----------- | ------------- | ------------- | ------------- | ------------- | ------------- |
| Keyword     | (1): 0.0154   | (0): 0.0160   | (2): 0.0161   | (4): 0.0167   | (3): 0.0166   |
| Vector      | (2): 0.016502 | (4): 0.016502 | (0): 0.016503 | (1): 0.016503 | (3): 0.016666 |

As you can see, the results for each rank are identical, regardless of the input score.

#### Relative score fusion

In relative score fusion, the largest score is set to 1 and the lowest to 0, and all entries in-between are scaled according to their **relative distance** to the **maximum** and **minimum values**.

| Search Type | (id): score | (id): score | (id): score | (id): score | (id): score |
| ----------- | ----------- | ----------- | ----------- | ----------- | ----------- |
| Keyword     | (1): 1.0    | (0): 0.511  | (2): 0.450  | (4): 0.022  | (3): 0.0    |
| Vector      | (2): 1.0    | (4): 0.996  | (0): 0.993  | (1): 0.986  | (3): 0.0    |

The scores therefore reflect the relative distribution of the original scores. For example, the vector search scores of the first 4 documents were almost identical, which is still the case for the normalized scores.

#### Comparison

For the vector search, the scores for the top 4 objects (**IDs 2, 4, 0, 1**) were almost identical, and all of them were good results. While for the keyword search, one object (**ID 1**) was much better than the rest.

This is captured in the final result of `relativeScoreFusion`, which identified the object **ID 1** the top result. This is justified because this document was the best result in the keyword search with a big gap to the next-best score and in the top group of vector search.

In contrast, for `rankedFusion`, the object **ID 2** is the top result, closely followed by objects **ID 1** and **ID 0**.

### Alpha parameter

The alpha value determines the weight of the vector search results in the final hybrid search results. The alpha value can range from 0 to 1:

- `alpha = 0`: Keyword search only
- `alpha < 0.5`: More weight to keyword search
- `alpha = 0.5`: Equal weight to both searches
- `alpha > 0.5`: More weight to vector search (`0.75` is the default)
- `alpha = 1`: Vector search only

Lower `alpha` towards `0` to give the keyword component more influence.

:::callout{intent="warning" title="Set `alpha` explicitly"}
`0.75` is the server default. It applies only when a request reaches Weaviate with no `alpha` value, which is the case for GraphQL, and over gRPC from Weaviate `v1.36.7` and later, which added the ability for a client to leave `alpha` unset.

Client libraries do not all leave `alpha` unset. Depending on your client and your server version, the effective weighting can differ from `0.75`, and in some cases can be a pure keyword search. Set `alpha` explicitly whenever the weighting matters, and check your client library page for its behavior.
:::

## Search thresholds

Hybrid search supports a maximum vector distance threshold through the `max vector distance` parameter.

This threshold applies only to the vector search component of the hybrid search, allowing you to filter out results that are too dissimilar in vector space, regardless of their keyword search scores.

For example, consider a maximum vector distance of `0.3`. This means objects with a vector distance higher than `0.3` will be excluded from the hybrid search results, even if they have high keyword search scores.

This can be useful when you want to ensure semantic similarity meets a minimum standard while still taking advantage of keyword matching.

There is no equivalent threshold parameter for the keyword (BM25) component of hybrid search or the final combined scores.

This is because BM25 scores are not normalized or bounded like vector distances, making a universal threshold less meaningful.

## Keyword (BM25) search parameters

Hybrid search in Weaviate supports all the parameters available for keyword (BM25) search. This includes, for example, the ability to set the tokenization method, stopwords, BM25 parameters (k1, b), [search operators](keyword-search.md#keyword-search-operators) (`and`, `or`, or `and_cross`), specific properties to search and/or to boost particular properties.

For more information on these parameters, see the [keyword search page](keyword-search.md).

## Further resources

- [How-to: Search](../how-to-query-search/index.md)
- [How-to: Hybrid search](../how-to-query-search/hybrid.md)
- [Blog: A deep dive into Weaviate's fusion algorithms](https://weaviate.io/blog/hybrid-search-fusion-algorithms)

## Questions and feedback

Have a question or feedback? Here's how to reach us.

::::card-grid
:::card{title="Community Forum" href="https://forum.weaviate.io/c/support" icon="messages-square"}
Ask questions and connect with other developers on our **Community forum**.
:::

:::card{title="Support" href="/guides/support-overview" icon="life-buoy"}
Weaviate Cloud user or customer? Find the right channel on the **Support page**.
:::
::::

## Related pages

- [Agents](./agents-index.md)
- [AI-assisted Weaviate code generation](./ai-assisted-vibe-coding-index.md)
- [APIs](./apis-index.md)
- [Authorization and authentication](./authorization-and-authentication-index.md)
- [Benchmarks](./benchmarks-index.md)
- [Best practices](./best-practices-index.md)
- [Client libraries](./clients-index.md)
- [Client Libraries / SDKs](./client-libraries-index.md)
- [Cloud](./cloud-index.md)
- [Cloud account management](./cloud-account-management-index.md)

# Agent Instructions

This portal answers questions programmatically. To receive a synthesized,
source-cited answer instead of crawling page by page, append the `?ask=`
query parameter to any page URL on this site:

    /guides/quickstart?ask=how+do+I+authenticate

Optional parameters:

- `&goal=<what-you-are-trying-to-do>` steers the answer toward your
  objective (e.g. `&goal=write+a+python+client`).
- `&version=<label>` scopes the answer to a mounted version when the
  portal publishes more than one.

The response is `text/markdown`: the answer followed by a `# Sources` list
of the portal pages it was grounded in. Status codes are the contract:

- `200` — the answer; `402` — the portal owner’s plan or answer credits are
  exhausted (surface this to your operator; do NOT retry); `429` — you are
  rate-limited; back off for the `Retry-After` seconds; `503` — the answer
  lane is temporarily unavailable; fall back to crawling the `.md` pages.

For the full corpus map read `llms.txt` at the site root; for the tool
surface (search + page fetch as MCP tools) see `/mcp`.
