# Dec 5th, 2025: \[EN\] You know, for hybrid search

**URL:** <https://discuss.elastic.co/t/dec-5th-2025-en-you-know-for-hybrid-search/383218>\
**Category:** Advent Calendar\
**Created:** [December 5, 2025, 8:00am UTC](https://discuss.elastic.co/t/dec-5th-2025-en-you-know-for-hybrid-search/383218 "2025-12-05T08:00:16Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![Kathleen\_DeRusso](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/kathleen_derusso/32/132039_2.png) [@Kathleen\_DeRusso](https://discuss.elastic.co/u/Kathleen_DeRusso)\
**Post date:** [December 5, 2025, 8:00am UTC](https://discuss.elastic.co/t/dec-5th-2025-en-you-know-for-hybrid-search/383218/1 "2025-12-05T08:00:16Z")

</div>

![social-advent-2021-Day5](https://us1.discourse-cdn.com/elastic/original/3X/e/3/e338700aaa54ccfa0982919c2221ad86bb467e6d.png)

If you’ve tried setting up a hybrid search experience, then you know there can be a steep learning curve. This is especially true when combining text search with semantic search results, because the scores returned from each search can be vastly different. It can be difficult to know where to start, and manually tuning results can be error prone. The good news is that we’re making this process significantly easier.

This post will focus on a lot of defaults, but it’s important to note that we’ve built a lot of customization in as well, so we support simple happy path use cases as well as powerful customizable and expert use cases.

## Indexing your data

First, let’s start with the [semantic\_text](https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/semantic-text) field. Semantic text is designed to make it seem like you’re working with a regular text field under the hood. It will take care of chunking, inference, and semantic search transparently. At the minimum, all you need is a mapping for your field:

```auto
PUT my-index
{
  "mappings": {
    "properties": {
      "semantic_title": {
        "type": "semantic_text"
      }
    }
  }
}

```

This mapping will create defaults, such as defaulting to using our in-house ELSER model for inference. No indexing pipeline configuration required! If you’re interested in trying out `semantic_text` for the first time, this [tutorial](https://www.elastic.co/docs/solutions/search/semantic-search/semantic-search-semantic-text) is a great place to start.

To ensure that semantic\_text works like a regular text field, we’ve added [support for using the match query on semantic\_text fields](https://www.elastic.co/search-labs/blog/semantic-search-match-knn-sparse-vector), making it transparent that you’re actually performing a semantic search under the hood:

```auto
POST my-index/_search
{
  "query": {
    "match": {
      "semantic_title": "What is semantic search?"
    }
  }
}

```

## 

## Hybrid search using retrievers

We then built on the fact that a lot of search use cases are well-served by match queries and their associated weights. While [retrievers](https://www.elastic.co/docs/reference/elasticsearch/rest-apis/retrievers) have been around for a while now offering capabilities like [RRF](https://www.elastic.co/docs/reference/elasticsearch/rest-apis/reciprocal-rank-fusion), we simplified this syntax to work seamlessly with any combination of `text` and `semantic_text` fields, and perform that score combination and normalization seamlessly. You can read this [blog](https://www.elastic.co/search-labs/blog/hybrid-search-multi-field-query-retrievers-elasticsearch) for all about how this [syntactic sugar](https://www.elastic.co/docs/reference/elasticsearch/rest-apis/retrievers/retrievers-examples#retrievers-examples-rrf-multi-field-query-format) came to be. Here’s an example of how to do hybrid search using RRF:

```auto
GET my-index/_search
{
  "retriever": {
    "rrf": {
      "fields": ["title", "semantic_title"],
      "query": "What is semantic search?"
    }
  }
}

```

And a similar example using the [linear](https://www.elastic.co/docs/reference/elasticsearch/rest-apis/retrievers/linear-retriever) retriever:

```auto
GET my-index/_search{
  "retriever": {
    "linear": {
      "fields": ["title", "semantic_title^2"],
      "query": "What is semantic search?",
      “normalizer”: “l2_norm”
    }
  }
}

```

These can be plugged into retrievers like the [text\_similarity\_reranker](https://www.elastic.co/docs/reference/elasticsearch/rest-apis/retrievers/text-similarity-reranker-retriever) retriever, so you can use semantic reranking over your hybrid search results. Pretty simple, right?

## Hybrid search using ES|QL

With that said some of the most exciting features we’re working on are using our new piped query language [ES|QL](https://www.elastic.co/docs/reference/query-languages/esql), which is extremely powerful for hybrid search use cases. If you’ve attended one of our [Elastic{ON}](https://www.elastic.co/events/elasticon) events this year, this preview may look a little familiar to you.

Let’s start with the [match](https://www.elastic.co/docs/reference/query-languages/esql/functions-operators/search-functions) function. We can represent this by directly referencing match:

```auto
FROM my-index METADATA _score
| WHERE match(title, "What is semantic search?")
| SORT _score DESC

```

or through a shorthand syntax:

```auto
FROM my-index METADATA _score
| WHERE title:"What is semantic search?"
| SORT _score DESC

```

The best part about this, is that because we’re using match, just like in the DSL `semantic_text` is supported out of the box!

Now, when you want to combine results using `semantic_text` you use the [FORK](https://www.elastic.co/docs/reference/query-languages/esql/commands/fork) command to execute each match query in a different fork and return them in the same result:

```auto
FROM my-index METADATA _score
| FORK 
  (WHERE semantic_title: "What is semantic search?" | SORT _score DESC)
  (WHERE title:"What is semantic search?" | SORT _score DESC)

```

You can then use the [FUSE](https://www.elastic.co/docs/reference/query-languages/esql/commands/fuse) command to combine these results using the RRF algorithm:

```auto
FROM my-index METADATA _score
| FORK 
  (WHERE semantic_title: "What is semantic search?" | SORT _score DESC)
  (WHERE title:"What is semantic search?" | SORT _score DESC)
| FUSE
| SORT _score DESC

```

You could also plug this into additional use cases like [rerank](https://www.elastic.co/docs/reference/query-languages/esql/commands/rerank) and [completion](https://www.elastic.co/docs/reference/query-languages/esql/commands/completion).

Finally, sometimes your use cases may make more sense to only perform a lexical search for example, vs. a semantic search. We can also use fork to determine at query time whether to perform a lexical or semantic search - for example based on the number of terms in the query, shorter queries may not benefit as much from semantic search for all use cases.

```auto
FROM search-index METADATA _score
| EVAL lexical = MV_COUNT(SPLIT(?query, " ")) <= 3
| FORK ( WHERE lexical | WHERE title:?query )
       ( WHERE NOT lexical | WHERE semantic_title:?query )
| SORT _score DESC

```

This is just a brief example of what we can do, but if you dig into our docs you’ll also see how powerful and customizable all of these are as well! Try them out and we look forward to hearing your feedback!
