procmailsc - procmail の重みつきスコアリング手法 [*] w^x 条件文 レシピには伝統的な真偽条件を指定できるが、 それに加えてマッチする -- あるいはマッチしない -- 条件に対して、 重みつきスコアリング手法を採り入れることもできる。 レシピに重みつきスコアリング手法を使う場合、 あるレシピがマッチするということは、その最終スコアは必ず正の値である。 その条件に `weight' (重み) (w) 及び `exponent' (指数) (x) を置く ことで、スコアが適用される。 条件(の同一行)に w^x を前置すればスコアリング手法を適用できる。 但し、 w 及び x は -2147483647.0 〜 2147483647.0 の範囲内(両端を含む)の実数である。 最初に正規表現を見つけると、スコアに w を加算する。二番目を見つけると、 w*x を加算する。三番目を見つけると、 w*x*x を加算する。四番目を見つけると、 w*x*x*x を加算する。以下同様。 これは以下の簡単な公式で記述できる: 4 n n k-1 x - 1 w * Sum x = w * ------- k=1 x - 1 これは上記の条件において n 回マッチする際のスコアの合計を表す。 以下の場合は区別されるので注意されたい: x=0 最初のマッチのみがスコア w に影響する。後続のマッチは無視される。 x=1 全てのマッチはスコア w に等しく影響する。スコアはマッチする度毎にその数に 比例して線形的に増加する。 0<x<1 全てのマッチはそれ以前のスコアに対してより少なく影響する。 スコアはある値に向けて漸近線状に変化する (後述の 備考 の章を参照のこと。) 1<x 全てのマッチはそれ以前のスコアに対してより多く影響する。 スコアは指数的に増加する。 x<0 奇数あるいは偶数番目のマッチを与えるのに便利である。 正規表現が否定された場合(例: マッチしなかった場合)、 n は明らかに 0 あるいは 1となる。 プログラムが正常終了の結果として終了コード EXIT_SUCCESS (=0) を返す 場合、スコアの合計は w となる。 上記以外の(実行失敗を示す)終了コードを返す場合、スコアの合計は x となる。 プログラムの終了コードが否定される場合、終了コードはあたかもマッチした 数であったかの如く見倣される。 そして、スコアの合計は通常の正規表現が n=`exitcode' 回数マッチしたものとして処理される。 現在のメールの長さが M である場合: 1 * w^x > L という条件式は以下のような式でスコアに加算する: 4 x / M \ w * | --- | \ L / また: 1 * w^x < L という条件式は以下のような式でスコアに加算する: 4 x / L \ w * | --- | \ M / 両者共、 L=M であればスコアに w を加算する。 しかしながら前者の場合は大きいメールが有利であり、後者の場合は 小さいメールが有利である。 x の値によって関数の勾配を微調整することができるが、 典型的には x=1 である。 レシピの全ての条件の最終的な合計スコアを問い合わせるには、環境変数 $= を用いる。 この変数は procmail がレシピ内の全ての条件をパースした後はいつでも参照可能である。 (例えレシピが実行されなかったとしても。) 以下のレシピは本文が150行以上のメールを全て捨てる。 最初の条件は空の正規表現を含む。 すなわち、この条件は全てにマッチし、予めスコアに負の値のオフセットを与える為に使われる。 2番目の条件はメール中の全ての行にマッチし、1行毎に+1ポイントずつ加算することで、直前に設定していた負のオフセット値を消費する。 最後の条件では、メールが150行以上である場合のみにスコアが正の値になる。 5 :0 Bh * -150^0 * 1^1 ^.*$ /dev/null あなたがいつも真っ先に読む優先度の高いフォルダがあると仮定しよう。 次のレシピは重要度の高いメールを抜き出して特別なフォルダに放り込む。 最初の条件は定型的なものであり、スコアには何ら作用しないが、今回のケースにおいてはこの条件が満たされていなければならない。【訳注: Precedence: 行は各種メイリングリストや vacation 等の自動応答ソフト等、人手を介さない配送ソフトがメールを配送する際に付加したり、配送すべきか否かを判断するヘッダである。】 これ以外の条件は以下のような状況を記述する: John と Claire はいつも何らかの重要な発言をする。 会議は大概重要である。 彼らに対する返答はやや優先する。 Elvis に関するメール (これはあくまでも単なる一例に過ぎないのであしからず :-) は優先する (更に言えば、そのメールはもっと優先するが、 Elvis に割り当てられる特別なスコアは、彼がどれほど頻繁に言及しても、最大 4000 である)。 沢山の引用行は忌み嫌われ、顔マークは評価される (これらのスコアは最大 3500 に達する)。 彼ら3人は通常は興味深いメールを送信しないし、短いメールを好むはずだ (例えば、 2000バイトの長いメールはスコアを -100 、 4000バイトの長いメールはスコアを -800 減じる。)。 ご覧の通り、重要でない誰かがメールを送信すると、まだ優先度の高いフォルダに 格納される機会がある。 例えば、会議に関するメールや、少なくとも2つの顔マークを含んでいる場合である。 11 :0 HB * !^Precedence:.*(junk|bulk) * 2000^0 ^From:.*(john@home|claire@work) * 2000^0 ^Subject:.*meeting * 300^0 ^Subject:.*Re: * 1000^.75 elvis|presley * -100^1 ^> * 350^.9 :-\) * -500^0 ^From:.*(boss|jane|henry)@work * -100^3 > 2000 priority_folder 仮にあなたがメイリングリストに加入して、そして良質のメールだけを 読みたければ、以下のレシピが目的に適うはずだ。 先ず、当該メールがメイリングリストからのものであることを確認する。 次に、評価に値する意見を述べる重要人物からのメールであるか、あるいは 確実に全ての内容を知りたい表題に関するものであるかをチェックする。 もしそうならば、当該メールを前述のフォルダへファイリングする。 さもなくば、引用行と原文行の比率が最大 1:2 であるかチェックする。 もしこの比率を越えるものであれば、当該メールを捨てる。 これらのテストを通過した全てのメールはファイリングする。 15 :0 ^From mailinglist-request@some.where { :0: * ^(From:.*(paula|bill)|Subject:.*skiing) mailinglist :0 Bh * 20^1 ^> * -10^1 ^[^>] /dev/null :0: mailinglist } 更なる実例は procmailex(5) を参照されたい。 重みの順番による検索スピードを高速化させるために、 procmail の内部 egrep エンジンは常に最左の 最短 のマッチを探す。 ただし、変数 MATCH への割り当てを【訳注: \/によって】行っている最中は、最左の 最長 のマッチを探す。 例えば、それ自身による最左の 最短 のマッチに用いる正規表現は: .* は常に同じ点でゼロ長さの文字列にマッチする。 .+ は常に(勿論、改行を除く)任意の1文字にマッチする。 procmail(1), procmailrc(5), procmailex(5), sh(1), csh(1), egrep(1), grep(1), もし、長さ条件において、指定した x がオーバフローを起こした場合、 procmail は数学ライブラリの関数 pow(3) のなすがままとなる。 `工学'フォーマットの浮動小数点数値 (例: 12e5) は認められない。 `正の極大値' (2147483647) に到達すると、直ちにそれ以降の 重み付けされた 条件は単純に読み飛ばされる。 `負の極大値' (-2147483647) に到達すると、直ちにそれ以降の 条件は `マッチしないもの' として見倣され、レシピは早々に終了する。 もし、正規表現重み付け公式 0<x<1 において、この条件におけるスコア加算の総和は漸近的に変化する: 3 w ------- 1 - x 最大値の半分に至る為には、 3 - ln 2 n = -------- ln x というマッチが必要になる。 Stephen R. van den Berg <srb@cuci.nl> Philip A. Guenther <guenther@sendmail.com>