« 目次

Movable Type オブジェクト・リファレンス

MT::JunkFilter

概要

use MT::JunkFilter;
MT::JunkFilter->filter($comment);

はじめに

Movable Type 3.2では、組み込み型の迷惑コメント/トラックバック検知フレームワークを備えており、プラグイン開発者は、プラグイン同士で矛盾を起こすことなく、このフレームワークを拡張することができます。このフレームワークではある種のスコアリング・モデルを使っています。各プラグインでは、受信したコメント/トラックバックに数値スコアをつけるかつけないかを選ぶことができます。これらのスコアを集計したものがスコア集計値で、コメント/トラックバックに対する処理(つまり、公開するか、それとも迷惑コメント/トラックバックとするか)は、このスコア集計値に応じて決まります。

スコア集計値は、評価を行った全プラグインの出したスコアの平均(算術平均)です。ただし、プラグイン側でスコアを出さないことも可能で、その場合にはそのプラグインは平均値には算入されません。こうして求めた値をスコア集計値と呼んでいます。スコア集計値が判断基準値(デフォルトでは0)よりも大きい場合には、そのコメント(あるいはトラックバック)は迷惑コメント/トラックバックとみなされます。

この仕組みは、別の見方をすると、「天秤ばかり」を使ってコメントの重さを測っているようなものだと考えることもできます。この天秤は最初は水平ですが、各プラグインはコメントの内容を見て、天秤上の任意の場所に単位重量分の分銅を置く(あるいはどこにも置かない)ことができます。もし、すべてのプラグインが分銅を天秤の左側に置いたとすると、天秤は左に傾きます。このとき、そのコメントは迷惑と判断されます。すべてのプラグインが分銅を天秤の右側に置けば、もちろん天秤も右側に傾き、そのコメントは迷惑ではないと見なされます。右側にも左側にも分銅が置かれた場合、それぞれの側のどのあたりに、いくつ分銅が置かれたかによって結果は異なります。Movable Typeの算出する平均値は、すべての分銅の重心のようなものと言うことができます。

直感的にわかるように、絶対値の大きなプラスのスコアがあれば、絶対値の小さなマイナスのスコアがあっても相殺されてしまいます。あるいは正負いずれかのスコアを出すプラグインが多ければ、反対側のスコアは打ち消されます。

スコアリングの方針

プラグインの設計時には、適切なスコアを返すよう慎重に設計することが重要です。その際は、次の点に注意してください。

判断基準値はデフォルトでは0ですが、自分で調整することもできます。これは、天秤ばかりのたとえで言えば、風袋の重量を考慮したり天秤自体の支点をずらしておいたりするようなものだと言えます。多数の適正なコメントが迷惑コメントのフォルダーに入ってしまったり、あるいは逆に多数の迷惑コメントが公開されてしまったりするといった場合、ユーザーが判断基準値を変更することで調節できます。しかし、だからといってプラグイン側の補正が不十分でもよいというわけではありません。

このことから考えて、場合によってはプラグインが常にスコアを返す必要はない、ということは重要な意味を持ちます。プラグイン側でそのコメントが迷惑コメントかそうでないかを判断するに足る情報が得られないという状況はいくらでもあります。このような場合、0を返すというのは適切ではありません。つまり、0は0としてカウントされてしまうからです。デフォルトの判断基準値は0なので、0を返すことが最終的な判断に影響することはありませんが、ユーザーが判断基準値を0より上に設定している場合、0は迷惑でないという判断と見なされますし、またユーザーが判断基準値を0よりも下に設定している場合、0を返すということは迷惑と判断したことになります。

天秤ばかりの例で言えば、この天秤は-10から10までの完全にスムーズな連続体と言えます。つまり迷惑なものと迷惑でないものを切り分ける特定の値は存在しません。プラグイン中のセンサー部分がコメントについて判断できない場合は、スコアを返さずに他のプラグインに判断を任せるようにしてください。

サンプル・コード

APIの概略をつかむため、サンプル・コードを見てみましょう。

eの文字は有害だということで、コメント/トラックバック中のeを検知して、eを多数含んでいる場合には迷惑スコアを高くするようなプラグインを作りたいとします。

package SpamTest;

use strict;

use MT::JunkFilter qw(ABSTAIN);
use base 'MT::Plugin';

sub name { "Sample Spam Detector"; }
sub description { "Counts the number of E's, an indicator of junk."; }

sub score {
    my ($obj) = @_;
    my @es = $obj->all_text =~ m/(e)/gi;
    my $count = scalar @es;
    my $score = (2 ** $count - 1);

    return ABSTAIN if ($score <= 0);

    return (-$score, "Contained $count 'e' characters");
}

