# Функции поиска и ранжирования

### BM25A()
`BM25A(k1,b)` возвращает точное значение `BM25A()`. `BM25A(k1,b,avgdl)` дополнительно позволяет переопределить среднюю длину документа, используемую в формуле. Он требует ранкера `expr` и включенных `index_field_lengths`. Параметры `k1`, `b` и опциональный `avgdl` должны быть числами с плавающей точкой.

### BM25F()
`BM25F(k1, b, {field=weight, ...})` возвращает точное значение `BM25F()` и требует включения `index_field_lengths`. Также необходим ранкер `expr`. Параметры `k1` и `b` должны быть числами с плавающей точкой.

### EXIST()
Заменяет несуществующие столбцы значениями по умолчанию. Возвращает либо значение атрибута, указанного в 'attr-name', либо 'default-value', если этот атрибут не существует. Атрибуты STRING или MVA не поддерживаются. Эта функция полезна при поиске по нескольким таблицам с разными схемами.

```sql
SELECT *, EXIST('gid', 6) as cnd FROM i1, i2 WHERE cnd>5
```

### MIN_TOP_SORTVAL()
Возвращает значение ключа сортировки худшего элемента в текущих top-N совпадениях, если ключ сортировки является числом с плавающей точкой, и 0 в противном случае.

### MIN_TOP_WEIGHT()
Возвращает вес худшего элемента в текущих top-N совпадениях.

### PACKEDFACTORS()
`PACKEDFACTORS()` может использоваться в запросах для отображения всех рассчитанных весовых коэффициентов при сопоставлении или для предоставления бинарного атрибута для создания пользовательской ранжирующей UDF. Эта функция работает только если указан ранкер выражений и запрос не является полным сканированием; в противном случае возвращается ошибка. `PACKEDFACTORS()` может принимать необязательный аргумент, отключающий расчет фактора ранжирования ATC: `PACKEDFACTORS({no_atc=1})`. Расчет ATC значительно замедляет обработку запроса, поэтому эта опция может быть полезна, если вам нужно увидеть факторы ранжирования, но ATC не требуется. `PACKEDFACTORS()` также может выводить данные в формате JSON: `PACKEDFACTORS({json=1})`. Соответствующие выводы в формате пар ключ-значение или JSON показаны ниже. (Обратите внимание, что примеры ниже перенесены для удобства чтения; фактические возвращаемые значения будут в одну строку.)

```sql
mysql> SELECT id, PACKEDFACTORS() FROM test1
    -> WHERE MATCH('test one') OPTION ranker=expr('1') \G
*************************** 1\. row ***************************
             id: 1
packedfactors(): bm25=569, bm25a=0.617197, field_mask=2, doc_word_count=2,
    field1=(lcs=1, hit_count=2, word_count=2, tf_idf=0.152356,
        min_idf=-0.062982, max_idf=0.215338, sum_idf=0.152356, min_hit_pos=4,
        min_best_span_pos=4, exact_hit=0, max_window_hits=1, min_gaps=2,
        exact_order=1, lccs=1, wlccs=0.215338, atc=-0.003974),
    word0=(tf=1, idf=-0.062982),
    word1=(tf=1, idf=0.215338)
1 row in set (0.00 sec)
```

```sql
mysql> SELECT id, PACKEDFACTORS({json=1}) FROM test1
    -> WHERE MATCH('test one') OPTION ranker=expr('1') \G
*************************** 1\. row ***************************
                     id: 1
packedfactors({json=1}):
{

    "bm25": 569,
    "bm25a": 0.617197,
    "field_mask": 2,
    "doc_word_count": 2,
    "fields": [
        {
            "lcs": 1,
            "hit_count": 2,
            "word_count": 2,
            "tf_idf": 0.152356,
            "min_idf": -0.062982,
            "max_idf": 0.215338,
            "sum_idf": 0.152356,
            "min_hit_pos": 4,
            "min_best_span_pos": 4,
            "exact_hit": 0,
            "max_window_hits": 1,
            "min_gaps": 2,
            "exact_order": 1,
            "lccs": 1,
            "wlccs": 0.215338,
            "atc": -0.003974
        }
    ],
    "words": [
        {
            "tf": 1,
            "idf": -0.062982
        },
        {
            "tf": 1,
            "idf": 0.215338
        }
    ]

}
1 row in set (0.01 sec)
```

Эта функция может использоваться для реализации пользовательских функций ранжирования в UDF, как в:

```sql
SELECT *, CUSTOM_RANK(PACKEDFACTORS()) AS r
FROM my_index
WHERE match('hello')
ORDER BY r DESC
OPTION ranker=expr('1');
```

Где `CUSTOM_RANK()` — это функция, реализованная в UDF. Она должна объявлять структуру `SPH_UDF_FACTORS` (определена в sphinxudf.h), инициализировать эту структуру, распаковывать в нее факторы перед использованием и деинициализировать ее после использования, как показано ниже:

```sql
SPH_UDF_FACTORS factors;
sphinx_factors_init(&factors);
sphinx_factors_unpack((DWORD*)args->arg_values[0], &factors);
// ... can use the contents of factors variable here ...
sphinx_factors_deinit(&factors);
```

Данные `PACKEDFACTORS()` доступны на всех этапах запроса, а не только во время начального сопоставления и ранжирования. Это позволяет реализовать еще одно особенно интересное применение `PACKEDFACTORS()`: повторное ранжирование.

