При использовании простых таблиц возникает проблема, связанная с необходимостью иметь данные в таблице как можно более свежими.
В этом случае используются одна или несколько вторичных (также известных как дельта) таблиц для захвата измененных данных между временем создания основной таблицы и текущим временем. Измененные данные могут включать новые, обновленные или удаленные документы. Поиск становится поиском по основной таблице и дельта-таблице. Это работает бесшовно, когда вы просто добавляете новые документы в дельта-таблицу, но когда дело доходит до обновленных или удаленных документов, остается следующая проблема.
Если документ присутствует как в основной, так и в дельта-таблице, это может вызвать проблемы во время поиска, так как движок увидит две версии документа и не будет знать, как выбрать правильную. Таким образом, дельта-таблица должна каким-то образом сообщить поиску, что в основной таблице есть удаленные документы, которые следует игнорировать. Для этого и нужны kill-листы.
Таблица может поддерживать список идентификаторов документов, который можно использовать для подавления записей в других таблицах. Эта функция доступна для простых таблиц, использующих источники из базы данных, или простых таблиц, использующих XML-источники. В случае источников из базы данных, источник должен предоставить дополнительный запрос, определенный с помощью sql_query_killlist. Он будет хранить в таблице список документов, который сервер может использовать для удаления документов из других простых таблиц.
Ожидается, что этот запрос вернет ряд строк с одним столбцом, каждая из которых содержит только идентификатор документа.
Во многих случаях запрос представляет собой объединение запроса, который извлекает список обновленных документов, и списка удаленных документов, например:
sql_query_killlist = \
SELECT id FROM documents WHERE updated_ts>=@last_reindex UNION \
SELECT id FROM documents_deleted WHERE deleted_ts>=@last_reindex
Простая таблица может содержать директиву killlist_target, которая сообщит серверу, что она может предоставить список идентификаторов документов, которые следует удалить из определенных существующих таблиц. Таблица может использовать либо свои собственные идентификаторы документов в качестве источника для этого списка, либо предоставить отдельный список.
Устанавливает таблицу (таблицы), к которой будет применен kill-лист. Необязательный параметр, значение по умолчанию пустое.
Когда вы используете простые таблицы, вам часто нужно поддерживать не одну таблицу, а набор таблиц, чтобы иметь возможность быстрее добавлять/обновлять/удалять новые документы (читайте о дельта-обновлениях таблиц). Чтобы подавить совпадения в предыдущей (основной) таблице, которые были обновлены или удалены в следующей (дельта) таблице, вам необходимо:
- Создать kill-лист в дельта-таблице с помощью sql_query_killlist
- Указать основную таблицу как
killlist_targetв настройках дельта-таблицы:
- CONFIG
table products {
killlist_target = main:kl
path = products
source = src_base
}Когда killlist_target указан, kill-лист применяется ко всем перечисленным в нем таблицам при запуске searchd. Если любая из таблиц из killlist_target подвергается ротации, kill-лист повторно применяется к этим таблицам. Когда kill-лист применяется, таблицы, на которые он повлиял, сохраняют эти изменения на диск.
killlist_target имеет 3 режима работы:
killlist_target = main:kl. Идентификаторы документов из kill-листа дельта-таблицы подавляются в основной таблице (см.sql_query_killlist).killlist_target = main:id. Все идентификаторы документов из дельта-таблицы подавляются в основной таблице. Kill-лист игнорируется.killlist_target = main. И идентификаторы документов из дельта-таблицы, и ее kill-лист подавляются в основной таблице.
Можно указать несколько целей, разделенных запятыми, например:
killlist_target = table_one:kl,table_two:kl
Вы можете изменить настройки killlist_target для таблицы без ее перестроения, используя ALTER.
Однако, поскольку 'старая' основная таблица уже записала изменения на диск, документы, которые были в ней удалены, останутся удаленными, даже если она больше не находится в killlist_target дельта-таблицы.
- SQL
- HTTP
ALTER TABLE delta KILLLIST_TARGET='new_main_table:kl'POST /cli -d "
ALTER TABLE delta KILLLIST_TARGET='new_main_table:kl'"Обычную таблицу можно преобразовать в реального времени (RT) или добавить к существующей RT-таблице.
Первый случай полезен, когда необходимо полностью перегенерировать RT-таблицу, что может потребоваться, например, если нужно обновить настройки токенизации. В этой ситуации подготовка обычной таблицы и её преобразование в RT-таблицу может быть проще, чем подготовка пакетного задания для выполнения INSERT-запросов для добавления всех данных в RT-таблицу.
Во втором случае обычно требуется добавить большой объём новых данных в RT-таблицу, и снова создание обычной таблицы с этими данными проще, чем заполнение существующей RT-таблицы.
Вы также можете присоединить существующую RT-таблицу к другой.
Оператор ATTACH позволяет преобразовать обычную таблицу для присоединения к существующей RT-таблице. Он также позволяет присоединить содержимое одной RT-таблицы к другой RT-таблице.
ATTACH TABLE plain_or_rt_table TO TABLE rt_table [WITH TRUNCATE]
После успешного выполнения ATTACH данные, изначально хранившиеся в исходной обычной таблице, становятся частью целевой RT-таблицы, а исходная обычная таблица становится недоступной (до следующей пересборки). Если исходная таблица является RT-таблицей, её содержимое перемещается в целевую RT-таблицу, а исходная RT-таблица остаётся пустой. ATTACH не приводит к каким-либо изменениям данных таблицы. По сути, он просто переименовывает файлы (превращая исходную таблицу в новый дисковый чанк целевой RT-таблицы) и обновляет метаданные. Таким образом, это, как правило, быстрая операция, которая может (часто) завершаться менее чем за секунду.
Обратите внимание, что когда таблица присоединяется к пустой RT-таблице, поля, атрибуты и настройки обработки текста (токенизатор, словоформы и т.д.) из исходной таблицы копируются и вступают в силу. Соответствующие части определения RT-таблицы из файла конфигурации будут проигнорированы.
При использовании опции TRUNCATE RT-таблица очищается перед присоединением исходной обычной таблицы. Это позволяет сделать операцию атомарной или гарантирует, что присоединяемая исходная обычная таблица будет единственными данными в целевой RT-таблице.
ATTACH TABLE имеет ряд ограничений. Наиболее важно, что в настоящее время требуется, чтобы целевая RT-таблица была либо пустой, либо имела те же настройки, что и исходная таблица. В случае, если исходная таблица присоединяется к непустой RT-таблице, данные RT-таблицы, собранные на данный момент, сохраняются как обычный дисковый чанк, а присоединяемая таблица становится новейшим дисковым чанком, при этом документы с одинаковыми ID помечаются как удалённые. Полный список ограничений следующий:
- Целевая RT-таблица должна быть либо пустой, либо иметь те же настройки, что и исходная таблица.
- В исходной таблице необходимо установить phrase_boundary_step равным 0 и stopword_step равным 1.
- Example
Перед ATTACH RT-таблица пуста и имеет 3 поля:
mysql> DESC rt;
Empty set (0.00 sec)
mysql> SELECT * FROM rt;
+-----------+---------+
| Field | Type |
+-----------+---------+
| id | integer |
| testfield | field |
| testattr | uint |
+-----------+---------+
3 rows in set (0.00 sec)Обычная таблица не пуста:
mysql> SELECT * FROM plain WHERE MATCH('test');
+------+--------+----------+------------+
| id | weight | group_id | date_added |
+------+--------+----------+------------+
| 1 | 1304 | 1 | 1313643256 |
| 2 | 1304 | 1 | 1313643256 |
| 3 | 1304 | 1 | 1313643256 |
| 4 | 1304 | 1 | 1313643256 |
+------+--------+----------+------------+
4 rows in set (0.00 sec)Присоединение обычной таблицы к RT-таблице:
mysql> ATTACH TABLE plain TO TABLE rt;
Query OK, 0 rows affected (0.00 sec)Теперь RT-таблица имеет 5 полей:
mysql> DESC rt;
+------------+-----------+
| Field | Type |
+------------+-----------+
| id | integer |
| title | field |
| content | field |
| group_id | uint |
| date_added | timestamp |
+------------+-----------+
5 rows in set (0.00 sec)И она не пуста:
mysql> SELECT * FROM rt WHERE MATCH('test');
+------+--------+----------+------------+
| id | weight | group_id | date_added |
+------+--------+----------+------------+
| 1 | 1304 | 1 | 1313643256 |
| 2 | 1304 | 1 | 1313643256 |
| 3 | 1304 | 1 | 1313643256 |
| 4 | 1304 | 1 | 1313643256 |
+------+--------+----------+------------+
4 rows in set (0.00 sec)После ATTACH обычная таблица удаляется и больше не доступна для поиска:
mysql> SELECT * FROM plain WHERE MATCH('test');
ERROR 1064 (42000): no enabled local indexes to searchЕсли вы решите перейти с Plain режима на RT режим или в некоторых других случаях, таблицы реального времени и percolate, созданные в Plain режиме, могут быть импортированы в Manticore, работающий в RT режиме, с помощью оператора IMPORT TABLE. Общий синтаксис следующий:
IMPORT TABLE table_name FROM 'path'
где параметр 'path' должен быть задан следующим образом: /your_backup_folder/your_backup_name/data/your_table_name/your_table_name
- bash
mysql -P9306 -h0 -e 'create table t(f text)'
mysql -P9306 -h0 -e "backup table t to /tmp/"
mysql -P9306 -h0 -e "drop table t"
BACKUP_NAME=$(ls /tmp | grep 'backup-' | tail -n 1)
mysql -P9306 -h0 -e "import table t from '/tmp/$BACKUP_NAME/data/t/t'
mysql -P9306 -h0 -e "show tables"Выполнение этой команды копирует все файлы таблицы указанной таблицы в data_dir. Все внешние файлы таблицы, такие как wordforms, exceptions и stopwords, также копируются в тот же data_dir.
IMPORT TABLE имеет следующие ограничения:
- пути к внешним файлам, которые изначально были указаны в файле конфигурации, должны быть абсолютными
- поддерживаются только таблицы реального времени и percolate
- plain таблицы необходимо предварительно (в plain режиме) конвертировать в таблицы реального времени с помощью ATTACH TABLE
Обратите внимание, что команда IMPORT TABLE не поддерживает таблицы, созданные в версиях старше 5.0.0.
Если вышеописанный метод миграции plain таблицы в RT таблицу невозможен, вы можете использовать indexer --print-rt для выгрузки данных из plain таблицы напрямую без необходимости конвертировать её в таблицу типа RT, а затем импортировать дамп в RT таблицу прямо из командной строки.
Однако этот метод имеет несколько ограничений:
- Поддерживаются только источники на основе SQL
- MVAs не поддерживаются
- bash
/usr/bin/indexer --rotate --config /etc/manticoresearch/manticore.conf --print-rt my_rt_index my_plain_index > /tmp/dump_regular.sql
mysql -P $9306 -h0 -e "truncate table my_rt_index"
mysql -P 9306 -h0 < /tmp/dump_regular.sql
rm /tmp/dump_regular.sqlВращение таблицы — это процедура, при которой сервер searchd ищет новые версии определённых таблиц в конфигурации. Вращение поддерживается только в режиме Plain.
Есть два случая:
- для plain-таблиц, которые уже загружены
- таблиц, добавленных в конфигурацию, но ещё не загруженных
В первом случае индексатор не может разместить новую версию таблицы онлайн, поскольку работающая копия заблокирована и загружена searchd. В этом случае indexer нужно вызвать с параметром --rotate. Если используется rotate, indexer создаёт новые файлы таблиц с .new. в названии и посылает сигнал HUP searchd, информируя о новой версии. searchd выполнит проверку и заменит старую версию таблицы на новую. В некоторых случаях может потребоваться создать новую версию таблицы, не выполняя вращение сразу. Например, может понадобиться сначала проверить состояние новых версий таблиц. В этом случае indexer может принимать параметр --nohup, который запрещает посылать сигнал HUP серверу.
Новые таблицы могут быть загружены с помощью вращения; однако обычная обработка сигнала HUP заключается в проверке новых таблиц только если конфигурация изменилась после запуска сервера. Если таблица уже была определена в конфигурации, таблицу следует сначала создать запуском indexer без вращения и выполнить оператор RELOAD TABLES вместо этого.
Также существуют два специализированных оператора, которые могут использоваться для вращения таблиц:
RELOAD TABLE tbl [ FROM '/path/to/table_files' [ OPTION switchover=1 ] ];
Команда RELOAD TABLE позволяет выполнять вращение таблицы через SQL.
Эта команда работает в трёх режимах. В первом режиме, без указания пути, сервер Manticore проверяет наличие новых файлов таблиц в директории, указанной в параметре path. Новые файлы таблиц должны называться tbl.new.sp?.
Если вы указываете путь, сервер ищет файлы таблиц в этой директории, перемещает их в директорию таблицы, указанную в path, переименовывает из tbl.sp? в tbl.new.sp? и выполняет вращение.
Третий режим, активируемый опцией OPTION switchover=1, переключает индекс на новый путь. Здесь демон пытается загрузить таблицу напрямую из нового пути без перемещения файлов. Если загрузка успешна, новый индекс заменяет старый.
Также демон записывает уникальный файл-ссылку (tbl.link) в директории, указанной в path, поддерживая постоянное перенаправление.
Если вы возвращаете перенаправленный индекс к пути, указанному в конфигурации, демон обнаружит это и удалит файл ссылки.
После перенаправления демон получает таблицу из вновь связанного пути. При вращении он ищет новые версии таблицы по новому перенаправленному пути. Учтите, что демон проверяет конфигурацию на общие ошибки, например, дублирование путей для разных таблиц. Однако он не выявляет ситуации, когда несколько таблиц указывают на один и тот же путь через перенаправление. В нормальной работе таблицы блокируются файлом .spl, но отключение блокировки может вызвать проблемы. Если возникает ошибка (например, путь недоступен по любой причине), необходимо вручную исправить (или просто удалить) файл ссылки.
indextool следует по файлу ссылки, но другие утилиты (indexer, index_converter и др.) не распознают файл ссылки и используют путь, определённый в конфигурационном файле, игнорируя перенаправление. Таким образом, вы можете просмотреть индекс с помощью indextool, и он прочитает с нового местоположения. Однако более сложные операции, такие как слияние, не учтут файл ссылки.
mysql> RELOAD TABLE plain_table;
mysql> RELOAD TABLE plain_table FROM '/home/mighty/new_table_files';
mysql> RELOAD TABLE plain_table FROM '/home/mighty/new/place/for/table/table_files' OPTION switchover=1;
RELOAD TABLES;
Эта команда работает аналогично системному сигналу HUP, вызывая вращение таблиц. Тем не менее, она не точно повторяет обычный сигнал HUP (который может быть вызван командой kill -HUP или indexer --rotate). Эта команда активно ищет таблицы, требующие вращения, и способна перечитать конфигурацию. Например, если вы запускаете Manticore в режиме plain с конфигурационным файлом, указывающим на несуществующую plain-таблицу, то если вы потом попытаетесь сделать indexer --rotate для этой таблицы, сервер не распознает новую таблицу, пока вы не выполните RELOAD TABLES или не перезапустите сервер.
В зависимости от значения параметра seamless_rotate, новые запросы могут временно приостанавливаться, и клиенты будут получать временные ошибки.
mysql> RELOAD TABLES;
Query OK, 0 rows affected (0.01 sec)
Вращение предполагает, что старая версия таблицы отбрасывается, а новая версия загружается и заменяет существующую. В процессе замены сервер также должен обслуживать входящие запросы к обновляемой таблице. Чтобы избежать задержек в выполнении запросов, сервер по умолчанию реализует бесшовное вращение таблицы, как описано ниже.
Таблицы могут содержать данные, которые необходимо предварительно кэшировать в ОЗУ. В настоящее время файлы .spa, .spb, .spi и .spm полностью предварительно кешируются (они содержат данные атрибутов, данные блоб-атрибутов, таблицу ключевых слов и карту удалённых строк соответственно). Без бесшовного вращения вращение таблицы старается использовать минимально возможный объём ОЗУ и работает следующим образом:
- Новые запросы временно отклоняются (с кодом ошибки "retry").
searchdждёт завершения всех текущих запросов.- Старая таблица освобождается, и её файлы переименовываются.
- Новые файлы таблицы переименовываются и выделяется необходимый объём ОЗУ.
- Новые данные атрибутов таблицы и словари предварительно загружаются в ОЗУ.
searchdвозобновляет обслуживание запросов из новой таблицы.
Однако если данных атрибутов или словарей много, шаг предварительной загрузки может занять заметное время — до нескольких минут при загрузке файлов объёмом 1–5+ ГБ.
При включённом бесшовном вращении, вращение работает следующим образом:
- Выделяется новая таблица для хранения в ОЗУ.
- Асинхронно загружаются в ОЗУ новые данные атрибутов и словаря таблицы.
- При успешном завершении старая таблица освобождается, а файлы обеих таблиц переименовываются.
- При неудаче новая таблица освобождается.
- В любой момент запросы обслуживаются либо из копии старой, либо из копии новой таблицы.
Бесшовное вращение требует большего пикового использования памяти во время вращения (потому что обе копии данных .spa/.spb/.spi/.spm — старые и новые — должны находиться в ОЗУ при предварительной загрузке новой копии). Однако среднее использование остаётся тем же.
Пример:
seamless_rotate = 1