MT->add_plugin(__PACKAGE__->new);
MT->register_junk_filter({name => 'E Junk Filter', code => ¥&score});

1;

このコードには、Movable Typeの基本的なプラグイン定義の決まり文句的なコードも含まれていますので、迷惑コメント/トラックバックの判断の部分に絞って見てみましょう。自作のスコアリング・ルーチンを、コメント受信時に実行するように登録しているのは

MT->register_junk_filter({name => 'E Junk Filter', code => ¥&score});

の部分です。このルーチンの構造は次のような単純なものです。

sub score {
    my ($obj) = @_;

    # ... return ABSTAIN if I can't find any E's ...
    # ... calculate a score based on "e" count ...

    return (-$score, "Contained $count 'e' characters");
}

このルーチンは1つだけ引数を取ります。フィルタリングの対象となるコメント(あるいはトラックバック)です。

戻り値は 、($score, [$log_line1, $log_line2])という形のリストでなければなりません。ただし2番目以降の値(ログ・メッセージの配列)は省略可能です。$scoreは-10から+10までの範囲の実数か、またはABSTAINという特殊な定数(MT::JunkFilterパッケージ中で定義されています)でなければなりません。

上のルーチンの例をもう少し細かく見てみましょう。ここではまずPerlの正規表現でeの数をカウントし、このカウントで算術演算(2の累乗)を取ることで、eの数が増えれば増えるほど大幅にスコアが高くなるようにしています。eが1個の場合であれば迷惑コメントの疑いがある、4~5個あれば確実に迷惑コメント、ということです。

ログ・メッセージには、プラグインが返すスコアを含めるようにするとよいでしょう。ログ・メッセージは、管理画面でコメントの内容とともに表示されるので、ブログ管理者が見たときに、どうしてそのようなスコアが返されたのかがわかるようになります。プラグインとは別に、Movable Type本体でもスコア集計値と処理内容を記載したログを追加します。

コメント中にeがない場合、プラグインはそのコメントについて正しい判断ができません。適正なコメントかもしれませんし、迷惑コメントと判断できる別の(eとは無関係な)記号が含まれていることも考えられます。けれどもそれはこのプラグインでは関知しないことなので、ABSTAINを返します。

注意しなければならないのは、0というスコアを返すことは、それ自体がコメントに対する判断であり、判断を放棄したことにはならないということです。ではどういう判断ということになるのでしょうか。たとえば、-1よりも少し迷惑の度合いが高く、1よりも少し迷惑の度合いが低い、ということになります。ブログ管理者は判断基準値を調節できるので、0というスコアを返すだけでコメントが迷惑に分類されたり、逆に適正なコメントが迷惑に分類されるのを防ぐことがあります。プラグイン開発者には、ユーザーが判断基準値をどう設定するかは予測がつきませんので、0というスコアは連続体のある1点に過ぎないと考えなければなりません。

一方、ABSTAINは、プラグインがそのコメント/トラックバックの迷惑度を判断するすべを持たないということを意味し、スコア集計値にはまったく影響を与えません。たとえば、次にコードを示すホワイトリスト・プラグインは、リストにある名前を含むコメントを迷惑フォルダーに入れないようにするプラグインですが、どんなスコアをつければコメントが迷惑とみなされるかを知るすべがないので、スコアをつけるのは危険です。また、ホワイトリストにある少数の名前を別にすれば、迷惑でないと判断する材料もありません。そこで、ホワイトリスト・プラグイン自身の基準にとって意味のある判断材料がない限りは、ABSTAINを返します。

sub score {
    my ($obj) = @_;
    my @whitelist_terms = ('George¥s+Lucas', 'Boutros¥s+Boutros¥s+Ghali',
        'Neil¥s+Armstrong', 'Salif¥s+Keita');
    my $whitelist_expr = join "|", @whitelist_terms;

    if ($obj->all_text() =~ /$whitelist_expr/i) {
        return (1, "Whitelisted by spam-whitelister.pl");
    } else {
        return ABSTAIN;
    }
}

迷惑コメント/トラックバック・フィルターのプラグインを自作する際には、Movable Typeの標準プラグインであるSpamLookupをベースにするとよいでしょう。Movable Typeに含まれるSpamLookupのコードはアーティスティック・ライセンスを利用条件としており、Perl自体と同様の条件で改変/再配布が可能です。


Copyright © 2001-2006 Six Apart, Ltd. All Rights Reserved.