# Обработка полученных данных

По умолчанию, первый столбец из результирующего набора `sql_query` индексируется как идентификатор документа.

Идентификатор документа *ДОЛЖЕН* быть самым первым полем, и он **ДОЛЖЕН БЫТЬ** явным, уникальным, ненулевым беззнаковым 64-битным целым числом. Отрицательные идентификаторы документов не допускаются. В отличие от RT-таблиц, `0` нельзя использовать, чтобы запросить автоматически сгенерированный ID для обычных таблиц.

Вы можете указать до 256 полнотекстовых полей и произвольное количество атрибутов. Все столбцы, которые не являются ни идентификатором документа (первым), ни атрибутами, будут проиндексированы как полнотекстовые поля.


## Объявление атрибутов:

### sql_attr_bigint

Объявляет 64-битное *знаковое* целое число.

### sql_attr_bool

Объявляет булевый атрибут. Эквивалентен целочисленному атрибуту с размером в 1 бит.

### sql_attr_float

Объявляет атрибут с плавающей точкой.

Значения будут храниться в формате одинарной точности, 32-битном IEEE 754. Представленный диапазон составляет приблизительно от 1e-38 до 1e+38. Количество десятичных цифр, которые могут быть точно сохранены, составляет приблизительно 7.

Одно из важных применений атрибутов с плавающей точкой — хранение значений широты и долготы (в радианах) для последующего использования в вычислениях расстояний на сфере во время выполнения запроса.

### sql_attr_json

Объявляет JSON-атрибут.

При индексации JSON-атрибутов Manticore ожидает текстовое поле с данными в формате JSON. JSON-атрибуты поддерживают произвольные JSON-данные без ограничений на уровень вложенности или типы.

### sql_attr_multi

Объявляет многозначный атрибут (MVA).

Обычные атрибуты позволяют прикреплять только 1 значение к каждому документу. Однако бывают случаи (например, теги или категории), когда желательно прикрепить несколько значений одного и того же атрибута и иметь возможность применять фильтрацию или группировку к спискам значений.

MVA может получать значения из столбца (как и остальные типы данных) — в этом случае столбец в результирующем наборе должен предоставлять строку с несколькими целыми значениями, разделенными запятыми — или путем выполнения отдельного запроса для получения значений.

При выполнении запроса движок запускает запрос, группирует результаты по ID и присваивает значения соответствующим документам в таблице. Значения с ID, не найденным в таблице, отбрасываются. Перед выполнением запроса будут выполнены все определенные `sql_query_pre_all`.

Формат объявления для sql_attr_multi следующий:

```ini
sql_attr_multi = ATTR-TYPE ATTR-NAME 'from' SOURCE-TYPE \
    [;QUERY] \
    [;RANGED-QUERY]
```

где

* ATTR-TYPE — это `uint`, `bigint` или `timestamp`.
* SOURCE-TYPE — это `field`, `query`, `ranged-query` или `ranged-main-query`.
* QUERY — это необязательный SQL-запрос, используемый для получения всех пар (docid, attrvalue).
* RANGED-QUERY — это необязательный SQL-запрос, используемый для получения минимального и максимального значений ID, аналогично `sql_query_range`.
* Обратные слеши включены только для ясности; все также можно объявить в одной строке.

Используется с SOURCE-TYPE типа ranged-query. Если используется SOURCE-TYPE `ranged-main-query`, то опустите RANGED-QUERY, и он автоматически будет использовать тот же запрос из `sql_query_range` (полезная опция в сложных настройках наследования, чтобы избежать многократного ручного дублирования одного и того же запроса).

```ini
sql_attr_multi = uint tag from field
sql_attr_multi = uint tag from query; SELECT id, tag FROM tags
sql_attr_multi = bigint tag from ranged-query; \
    SELECT id, tag FROM tags WHERE id>=$start AND id<=$end; \
    SELECT MIN(id), MAX(id) FROM tags
```

### sql_attr_string

Объявляет строковый атрибут. Максимальный размер каждого значения фиксирован и составляет 4 ГБ.

### sql_attr_timestamp

Объявляет временную метку UNIX.

Временные метки могут хранить даты и время в диапазоне от 1 января 1970 года до 19 января 2038 года с точностью до секунды. Ожидаемое значение столбца должно быть временной меткой в формате UNIX, то есть 32-битным беззнаковым целым числом секунд, прошедших с полуночи 1 января 1970 года по GMT. Временные метки внутренне хранятся и обрабатываются как целые числа везде. Помимо работы с временными метками как с целыми числами, вы также можете использовать их с различными функциями, основанными на датах, такими как режим сортировки по временным сегментам или извлечение дня/недели/месяца/года для GROUP BY.

Обратите внимание, что типы столбцов DATE или DATETIME в MySQL не могут быть напрямую использованы в качестве атрибутов временной метки в Manticore; вам нужно явно преобразовать такие столбцы с помощью функции UNIX_TIMESTAMP (если данные находятся в диапазоне).

