Ngramを利用したページ類似度チェッカー+Ngram計算のphpクラス 1

Ngramを利用したページ類似度チェッカー+Ngram計算のphpクラス

Ngram

まあ何がやりたかったって
スパムチェック的な類似度チェッカーです。

こんなかんじ。
類似度チェッカー

全く違うURLだと5~10%くらいになって
ちょっと関係がある(リンク紹介してたり)すると20%くらいかな
同じブログの違う記事とかだと40%くらいになって
60%超えたらかなり似てるページってかんじのラインです。

例えば wikiの アイスランドのページとアイルランドのページとかでやると
重複度77%とかになります。

Googleは言語にとらわれない解析方法を使っているとのことなので、
高確率で、どっかにNgramは使ってると思うので、
デュプリケイトコンテンツとかの参考に使えるかなーと。

一応ソース公開

たいしたものじゃないんですが、たいしたものじゃないだけに
ソースくらい出しとけというお話です。

アルゴリズム的には単純に
・URLからタグを引っぺがす
・出てきたテキストのNgram(3)を抽出
・2個URLの共通項を出す(php の array_instersect 使っただけ)
・(共通項の数 / Ngram(3)の個数) %

まあなんか array_intersect とarray_diff がま逆の動きをしないので
あやしいんですが。。
ソースを追うのもめんどいので後で検証。

使い方

Newして(引数でNgram2,3とかコントロール)
RunメソッドにURL突っ込むだけです。

こんなかんじです。
(以下見やすくする為にインデントを全角スペースに変換してあります。)

$Ngram = new CreateNgram();
if($Ngram->run(“http://dev.neoinspire.net/archives/92″,”http://dev.neoinspire.net/archives/90″)){
  print($Ngram->result);
  echo”<pre>”;
  print_r($Ngram->mainNgram);
  print_r($Ngram->checkNgram);
  echo”</pre>”;
}else{
  echo “対象のURLを解析できませんでした。”;
}

以下ソースです。コピペしてUTF8で保存してください。

<?php
/*
*2つのURLのNgramを比較して類似度を出すクラス
*引数を一つで出した場合単純に対象URLのNgramを抽出する
*/
Class CreateNgram{

  var $mainNgram; //第一引数URLのNgram
  var $checkNgram; //第二引数URLのNgram

  var $ngram; //Ngramをいくつでやるか
  var $result; //類似度

  function CreateNgram($ngram=3){
    $this->ngram = $ngram;
  }

  function run($mainUrl=null,$checkUrl=null){
    if(!empty($mainUrl) && !empty($checkUrl)){
      if($mainHtml = mb_convert_encoding(@file_get_contents($mainUrl), ‘UTF-8’, ‘auto’))
        $this->mainNgram = $this->_ngram($this->_solid($mainHtml));

      if($checkHtml = mb_convert_encoding(@file_get_contents($checkUrl), ‘UTF-8’, ‘auto’))
        $this->checkNgram = $this->_ngram($this->_solid($checkHtml));

      if(!empty($this->mainNgram) && !empty($this->checkNgram)){
        $mainResult = @array_intersect($this->mainNgram,$this->checkNgram);
        $checkResult = @array_intersect($this->checkNgram,$this->mainNgram);
        $result1 = count($mainResult);
        $result2 = count($checkResult);
        $cnt1 = count($this->mainNgram);
        $cnt2 = count($this->checkNgram);
        $this->result = @round((($result1 + $result2) / ($cnt1 + $cnt2)),3);
        return true;
      }else{
        return false;
      }
    }else{
      return false;
    }
  }

  function _ngram($query=null){
    $query = trim($query);
    if(!empty($query)){
      $len = mb_strlen($query,’UTF-8′);
      for($i=0; $i< $len; $i++){         $buf = trim(mb_substr($query, $i, $this->ngram,’UTF-8′));
        if(isset($buf))$ngrams[] = $buf;
      }
    }else{
      $ngrams = “”;
    }
    return $ngrams;
  }

  function _solid($html=null){
    if($html){
      $pat[]=”/<script.+?\/script>/is”;
      $pat[]=”/<style.+?\/style>/is”;
      $pat[]=”/<\!\-\-.+?\-\->/is”;
      $pat[]=”/<.*?>/is”;
      $pat[]=”/\r|\n|\s/is”;
      $rep=””;
      return preg_replace($pat,$rep,$html);
    }else{
      return “”;
    }
  }
}
?>


->