---
metadata:
  - name: generator
    content: Diplodoc Platform v5.56.0
alternate:
  - https://ydb.tech/docs/en/dev/hybrid-search.md?version=main
  - https://ydb.tech/docs/ru/dev/hybrid-search.md?version=main
  - href: ru/dev/hybrid-search.md
    type: text/markdown
    title: Markdown version
  - href: ../llms.txt
    type: text/markdown
    title: llms.txt
sourcePath: ru/core/dev/hybrid-search.md
---
> **Documentation Index:** Fetch the complete configuration index at https://ydb.tech/docs/ru/llms.txt

# Гибридный поиск

Гибридный поиск объединяет [полнотекстовый поиск](https://ydb.tech/docs/ru/dev/fulltext-indexes.md?version=main) и [векторный поиск](https://ydb.tech/docs/ru/dev/vector-indexes.md?version=main) в едином ранжированном результате: каждый документ оценивается одновременно по релевантности текста и по близости эмбеддингов, а два ранжирования объединяются в одно. Это сочетает точность лексического сопоставления и полноту семантической близости и является распространённым строительным блоком для этапа извлечения данных в подходе Retrieval-Augmented Generation (RAG).

Общее описание гибридного поиска см. в разделе [Понятие гибридного поиска](https://ydb.tech/docs/ru/concepts/query_execution/hybrid_search.md?version=main).

Гибридный поиск — это не отдельный тип индекса. Он переиспользует два существующих индекса одной и той же таблицы:

* [fulltext_relevance](https://ydb.tech/docs/ru/dev/fulltext-indexes.md?version=main#relevance) по текстовой колонке — даёт сигнал релевантности [BM25](https://en.wikipedia.org/wiki/Okapi_BM25);
* [vector_kmeans_tree](https://ydb.tech/docs/ru/dev/vector-indexes.md?version=main) по колонке с эмбеддингами — даёт сигнал близости ближайших соседей (семантический).

## Подготовка индексов {#prepare}

Создайте таблицу с текстовой колонкой и колонкой эмбеддингов, затем добавьте оба индекса.

```yql
CREATE TABLE documents (
    id Uint64,
    text Utf8,
    embedding String,
    PRIMARY KEY (id)
);
```

Добавьте индекс `fulltext_relevance` по текстовой колонке (для ранжирования по релевантности требуется именно этот тип, а не `fulltext_plain`):

```yql
ALTER TABLE documents
  ADD INDEX ft_idx
  GLOBAL USING fulltext_relevance
  ON (text)
  WITH (tokenizer=standard, use_filter_lowercase=true);
```

Добавьте индекс `vector_kmeans_tree` по колонке эмбеддингов:

```yql
ALTER TABLE documents
  ADD INDEX vec_idx
  GLOBAL USING vector_kmeans_tree
  ON (embedding)
  WITH (distance=cosine);
```

Подробности о каждом типе индекса — в разделах [Полнотекстовые индексы](https://ydb.tech/docs/ru/dev/fulltext-indexes.md?version=main) и [Векторные индексы](https://ydb.tech/docs/ru/dev/vector-indexes.md?version=main).

## Выполнение гибридного запроса {#query}

Гибридный запрос — это обычный `SELECT` по основной таблице (без `VIEW`), у которого ключ `ORDER BY` представляет собой единственный вызов `HybridRank`. `HybridRank` принимает по одному оценивающему выражению на каждую ветвь: [FullTextScore](https://ydb.tech/docs/ru/yql/reference/builtins/fulltext.md?version=main#fulltext-score) для текстовой ветви и [Knn](https://ydb.tech/docs/ru/yql/reference/udf/list/knn.md?version=main)-расстояние или сходство для векторной ветви.

```yql
PRAGMA ydb.KMeansTreeSearchTopSize = "10";

$queryText = "машинное обучение";
$queryVector = Knn::ToBinaryStringFloat([0.1, 0.2, 0.3, 0.4]);

SELECT id, text
FROM documents
ORDER BY HybridRank(
    FullTextScore(text, $queryText),
    Knn::CosineDistance(embedding, $queryVector))
LIMIT 10;
```

Оба входа происходят из одного пользовательского запроса: `$queryText` — это текст поиска (сопоставляется лексически), а `$queryVector` — его эмбеддинг, вычисленный приложением (сопоставляется семантически). YDB не вычисляет эмбеддинги самостоятельно, поэтому вектор передаётся извне — здесь он построен из литерала с помощью [Knn::ToBinaryStringFloat](https://ydb.tech/docs/ru/yql/reference/udf/list/knn.md?version=main#functions-convert), но в приложении это результат работы модели эмбеддингов.

YDB автоматически сопоставляет каждую ветвь с её индексом по оцениваемой колонке (`text` → полнотекстовый индекс релевантности, `embedding` → векторный индекс), извлекает пул кандидатов из каждой ветви и объединяет два ранжирования. Результат — топ `LIMIT` документов по объединённой оценке.

Обратите внимание, что, в отличие от полнотекстового и векторного поиска, гибридный запрос **не** использует `VIEW IndexName`: индексы выбираются по аргументам `HybridRank`, а чтение идёт по основной таблице.

`PRAGMA ydb.KMeansTreeSearchTopSize` управляет полнотой векторной ветви — см. [KMeansTreeSearchTopSize](https://ydb.tech/docs/ru/yql/reference/syntax/select/vector_index.md?version=main#KMeansTreeSearchTopSize). Как и при обычном векторном поиске, его следует задавать явно.

## Настройка объединения {#tuning}

Способ объединения и его параметры передаются как именованные аргументы `HybridRank`. Наиболее употребительные:

* `Mode` — `"rrf"` (по умолчанию, Reciprocal Rank Fusion) или `"linear"` (взвешенная сумма нормализованных оценок);
* `Weights` — кортеж весов ветвей, по одному значению на оценивающий аргумент, для смещения ранжирования в сторону одного из сигналов;
* `K` — константа RRF (по умолчанию `60.0`);
* `Indexes` / `Limits` — явные имена индексов и размеры пулов кандидатов по ветвям.

Для встроенных режимов вклад каждой ветви фиксирован формулой. Для полного контроля над объединением передайте вместо `Mode` пользовательскую лямбду:

* `RankLambda` — лямбда, получающая ранги документа по ветвям (1-based позиция внутри каждой ветви) и возвращающая итоговую оценку;
* `ScoreLambda` — лямбда, получающая исходные оценки документа по ветвям (релевантность полнотекстового поиска или векторное расстояние/сходство) и возвращающая итоговую оценку.

Пользовательская лямбда заменяет встроенное объединение, поэтому её нельзя комбинировать с `Mode`, `Weights`, `K` или `Normalize` — перенесите все веса и константы в тело лямбды. Подробное описание и примеры — в разделе [Синтаксис гибридного запроса (HybridRank)](https://ydb.tech/docs/ru/yql/reference/syntax/select/hybrid_search.md?version=main#custom-fusion).

Например, чтобы дать векторной ветви вдвое больший вес, чем текстовой, в режиме RRF:

```yql
$queryText = "машинное обучение";
$queryVector = Knn::ToBinaryStringFloat([0.1, 0.2, 0.3, 0.4]);

SELECT id, text
FROM documents
ORDER BY HybridRank(
    FullTextScore(text, $queryText),
    Knn::CosineDistance(embedding, $queryVector),
    (1, 2) AS Weights)
LIMIT 10;
```

Полный список параметров и их семантика — в разделе [Гибридный поиск (HybridRank)](https://ydb.tech/docs/ru/yql/reference/syntax/select/hybrid_search.md?version=main).

## Ограничения {#limitations}

* Для таблицы должны существовать готовый индекс `fulltext_relevance` и непрефиксный индекс `vector_kmeans_tree` по соответствующим колонкам, иначе запрос завершится с понятной ошибкой.
* [Префиксные векторные индексы](https://ydb.tech/docs/ru/dev/vector-indexes.md?version=main) пока не поддерживаются.
* Если колонке ветви соответствует более одного полнотекстового (или векторного) индекса, ветвь неоднозначна и должна быть уточнена явным аргументом `AS Indexes`.
* `LIMIT` должен быть литералом, так как он задаёт размеры пулов кандидатов по ветвям. Чтобы использовать параметризованный `LIMIT`, передайте явный `AS Limits`.
* `HybridRank(...)` должен быть единственным ключом `ORDER BY` — его нельзя отрицать, оборачивать в другое выражение или комбинировать с другими ключами сортировки.
* Пользовательская лямбда объединения (`RankLambda` или `ScoreLambda`) заменяет встроенное объединение и не может комбинироваться с `Mode`, `Weights`, `K` или `Normalize`. Можно указать не более одного из `RankLambda` или `ScoreLambda`.
