当前位置: 首页 > 后端技术 > PHP

文章相似度计算

时间:2023-03-29 18:06:06 PHP

文章内容相似度计算方法及其优缺点PHP内置方法similar_textsimilar_text是PHP内置的字符串相似度比较函数,使用起来最方便,但由于其时间复杂度为O(N**3),处理时间会随着内容的长度增加。如果你对比的文章超过5000字,或者对比文章的量级比较大,不建议使用。它只能用于单个文章。通过分词进行余弦相似度比较的解决方法是先进行文章分词。可以使用stutter或者fastsearch分词服务进行文章分词,然后将需要比对的文章分词结果保存在redis中。当有新的文章进行比对时,将redis所有文章的分词结果从内存中取出,然后进行相似度比较,逐字进行相似度计算。相似度计算的准确性很高,但是当比对的文章量很大时,处理时间还是会很长。5000篇文章的相似度计算需要将近30S。主要计算代码:ClassTextSimilarity{/***[排除词]**@vararray*/private$_excludeArr=array('的','了','and','what','ah','哦','en','嗯','酒吧');/***[单词分布数组]**@vararray*/private$_words=array();/***[分词后数组1]**@vararray*/private$_segList1=array();/***[分词后的数组2]**@vararray*/private$_segList2=array();私有静态$test1=array();私有静态$test2=array();/***[分词两段文字]**@param[type]$text1[description]*@param[type]$text2[description]*/publicfunction__construct($text1,$text2){$this->_segList1=is_array($text1)?$text1:$this->segment($text1);$this->_segList2=is_array($text2)?$text2:$this->段($text2);}/***[外部调用]**@return[类型][描述]*/publicfunctionrun(){$this->analyse();$rate=$this->handle();回报率?$rate:'错误';}/***[分析两段文字]*/privatefunctionanalyse(){//t1foreach($this->_segList1as$v){if(!in_array($v,$this->_excludeArr)){如果(!array_key_exists($v,$this->_words)){$this->_words[$v]=array(1,0);}else{$this->_words[$v][0]+=1;}}}//t2foreach($this->_segList2as$v){if(!in_array($v,$this->_excludeArr)){if(!array_key_exists($v,$this->_words)){$this->_words[$v]=array(0,1);}else{$this->_words[$v][1]+=1;}}}}/***[处理相关度]**@return[type][description]*/private函数handle(){$sum=$sumT1=$sumT2=0;foreach($this->_wordsas$word){$sum+=$word[0]*$word[1];$sumT1+=pow($word[0],2);$sumT2+=pow($word[1],2);}$rate=$sum/(sqrt($sumT1*$sumT2));回报率;}/***[分词【http://www.xunsearch.com/scws/docs.php#pscws23】]**@param[type]$text[description]**@return[type][description]**@description分词只是一个简单的例子,你可以使用任何分词服务*/privatefunctionsegment($text){$outText=array();$xs=newXS('演示');//必须先创建一个xs实例,否则会抛出异常$tokenizer=newXSTokenizerScws;//直接创建实例$tokenizer->setIgnore();//处理$outText=$tokenizer->setMulti(1)->getResult($text);$outText=array_column($outText,'单词');$res=$xs->getScwsServer();$res->关闭();返回$outText;}}SimHashSimHash的原理是将一段很长的文本降维为0和1组成的字符串,然后计算两个01字符串之间的相似度,从而计算出两篇文章之间的相似度。相似度存储在redis或者mysql中,需要的时候取出来对比。20000篇文章的比对速度计算时间基本在2s以内,但是当文章数量很少,重复词很多时,文章不相同但相似度很高的问题。主要计算代码:classSimHash{protectedstatic$length=256;protectedstatic$search=array('0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f');protectedstatic$replace=array('0000','0001','0010','0011','0100','0101','0110','0111','1000','1001','1010','1011','1100','1101','1110','1111');/***[排除词]**@vararray*/privatestatic$_excludeArr=array('的','了','and','呀','ah','oh','en','嗯','酒吧','你','我','');publicstaticfunctionget(array&$set){$boxes=array_fill(0,self::$length,0);如果(is_int(key($set)))$dict=array_count_values($set);否则$dict=&$set;foreach($dictas$element=>$weight){if(in_array($element,self::$_excludeArr)){继续;}$hash=hash('sha256',$element);$hash=str_replace(self::$search,self::$replace,$hash);$hash=substr($hash,0,self::$length);$hash=str_pad($hash,self::$length,'0',STR_PAD_LEFT);对于($i=0;$i0)$s.='1';否则$s.='0';}返回$s;}公共静态函数hd($h1,$h2){$dist=0;对于($i=0;$i