Обратите внимание, что временные метки не могут представлять даты до 1 января 1970 года, и UNIX_TIMESTAMP() в MySQL не вернет ничего ожидаемого. Если вам нужно работать только с датами, а не со временем, рассмотрите функцию `TO_DAYS()` в MySQL.


### sql_attr_uint

Объявляет беззнаковый целочисленный атрибут.

Вы можете указать количество бит для целочисленных атрибутов, добавив ':BITCOUNT' к имени атрибута (см. пример ниже). Атрибуты с размером меньше стандартного 32-битного, или битовые поля, работают медленнее.

```ini
sql_attr_uint = group_id
sql_attr_uint = forum_id:9 # 9 bits for forum_id
```

### sql_field_string

Объявляет комбинированное строковое поле/атрибут. Значения будут проиндексированы как полнотекстовое поле, но также сохранены в строковом атрибуте с тем же именем. Обратите внимание, что это следует использовать только тогда, когда вы уверены, что хотите, чтобы поле было доступно для поиска как в полнотекстовом режиме, так и в качестве атрибута (с возможностью сортировки и группировки по нему). Если вы просто хотите иметь возможность получить исходное значение поля, вам не нужно ничего для этого делать, если вы явно не удалили поле из списка хранимых полей через [stored_fields](../../../Creating_a_table/Local_tables/Plain_and_real-time_table_settings.md#stored_fields).

```ini
sql_field_string = name
```

### sql_file_field

Объявляет поле на основе файла.

Эта директива заставляет индексатор интерпретировать содержимое поля как имя файла, загружать и обрабатывать указанный файл. Файлы размером больше max_file_field_buffer пропускаются. Любые ошибки во время загрузки файла (ошибки ввода-вывода, превышение лимитов и т.д.) будут сообщены как предупреждения индексации и не приведут к досрочному завершению индексации. Для таких файлов контент индексироваться не будет.

```ini
sql_file_field = field_name
```

### sql_joined_field

Запрос на получение присоединенного/полезного поля. Многозначный, необязательный, по умолчанию — пустой список запросов.

`sql_joined_field` позволяет использовать две различные функции: присоединенные поля и полезные данные (поля с полезной нагрузкой). Его синтаксис следующий:

```ini
sql_joined_field = FIELD-NAME 'from'  ( 'query' | 'payload-query' | 'ranged-query' | 'ranged-main-query' ); \
		QUERY [ ; RANGE-QUERY ]
```

где

* FIELD-NAME — это имя присоединенного/полезного поля
* QUERY — это SQL-запрос, который должен получить значения для дальнейшей обработки
* RANGE-QUERY — это необязательный SQL-запрос, который получает диапазон значений для обработки

**Joined fields** позволяют избежать использования операторов JOIN и/или GROUP_CONCAT в основном запросе выбора документов (sql_query). Это может быть полезно, когда JOIN на стороне SQL медленный, или его нужно выполнить на стороне Manticore, либо просто для имитации специфичной для MySQL функции `GROUP_CONCAT`, если ваш сервер базы данных её не поддерживает.

Запрос должен возвращать ровно 2 столбца: ID документа и текст, который нужно добавить к объединённому полю. ID документов могут повторяться, но должны идти в порядке возрастания. Все текстовые строки, полученные для данного ID, будут конкатенированы вместе, и результат конкатенации будет индексироваться как полное содержимое объединённого поля. Строки будут конкатенированы в том порядке, в котором они возвращаются запросом, между ними будет вставлен пробел для разделения. Например, если запрос для объединённого поля возвращает следующие строки:
```ini
( 1, 'red' )
( 1, 'right' )
( 1, 'hand' )
( 2, 'mysql' )
( 2, 'manticore' )
```

то результат индексирования будет эквивалентен добавлению нового текстового поля со значением 'red right hand' для документа 1 и 'mysql sphinx' для документа 2, включая позиции ключевых слов внутри поля в порядке их поступления из запроса. Если строки должны идти в определённом порядке, это должно быть явно определено в запросе.

Объединённые поля индексируются только иначе. Других отличий между объединёнными полями и обычными текстовыми полями нет.

Перед выполнением запроса объединённых полей будут выполнены любые заданные наборы `sql_query_pre_all`, если они существуют. Это позволяет установить нужную кодировку и прочие параметры в контексте объединённых полей.

Когда один запрос недостаточно эффективен или не работает из-за ограничений драйвера базы данных, можно использовать запросы на диапазоне. Они работают аналогично запросам на диапазоне в основном цикле индексирования. Диапазон будет запрошен и получен заранее один раз, затем будет выполнено несколько запросов с разными подстановками `$start` и `$end` для извлечения фактических данных.

При использовании запроса `ranged-main-query` опустите `ranged-query`, и будет автоматически использован тот же запрос, что и в `sql_query_range` (удобная опция в сложных схемах наследования, чтобы не дублировать один и тот же запрос множество раз вручную).

<!-- example payload -->
**Payloads** позволяют создать специальное поле, в котором вместо позиций ключевых слов хранятся так называемые пользовательские полезные данные (user payloads). Payloads — это настраиваемые целочисленные значения, прикреплённые к каждому ключевому слову. Их можно использовать во время поиска для влияния на ранжирование.

Запрос для полезных данных должен возвращать ровно 3 столбца:
- ID документа
- ключевое слово
- и целочисленное значение полезных данных.

ID документов могут повторяться, но должны идти в порядке возрастания. Payloads **должны** быть беззнаковыми целыми числами в 24-битном диапазоне, то есть от 0 до 16777215.

Единственный ранжировщик, учитывающий полезные данные, — `proximity_bm25` (ранжировщик по умолчанию [ranker](../../../Searching/Sorting_and_ranking.md#Available-built-in-rankers)). Для таблиц с полями полезных данных он автоматически переключится на вариант, который сопоставляет ключевые слова в этих полях, вычисляет сумму совпавших полезных данных, умноженную на веса полей, и добавляет эту сумму к итоговому рангу.

Обратите внимание, что поле payload игнорируется для полнотекстовых запросов, содержащих сложные операторы. Оно работает только для простых запросов типа «мешок слов».

<!-- intro -->
Пример конфигурации:
<!-- request Configuration file -->
```ini
source min {
    type = mysql
    sql_host = localhost
    sql_user = test
    sql_pass =
    sql_db = test
    sql_query = select 1, 'Nike bag' f \
    UNION select 2, 'Adidas bag' f \
    UNION select 3, 'Reebok bag' f \
    UNION select 4, 'Nike belt' f

    sql_joined_field = tag from payload-query; select 1 id, 'nike' tag, 10 weight \
    UNION select 4 id, 'nike' tag, 10 weight;
}

index idx {
    path = idx
    source = min
}
```

<!-- request Just SELECT -->
```sql
mysql> select * from idx;
+------+------------+------+
| id   | f          | tag  |
+------+------------+------+
|    1 | Nike bag   | nike |
|    2 | Adidas bag |      |
|    3 | Reebok bag |      |
|    4 | Nike belt  | nike |
+------+------------+------+
4 rows in set (0.00 sec)
```

<!-- request Full-text search -->

Обратите внимание, что при поиске по запросу `nike | adidas` результаты, содержащие «nike», получают больший вес из-за тега «nike» и его веса, заданного в запросе полезных данных.
```sql
mysql> select *, weight() from idx where match('nike|adidas');
+------+------------+------+----------+
| id   | f          | tag  | weight() |
+------+------------+------+----------+
|    1 | Nike bag   | nike |    11539 |
|    4 | Nike belt  | nike |    11539 |
|    2 | Adidas bag |      |     1597 |
+------+------------+------+----------+
3 rows in set (0.01 sec)
```

<!-- request Complex full-text search -->

Обратите внимание, что специальное поле полезных данных игнорируется для полнотекстовых запросов, содержащих сложные операторы. Оно работает только для простых запросов типа «мешок слов».

```sql
mysql> select *, weight() from idx where match('"nike bag"|"adidas bag"');
+------+------------+------+----------+
| id   | f          | tag  | weight() |
+------+------------+------+----------+
|    2 | Adidas bag |      |     2565 |
|    1 | Nike bag   | nike |     2507 |
+------+------------+------+----------+
2 rows in set (0.00 sec)
```

<!-- end -->

### sql_column_buffers

```ini
sql_column_buffers = <colname>=<size>[K|M] [, ...]
```

Размеры буферов для отдельных столбцов. Необязательно, по умолчанию пусто (размеры определяются автоматически). Применяется только к источникам `odbc` и `mssql`.

Драйверы ODBC и MS SQL иногда не могут вернуть максимально возможный реальный размер столбца. Например, столбцы `NVARCHAR(MAX)` всегда сообщают длину 2147483647 байт для `indexer`, хотя фактическая используемая длина скорее всего значительно меньше. Однако при этом буферы приема всё равно должны быть выделены заранее, и их размер нужно определить. Если драйвер вообще не сообщает длину столбца, Manticore выделяет по умолчанию буферы размером 1 КБ для каждого несимвольного столбца и 1 МБ для каждого символьного столбца. Сообщённая драйвером длина столбца также ограничивается максимальным размером 8 МБ, таким образом, если драйвер сообщает (почти) 2 ГБ длины, она будет усечена — вместо этого будет выделен буфер 8 МБ для данного столбца. Эти жёстко заданные пределы можно переопределить с помощью директивы `sql_column_buffers`, чтобы либо сэкономить память на фактически более коротких столбцах, либо преодолеть 8 МБ лимит для действительно более длинных столбцов. Значения директивы должны быть списком, разделённым запятыми, из выбранных имён столбцов и размеров:

Пример:

```ini
sql_query = SELECT id, mytitle, mycontent FROM documents
sql_column_buffers = mytitle=64K, mycontent=10M
```
<!-- proofread -->

