我可以有效地將 spamassassin 貝氏令牌從 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)
排序規則 utf8_general_ci,截至 9 年前,應該是BINARY(5)
.我不能簡單地轉換列類型,因為許多 UTF8 5-char 值長於 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
絕大多數數據都是唯一的,無論如何在 UTF8 中不超過 5 個字節,但我認為我這樣做的方式也以正確的方式保存了其餘部分。
聽起來文本可能是不同的編碼。除非您首先轉換為 utf8mb4,否則您不能將不同的編碼放入單個列中。但是,如果你不知道編碼是什麼,那是不切實際的。
如果您的目標只是傳遞字節,我會使用
VARBINARY(..)
orBLOB
這樣您就不會因字元集問題而絆倒。在 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
酌情。)