Назад | Перейти на главную страницу

Могу ли я с пользой конвертировать токены spamassassin bayes из utf8 CHAR (5) в BINARY (5)?

Моя установка spamassassin очень старая и была перенесена на две машины и несколько переустановок mysql. Недавно заметил, что при запуске sa-learn в сообщениях я получал в своих журналах множество ошибок вроде следующих:

bayes: _put_token: SQL error: Incorrect string value: '\x8A\x98s\x9A\xC8' for column 'token' at row 1

Я изучил базу данных, провел небольшое исследование и обнаружил этот очень старый отчет об ошибке это выявило проблему: моя схема (очень!) устарела. Колонка bayes_token.token является CHAR(5) collation utf8_general_ci, где 9 лет назад должно было быть BINARY(5).

Я не могу просто преобразовать тип столбца, потому что многие из 5-символьных значений UTF8 длиннее 5 байтов (в таблице ~ 110K строк).

Мой вопрос: есть ли какой-либо метод усечения слишком длинных токенов, который сохранит их действительность в классификаторе Байеса? Или в противном случае я могу удалить только эти строки, чтобы преобразовать остаток в двоичный?

ОБНОВЛЕНИЕ: мне удалось перенести содержимое столбца в добавленный BINARY(5) столбец в таблице (здесь назван token2) следующим образом:

UPDATE bayes_token SET token2 = CONVERT(token USING latin1);

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

Я думаю, что данные можно сохранить, но, возможно, не в чистом SQL. Мне нужно:

  1. Создайте новую копию пустой таблицы из актуальной схемы
  2. сгруппируйте все дубликаты каждого токена и просуммируйте эти строки ' ham_count и spam_count значения и макс. atime стоимость
  3. вставьте эти агрегированные результаты в новую таблицу
  4. замените исходную таблицу на новую

Я считаю, что я воссоздал данные, насколько мог, следующим образом.

  1. Добавить столбец token2 BINARY(5) NOT NULL к столу bayes_token
  2. UPDATE bayes_token SET token2 = CONVERT(token USING latin1);
  3. Создать новую таблицу bayes_token2 используя современную схему
  4. INSERT INTO bayes_token2 SELECT '1' AS id, token2 AS token, SUM(spam_count) AS spam_count, SUM(ham_count) AS ham_count, MAX(atime) AS atime FROM bayes_token GROUP BY token2;
  5. Удалить таблицу bayes_token и заменить на bayes_token2

Подавляющее большинство данных были уникальными и в любом случае не превышали 5 байтов в UTF8, но я думаю, что то, как я это сделал, сохранило и остальную часть правильным образом.

Похоже, текст мог быть в разных кодировках. Вы не можете поместить разные кодировки в один столбец, если сначала не конвертируете, скажем, в utf8mb4. Но если вы не знаете, что такое кодировка, это непрактично.

Если ваша цель - просто передать байты, я бы использовал VARBINARY(..) или BLOB так что вы не наткнетесь на проблемы с кодировкой.

В MySQL foo VARCHAR(5) CHARACTER SET utf8 может занимать до 15 байт. Для utf8mb4 до 20 байт. Так VARBINARY(20), без CHARACTER SET.

Если в вашей таблице в настоящее время foo в этом, объявленном таким образом,

ALTER TABLE t
    MODIFY COLUMN foo BINARY(20);

(Прикрепите NULL или NOT NULL в зависимости от обстоятельств.)