В примере выше мы использовали ранкер на основе выражений с фиктивным выражением и отсортировали результирующий набор по значению, вычисленному нашей UDF. Другими словами, мы использовали UDF для ранжирования всех наших результатов. Теперь, допустим для примера, что наша UDF чрезвычайно дорога в вычислении, с пропускной способностью всего 10 000 вызовов в секунду. Если наш запрос находит 1 000 000 документов, мы захотим использовать гораздо более простое выражение для выполнения большей части ранжирования, чтобы сохранить разумную производительность. Затем мы применим дорогую UDF только к нескольким лучшим результатам, скажем, к топ-100 результатам. Другими словами, мы построим топ-100 результатов с помощью более простой функции ранжирования, а затем переранжируем их с помощью более сложной. Это можно сделать с помощью подзапросов:

```sql
SELECT * FROM (
    SELECT *, CUSTOM_RANK(PACKEDFACTORS()) AS r
    FROM my_index WHERE match('hello')
    OPTION ranker=expr('sum(lcs)*1000+bm25')
    ORDER BY WEIGHT() DESC
    LIMIT 100
) ORDER BY r DESC LIMIT 10
```

В этом примере ранкер на основе выражений вызывается для каждого найденного документа для вычисления `WEIGHT()`, поэтому он вызывается 1 000 000 раз. Однако вычисление UDF может быть отложено до внешней сортировки, и оно будет выполнено только для топ-100 совпадений по `WEIGHT()`, согласно внутреннему лимиту. Это означает, что UDF будет вызвана только 100 раз. Наконец, выбираются топ-10 совпадений по значению UDF и возвращаются приложению.

Для справки, в распределенной настройке данные `PACKEDFACTORS()` отправляются от агентов на главный узел в двоичном формате. Это технически позволяет реализовать дополнительные этапы повторного ранжирования на главном узле при необходимости.

При использовании в SQL, но не при вызове из каких-либо UDF, результат `PACKEDFACTORS()` форматируется как обычный текст, который можно использовать для ручной оценки факторов ранжирования. Обратите внимание, что эта функция в настоящее время не поддерживается API Manticore.


### REMOVE_REPEATS()
`REMOVE_REPEATS ( result_set, column, offset, limit )` — удаляет повторяющиеся скорректированные строки с одинаковым значением 'column'.

```sql
SELECT REMOVE_REPEATS((SELECT * FROM dist1), gid, 0, 10)
```
Обратите внимание, что `REMOVE_REPEATS` не влияет на `total_found` в [метаинформации поискового запроса](../Node_info_and_management/SHOW_META.md#SHOW-META).

### WEIGHT()
Функция `WEIGHT()` возвращает рассчитанную оценку соответствия. Если порядок не указан, результат сортируется по убыванию оценки, предоставленной `WEIGHT()`. В этом примере мы сначала сортируем по весу, а затем по целочисленному атрибуту.

Приведенный выше поиск выполняет простое сопоставление, где все слова должны присутствовать. Однако мы можем сделать больше (и это всего лишь простой пример):

```sql
mysql> SELECT *,WEIGHT() FROM testrt WHERE MATCH('"list of business laptops"/3');
+------+------+-------------------------------------+---------------------------+----------+
| id   | gid  | title                               | content                   | weight() |
+------+------+-------------------------------------+---------------------------+----------+
|    1 |   10 | List of HP business laptops         | Elitebook Probook         |     2397 |
|    2 |   10 | List of Dell business laptops       | Latitude Precision Vostro |     2397 |
|    3 |   20 | List of Dell gaming laptops         | Inspirion Alienware       |     2375 |
|    5 |   30 | List of ASUS ultrabooks and laptops | Zenbook Vivobook          |     2375 |
+------+------+-------------------------------------+---------------------------+----------+
4 rows in set (0.00 sec)


mysql> SHOW META;
+----------------+----------+
| Variable_name  | Value    |
+----------------+----------+
| total          | 4        |
| total_found    | 4        |
| total_relation | eq       |
| time           | 0.000    |
| keyword[0]     | list     |
| docs[0]        | 5        |
| hits[0]        | 5        |
| keyword[1]     | of       |
| docs[1]        | 4        |
| hits[1]        | 4        |
| keyword[2]     | business |
| docs[2]        | 2        |
| hits[2]        | 2        |
| keyword[3]     | laptops  |
| docs[3]        | 5        |
| hits[3]        | 5        |
+----------------+----------+
16 rows in set (0.00 sec)
```

Здесь мы ищем четыре слова, но совпадение может произойти, даже если найдены только три из четырех слов. Поиск будет ранжировать документы, содержащие все слова, выше.

### ZONESPANLIST()
Функция `ZONESPANLIST()` возвращает пары совпавших зонных интервалов. Каждая пара содержит идентификатор совпавшего зонного интервала, двоеточие и порядковый номер совпавшего зонного интервала. Например, если документ гласит `<emphasis role="bold"><i>text</i> the <i>text</i></emphasis>`, и вы запрашиваете `'ZONESPAN:(i,b) text'`, то `ZONESPANLIST()` вернет строку `"1:1 1:2 2:1"`, означающую, что первый зонный интервал совпал с "text" в интервалах 1 и 2, а второй зонный интервал — только в интервале 1.

### QUERY()
`QUERY()` возвращает текущий поисковый запрос. `QUERY()` является выражением пост-лимита и предназначена для использования с [SNIPPET()](../Functions/String_functions.md#SNIPPET%28%29).

Функции таблиц являются механизмом обработки набора результатов после запроса. Функции таблиц принимают произвольный набор результатов в качестве входных данных и возвращают новый, обработанный набор в качестве выходных данных. Первый аргумент должен быть входным набором результатов, но функция таблицы может дополнительно принимать и обрабатывать больше аргументов. Функции таблиц могут полностью изменить набор результатов, включая схему. В настоящее время поддерживаются только встроенные функции таблиц. Функции таблиц работают как для внешнего `SELECT`, так и для [вложенного SELECT](../Searching/Sub-selects.md).

<!-- proofread -->
