# Структура таблицы в режиме реального времени

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

Один из способов решения этой проблемы — использовать несколько таблиц вместо одной цельной. Например, вы можете обработать источники прошлых лет и сохранить таблицу. Затем взять только источники текущего года и поместить их в отдельную таблицу, перестраивая её столько раз, сколько необходимо. После этого обе таблицы можно разместить как части распределённой таблицы и использовать её для запросов. Суть в том, что при каждой перестройке вы обрабатываете данные максимум за последние 12 месяцев, а таблица со старыми данными остаётся без изменений и не требует перестройки. Можно пойти дальше и разделить таблицу за последние 12 месяцев на месячные, недельные или дневные таблицы и так далее.

Этот подход работает, но вам нужно самостоятельно поддерживать распределённую таблицу. То есть добавлять новые части, удалять старые и следить, чтобы общее количество частичных таблиц не было слишком большим (при слишком большом числе таблиц поиск может замедлиться, а ОС обычно ограничивает число одновременно открытых файлов). Для решения этой проблемы можно вручную объединять несколько таблиц, запуская [indexer --merge](../Data_creation_and_modification/Adding_data_from_external_storages/Adding_data_to_tables/Merging_tables.md). Однако это решает только проблему большого числа таблиц, усложняя обслуживание. И даже при переиндексации «каждый час» вы скорее всего столкнетесь с заметной задержкой между появлением новых данных в источниках и перестроением таблицы, которое делает эти данные доступными для поиска.

Таблица в реальном времени разработана для решения этой задачи. Она состоит из двух частей:

1. Специальной таблицы в RAM (называемой RAM-чанком), содержащей части данных, поступающих прямо сейчас.
2. Набора обычных таблиц на диске, называемых дисковыми чанками, которые были построены ранее.

Это очень похоже на стандартную [распределённую таблицу](../Creating_a_table/Creating_a_distributed_table/Creating_a_distributed_table.md), состоящую из нескольких локальных таблиц.

Вам не нужно создавать такую таблицу с помощью `indexer`, который читает «рецепт» из конфигурации и источники таблиц. Вместо этого таблица в реальном времени предоставляет возможность «вставлять» новые документы и «замещать» существующие. При выполнении команды «insert» вы отправляете новые документы на сервер. Он строит маленькую таблицу из добавленных документов и сразу же выводит её в онлайн. Так, сразу после завершения команды «insert» вы можете выполнять поиск во всех частях таблицы, включая недавно добавленные документы.

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

**Во-первых, так как проиндексированные данные хранятся в RAM — что будет при аварийном отключении питания?** Потеряю ли я тогда таблицу? Перед завершением сервер сохраняет новые данные в специальный «binlog». Это один или несколько файлов, расположенных на постоянном носителе, который постепенно растёт по мере добавления новых изменений. Вы можете настроить поведение — как часто новые запросы (или транзакции) сохраняются в binlog и как часто выполняется команда «sync» по файлу binlog, чтобы заставить ОС действительно записать данные на надёжное хранилище. Самый параноидальный подход — сбрасывать и синхронизировать после каждой транзакции. Это самый медленный, но и самый безопасный метод. Самый быстрый способ — полностью отключить binlog. Это самый шустрый метод, но вы рискуете потерять проиндексированные данные. Также доступны промежуточные варианты, например, сброс/синхронизация каждую секунду.

Binlog предназначен специально для последовательной записи вновь поступающих транзакций; это не таблица и по нему нельзя выполнять поиск. Это всего лишь страховка, гарантирующая, что сервер не потеряет ваши данные. Если случится внезапный сбой и всё упадёт из-за программной или аппаратной проблемы, сервер загрузит самый свежий доступный дамп RAM-чанка, а затем воспроизведёт binlog, повторяя сохранённые транзакции. В итоге он достигнет того же состояния, в котором был в момент последнего изменения.

