--- spam.module.orig 2005-01-25 21:46:14.000000000 +0000 +++ spam.module 2005-01-27 00:16:54.000000000 +0000 @@ -122,7 +122,7 @@ $tokens = spam_tokenize($node->title, 'title*'); $tokens = array_merge($tokens, spam_tokenize($node->body)); $weight += spam_limit_urls('content', spam_count_urls()); - if (($rating = _spam_rating($tokens, $weight)) >= + if (($rating = _spam_rating($tokens, $weight)) >= variable_get('spam_threshold', 80)) { spam_node_actions($node, $tokens, 1, $op); } @@ -236,7 +236,7 @@ $group .= $inner_output; } $output .= form_group('Advanced configuration', $group); - + return $output; } @@ -260,7 +260,7 @@ $items = array(); if ($may_cache) { $items[] = array('path' => 'admin/comment/list/spam', 'title' => t('spam'), - 'access' => user_access('administer spam rating'), + 'access' => user_access('administer spam rating'), 'callback' => 'spam_admin', 'type' => MENU_LOCAL_TASK); $items[] = array('path' => 'admin/node/spam', 'title' => t('spam'), 'access' => user_access('administer spam rating'), @@ -333,7 +333,7 @@ $sql .= tablesort_sql($header); $result = pager_query($sql, 50); - // Make sure the update controls are disabled if we don't have any rows + // Make sure the update controls are disabled if we don't have any rows // to select from. $disabled = !db_num_rows($result); @@ -396,7 +396,7 @@ $sql .= tablesort_sql($header); $result = pager_query($sql, 50); - // Make sure the update controls are disabled if we don't have any rows + // Make sure the update controls are disabled if we don't have any rows // to select from. $disabled = !db_num_rows($result); @@ -847,7 +847,7 @@ function spam_page() { $content = arg(1); $op = arg(3); - + switch ($content) { case 'comment': if ($op) { @@ -883,7 +883,7 @@ } drupal_set_message(t('Comment marked as spam.')); drupal_goto("node/$comment->nid#comment-$comment->cid"); - } + } else { if (variable_get('spam_unpublish', 0)) { spam_admin_publish_comment($comment->cid); @@ -927,7 +927,7 @@ } drupal_set_message(t("$node->type marked as spam.")); drupal_goto("node/$node->nid"); - } + } else { if (variable_get('spam_unpublish', 0)) { spam_admin_publish_node($node->nid); @@ -944,7 +944,7 @@ /** * Break text into words. Special handling currently exists for urls. - * + * * @param $string A string of text to tokenize * @param $tag An optional tag to prepend to each token * @return An array of all words obtained from string @@ -1097,40 +1097,37 @@ /** * Test array of words against known words, determine probability is spam - * + * * @param $tokens An array of tokens * @return An int from 1 to 99 which is the probability that $tokens are spam */ // test whether or not current content in form of token array is spam function _spam_rating($tokens = array(), $weight = 0) { - // build token array, use drift as index - foreach ($tokens as $token) { - $p = db_fetch_object(db_query("SELECT probability FROM {spam_tokens} WHERE token = '%s'", $token)); - if (!$p->probability) { - $p->probability = variable_get('spam_unknown_probability', 40); - } - // get drift from median of 50 - $t["$token,$p->probability"] = abs($p->probability - 50); - } - // sort so largest drift is first - asort($t); - $keys = array_keys($t); - $max = variable_get('spam_interesting_tokens', 15); - $total = 0; - // grab n tokens with largest drift - for ($i = 0; $i < $max; $i++) { - if ($pair = array_shift($keys)) { - $p = explode(',',$pair); - // add up combined probabilities - $total = $total + $p[1]; + + // $drift - minimal drift from the median - a soft-ish shoulder of the filter + // $max - maximum number of tokens to evaluate, a hard shoulder of the filter + $probs = array(); + $drift = variable_get('spam_min_drift', 40); + //since the tokens are already filtered by drift, it may prove useful to + //get a few more anyway - this is more a memory saving and speed improvement + //measure than precision. It is somewhat akin to brain surgery, but fast. + $max = variable_get('spam_interesting_tokens', 40); + $num=0; + + //Speed increase depends on asort() and the number of interesting tokens considered + //vs the added comparison and evaluation in SQL + foreach($tokens as $token){ + $p = db_fetch_object(db_query("SELECT probability FROM {spam_tokens} WHERE token='%s' AND (ABS(50 - probablility) >= %d) AND last >= %d SORT BY ABS(50 - probability)", $token,$drift,$drift)); + if($p->probability){ + $probs += $p->probability; + $num++; } - else { - // no more tokens + if($num>$max) { break; } } - $rating = ($total + $weight) / $i; + $rating = ($probs + $weight) / $num; if ($rating > 99) $rating = 99; else if ($rating < 1) @@ -1144,7 +1141,7 @@ * bayesian filter. When passed in, each counter name should start with a * '+' or a '-', indicating whether the counter should be incremented or * decremented. - * + * * @param $counters An array of counter names */ function _count($counters) { @@ -1170,9 +1167,9 @@ * Saves an array of tokens to the database, marking as 'spam' or 'notspam'. * If the token already exists in the database, then the appropriate counter * is incremented, tracking how many times it has been seen. - * + * * @param $tokens An array of tokens to be saved in the database - * @param $type String, either 'spam' or 'notspam' + * @param $type String, either 'spam' or 'notspam' */ function spam_save_tokens($tokens, $type) { foreach ($tokens as $token) { @@ -1198,9 +1195,9 @@ * on what type of action is requested, either the token's 'spam' counter or * 'notspam' counter will be decremented. This function is used to unlearn * specific content that was mis-marked as spam or notspam. - * + * * @param $tokens An array of tokens to be saved in the database - * @param $type String, either 'spam' or 'notspam' + * @param $type String, either 'spam' or 'notspam' */ function spam_unsave_tokens($tokens, $type) { foreach ($tokens as $token) { @@ -1213,7 +1210,7 @@ } if ($type == 'spam') _count(array("+unlearned_notspam")); - else + else _count(array("+unlearned_spam")); variable_set('spam_calculate_probabilities', 1); } @@ -1230,7 +1227,7 @@ * the module's configuration page. * * TODO: Measure the effectiveness of both of these algorithms. Pick the best, - * or come up with something better. Ultimately this should not be a + * or come up with something better. Ultimately this should not be a * configurable option. */ function spam_calculate_probabilities($since = 0) { @@ -1452,7 +1449,7 @@ * based on the list of spamm comments and nodes in found in their respective * tables. This function is useful for three reasons: 1) if upgrading to a new * version of the tokenizer, you need to resynchronize your known tokens, 2) - * if your spam filter seems to be well trained, and you want to cleanly + * if your spam filter seems to be well trained, and you want to cleanly * measure its performance, and 3) if testing/developing an improved tokenizer * or spam probability logic. */