编程 Rspamd 不出 BAYES_SPAM:min_learns 是 ham/spam 各自 200,不是总数

2026-11-06 00:04:39

Rspamd 不出 BAYES_SPAM:从一条 skip 日志查到 min_learns 与配置位置

给 Rspamd 接上 Redis 后端、也训练了几百封邮件,扫描结果里却始终没有 BAYES_SPAM / BAYES_HAM 符号。下面按排查顺序记录。

现象与日志原文

日志里能看到这类行:

2018-12-27 13:16:35 #21975(controller); csession; bayes_classify: skip classification as ham class has not enough learns: 23, 200 required

意思很直接:ham 这个类只有 23 次学习记录,需要 200 次。分类器不是没工作,而是被门槛挡住了。

min_learns 是两个类各自计数

默认统计配置 conf/statistic.conf:

classifier "bayes" {
tokenizer {
name = "osb";
}
cache { }
new_schema = true;
store_tokens = false;
signatures = false;
#per_user = true;
min_tokens = 11;
backend = "redis";
min_learns = 200;
statfile {
symbol = "BAYES_HAM";
spam = false;
}
statfile {
symbol = "BAYES_SPAM";
spam = true;
}
learn_condition = "return require('lua_bayes_learn').can_learn";
}
  • min_learns = 200 是每个类的门槛:ham ≥ 200 且 spam ≥ 200 才开始分类。总共要 400 封,不是 200 封。只训 spam 不训 ham,同样不出符号。
  • min_tokens = 11:邮件分词后 token 少于 11 个的不参与统计处理,短邮件训不进去。
  • 从 2.0 起官方推荐 backend = "redis",原 sqlite3 方案只留在老文档里。

配置该写在哪

  • 改默认 bayes 分类器:local.d/classifier-bayes.conf(或 override.d/)。
  • 改全部分类器结构:local.d/statistic.conf。
  • 官方在 statistic.conf 注释里明确警告:绝不要同时使用 local.d/statistic.conf 和 local.d/classifier-bayes.conf。两者都 include 进同一个 classifier 块,键来源混乱,排查时极难判断哪个值生效。
  • 确认最终生效值:
rspamadm configdump classifier.bayes.min_learns

也可以 rspamc stat 看现状。很多「我明明配了 10」的案例,configdump 出来仍是 200,说明文件放错位置或没被 include。

Redis 后端参数与 servers 用 IP 的坑

  • tokenizer:目前只支持 osb,别改。
  • backend = "redis"
  • servers:IP:port。文档特别提醒——如果 /etc/hosts 里 localhost 同时映射 IPv4 和 IPv6,写 localhost 可能找不到 Redis,用回环 IP。
  • write_servers(可选):单独指定用于学习的实例;默认读写服务器做主从轮转,读服务器每次随机选。
  • password / database(可选,但官方建议用独立 Redis 实例,而不是共用 db 编号)。
  • per_user:按用户分开统计。
  • per_languages 在 Redis 后端不支持,语言只是混在一起存。

autolearn 的三种写法

autolearn 解决的是「什么时候学」,不是「学多少」。

  • autolearn = true:action 是 reject 时学 spam,分数为负时学 ham。
  • autolearn = [-5, 5]:分数 5 学 spam。
  • autolearn = "return function(task) ... end":自定义,返回 'ham' / 'spam' / nil。

关键限制:autolearn 在包括统计在内的所有规则处理完之后才执行,且仅当同一符号还没被插入时才生效。也就是说,如果本次检查已经出了 BAYES_SPAM,就不会再把这封邮件学成 spam。所以「开了 autolearn 就自动补到 200」只在别的规则先给出高分时才成立。

另外,learn_condition 是反向闸门(阻止学习),默认指向 lua_bayes_learn.can_learn;新版默认配置里的 autolearn 块还带 spam_threshold / junk_threshold / ham_threshold / check_balance / min_balance(默认 0.9)与 probability_check(spam_min 0.9、ham_max 0.1)。

手动训练与计数核对

训练:

rspamc learn_spam /path/to/mail.eml
rspamc learn_ham /path/to/mail.eml

计数,rspamc stat 输出类似:

Statfile: BAYES_SPAM type: redis; ... learned: 109; users: 1; languages: 0
Statfile: BAYES_HAM type: redis; ... learned: 61; users: 1; languages: 0

也可以直接看 Redis:HGETALL RS 里有 learns_spam / learns_ham / version。

训练语料要 ham 和 spam 数量接近。官方建议手动训一个大于 min_learns 的语料,而不是靠生产流量自然攒;只训一类会把概率推偏。

维护

  • 官方建议启用 bayes_expiry 模块定期清理统计库,否则 token 无限增长。
  • 3.12.1 新增 /bayes/classifiers HTTP 端点,可查分类器列表;3.14 起 autolearn 条件支持跳过本地/已认证邮件(Bayes: Allow skipping local/authenticated mail in autolearn condition)。

项目信息

  • 仓库:
  • 默认统计配置:
  • 统计 / Bayes 文档:

推荐文章

程序员茄子在线接单