おうちサーバについてちょっと触れたのは、プロバイダ(wakwak)で受信するメールのSPAM振り分け処理をおうちサーバでやっているからなのですが、最近またこぼれて、というかすり抜けてくるSPAMメールが固定化されてきているので、データベースを作り直しました。
プロバイダ側にもSPAM検出の機能はありますが、注意していないとHAMの誤判定で大事なメールをロスト、とかあると困りますので、一旦全部フェッチする、という戦略です。
まず構成ですが、プロバイダ→おうちサーバのfetchmailでフェッチ→mailfilterでSPAM判定処理→受信箱 という形になっています。おうちサーバで courier-imap4 と courier-pop3 を動かし、受信箱は Maildir 形式です。
mailfilter(maildrop)では、特定のメールアドレスからのメールはSPAMフィルタに通さずにふるい分け、その他のメールは nkfで強制UTF-8化→mecabで分かち書き→bogofilterに通してSPAM判定→reformailでヘッダに細工→maildropでフォルダに振り分け という処理をしています。
判定自体はメールそのものには手を加えないので、すべて UTF-8 にしてから判定処理を行い、その判定結果を元のメールヘッダに追加することにしています。なので、bogofilter に学習させるときにも、すべて UTF-8 にしてから単語登録させています。
bogofilter は NetBSD の package システムでインストールする際に、
PKG_OPTIONS.bogofilter=tokyocabinet
して、検索用のデータベースは tokyocabinet にしています。
そこまではいいとして、じゃあ学習(training)はどうするか、ですが、以下のようなシェルスクリプトを使っています。
#!/usr/pkg/bin/bash
if [ $# -lt 2 ]; then
echo "number of args: $#"
echo "usage: `basename $0` [ham|spam] directories..."
echo "at least two arguments must be specified."
echo "The first argument must be one of [ham|spam],"
echo "and the second must be directory, not file."
exit 1
fi
DIC=/usr/pkg/lib/mecab/dic/jumandic
#DIC=/usr/pkg/lib/mecab/dic/ipadic
#DIC=/usr/pkg/lib/mecab/dic/naist-jdic
shopt -s nocasematch
if [[ $1 == "ham" ]]; then
ARG="-n"
elif [[ $1 == "spam" ]]; then
ARG="-s"
else
echo "usage: `basename $0` [ham|spam] directories..."
echo "the argument must be one of [ham|spam]."
exit 1
fi
if [ ! -d $2 ]; then
echo "usage: `basename $0` [ham|spam] directories..."
echo "at least one directory must be specified."
echo "and it must be directory, not file."
exit 1
fi
shift
for dir in $* ; do
for i in $dir/* ; do
GUESS="`nkf --guess=1 $i`"
case $GUESS in
ISO-2022-JP)
nkf -J -w $i | mecab -d $DIC -Owakati | bogofilter $ARG
;;
Shift_JIS)
nkf -S -w $i | mecab -d $DIC -Owakati | bogofilter $ARG
;;
CP932)
nkf -S -w $i | mecab -d $DIC -Owakati | bogofilter $ARG
;;
EUC-JP)
nkf -E -w $i | mecab -d $DIC -Owakati | bogofilter $ARG
;;
UTF-8)
mecab -d $DIC -Owakati $i | bogofilter $ARG
;;
*)
bogofilter $ARG -B $i
;;
esac
done
done
まあ無駄な処理、といか全部
nkf -w
でいいじゃん、という話もありますが、一応日本語とそれ以外を分けたほうがいいかな、というのと、少しでも処理を軽くしたほうがいいかな、というのでこうしています。
時々こういう処理をしないと、誤判定のメールを再学習させてもあまり改善されず誤判定が繰り返されることがあるので、定常的に同じようなメールを誤判定することが続いたらデータベースを削除して作り直すことにしています。
ちなみに上記の学習をさせるために、SPAMメールもHAM(SPAMじゃない)メールもディスクの肥やしではないけれど保存してあります。ただ、SPAMメールで使われる単語などの傾向は年代によっても変わるようなので、もしも誤判定が増えたり同じメールを何度学習させても間違えるときにはデータベースの再構築が有効だと思います。
うちの場合にはSPAMが平均して月に1200通くらい配信されてきますが、bogofilterの学習には単語数で2000語以上、メール数で500以上は食わせたほうがよいようなので、最近3ヶ月程度を食わせれば十分です。