**Во-вторых, что насчёт лимитов?** Что если я хочу обработать, скажем, 10ТБ данных, но они просто не помещаются в RAM! Объём RAM для таблицы в реальном времени ограничен и может быть настроен. Когда индексируется определённый объём данных, сервер управляет RAM-частью таблицы, объединяя маленькие транзакции и сохраняя их количество и общий размер небольшими. Иногда этот процесс может вызывать задержки при вставке. Когда объединение уже не помогает, и новые вставки достигают [лимита RAM](../Creating_a_table/Local_tables/Plain_and_real-time_table_settings.md#rt_mem_limit), сервер преобразует таблицу на основе RAM в обычную таблицу на диске (называемую дисковым чанком). Эта таблица добавляется к коллекции таблиц во второй части RT-таблицы и становится доступной онлайн. RAM очищается, и пространство освобождается.

Когда данные из RAM безопасно сохранены на диск, что происходит:

* когда сервер сохраняет собранные данные как дисковую таблицу
* или когда он сбрасывает RAM-часть во время корректного завершения работы или с помощью [ручного сброса](../Securing_and_compacting_a_table/Flushing_RAM_chunk_to_disk.md#FLUSH-TABLE)

binlog для этой таблицы больше не нужен. Поэтому он удаляется. Если все таблицы сохранены, binlog удаляется.

**Третье, как насчёт коллекции дисков?** Если наличие многих частей диска замедляет поиск, то в чём разница, если я создаю их вручную в виде распределённой таблицы, или они создаются как части диска (или «чанки») таблицей RT? В обоих случаях вы можете объединить несколько таблиц в одну. Например, можно объединить почасовые таблицы за вчерашний день и сохранить вместо них одну «дневную» таблицу за вчера. При ручном обслуживании вам нужно самому продумывать схему и команды. С таблицей RT сервер предоставляет команду [OPTIMIZE](../Securing_and_compacting_a_table/Compacting_a_table.md#OPTIMIZE-TABLE), которая выполняет то же самое, но избавляет вас от ненужных внутренних деталей.

**Четвёртое, если мой «документ» представляет собой «мини-таблицу» и он мне больше не нужен, я могу просто выбросить его. Но если он «оптимизирован», то есть смешан вместе с кучей других документов, как я могу отменить или удалить его?** Да, индексированные документы «смешаны» вместе, и нет простого способа удалить один, не перестраивая всю таблицу. И если для простых таблиц перестройка или слияние — обычный способ обслуживания, для таблицы реального времени это сохраняет лишь простоту манипуляций, но не «реальное время». Чтобы решить эту проблему, Manticore использует трюк: когда вы удаляете документ, идентифицируемый по ID документа, сервер просто отслеживает этот номер. Вместе с другими удалёнными документами их ID сохраняются в так называемом [kill-list](../Data_creation_and_modification/Adding_data_from_external_storages/Adding_data_to_tables/Killlist_in_plain_tables.md#Table-kill-list). При поиске по таблице сервер сначала извлекает все подходящие документы, а потом исключает документы, найденные в kill-list (это самая базовая схема; на самом деле внутри всё сложнее). Суть в том, что ради «немедленного» удаления документы фактически не удаляются, а лишь помечаются как «удалённые». Они всё ещё занимают место в разных структурах таблицы, по сути являясь мусором. Статистика слов, влияющая на ранжирование, тоже не затрагивается, что означает, что поиск работает именно так, как заявлено: мы ищем среди всех документов, а затем просто скрываем помеченные как удалённые из итогового результата. Когда документ [заменяется](../Data_creation_and_modification/Updating_documents/REPLACE.md), это означает, что он удаляется в старых частях таблицы и вставляется снова в самую свежую часть. Все последствия «скрытия через killlist» также применимы в этом случае.

Когда происходит перестройка какой-то части таблицы, например, когда некоторые транзакции (сегменты) RAM-чанка сливаются, или когда RAM-чанк преобразуется в дисковый чанк, или когда два дисковых чанка объединяются вместе, сервер выполняет полную итерацию по затронутым частям и физически исключает удалённые документы из всех них. То есть, если они были в списках документов для некоторых слов — их удаляют. Если это было уникальное слово — оно удаляется полностью.

В итоге: удаление работает в два этапа:
1. Сначала мы помечаем документы как «удалённые» в реальном времени и исключаем их из результатов поиска.
2. Во время какой-то операции с чанком таблицы RT мы окончательно физически удаляем удалённые документы.

**Пятое, если таблица RT содержит простые дисковые таблицы в своей коллекции, могу ли я просто добавить в неё готовую старую дисковую таблицу?** Нет. Это невозможно, чтобы избежать ненужной сложности и предотвратить случайное повреждение. Однако, если ваша таблица RT только что создана и не содержит данных, то вы можете [ПРИСОЕДИНИТЬ ТАБЛИЦУ](../Data_creation_and_modification/Adding_data_from_external_storages/Adding_data_to_tables/Attaching_one_table_to_another.md) вашей дисковой таблице к ней. Ваша старая таблица будет перемещена внутрь таблицы RT и станет её частью.

В итоге о структуре таблицы RT: это умело организованная коллекция простых дисковых таблиц с быстрой таблицей в памяти, предназначенная для вставок в реальном времени и полу-реального времени удаления документов. Таблица RT имеет общую схему, общие настройки и может быть легко обслуживаемой без глубокого погружения в детали.
<!-- proofread -->

