Моя установка 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. Мне нужно:
ham_count
и spam_count
значения и макс. atime
стоимостьЯ считаю, что я воссоздал данные, насколько мог, следующим образом.
token2 BINARY(5) NOT NULL
к столу bayes_token
UPDATE bayes_token SET token2 = CONVERT(token USING latin1);
bayes_token2
используя современную схему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;
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
в зависимости от обстоятельств.)