simhash_server icon indicating copy to clipboard operation
simhash_server copied to clipboard

请教个使用问题

Open hjy2588818 opened this issue 9 years ago • 2 comments

这样计算出来每篇内容的simhash值,然后进行比对么?我的网站是PHP的,服务器上已经安装了,怎么计算两个值的相似度呢?请问有PHP的计算的代码么?

hjy2588818 avatar Jan 18 '17 04:01 hjy2588818

PHP 用这个吧, simhash算法, hash用的md5

class Simhash
{
	/**
	 * 通过分词计算simhash
	 * @param array  &$set ['词1', '词2', '词1'] 或 ['词1' => 2, '词2' => 1]
	 * @param int $length  返回的bit长度,一般如下值:32, 64, 128
	 * @return string 二进制文本
	 */
	public static function hash(array &$set, int $length = 128)
	{
		$boxes = array_fill(0, $length, 0);

		if (is_int(key($set)))
			$dict = array_count_values($set);
		else
			$dict = &$set;

		foreach ($dict as $element => $weight) {

			$hash = substr(hash('md5', $element), 0, $length / 8);
			$gmp = gmp_init($hash, 16);

			for ($i = 0; $i < $length; $i++)
				$boxes[$i] += gmp_testbit($gmp, $i) ? $weight : -$weight;
		}

		$result = gmp_init(str_repeat('0', $length), 2);

		foreach ($boxes as $i => $box) {
			if ($box > 0)
				gmp_setbit($result, $i);
		}

		return gmp_export($result); // 这里输出的是二进制 使用MySQL varbinary(16)存储
	}

	/**
	 * 计算两个Simhash的汉明距离,然后得到相似度
	 * Hamming distance
	 *
	 * @param  string $h1
	 * @param  string $h2
	 * @return float
	 */
	public static function hamdist(string $h1, string $h2)
	{
		if (($length = strlen($h1)) != strlen($h2) || $length <= 0)
			throw new \RuntimeException('strlen($h1) != strlen($h2) or zero size.');

		$b1 = gmp_import($h1); 
		$b2 = gmp_import($h2);

		return 1 - gmp_hamdist($b1, $b2) / ($length * 8);
	}
}

例子,肯定要先分词

$a = Simhash::hash(['我', '是', '中央电视台','的','员工', '对吧']);
$b = Simhash::hash(['我', '不是', '中央电视台','的','员工', '对吧']);

echo Simhash::hamdist($a, $b);  // 0.859375

Simhash算法对长文本还不错,但是上面的短句,效果就那样

fly-studio avatar Jul 06 '19 10:07 fly-studio

短文本用余弦定理

hjy2588818 avatar Jul 15 '19 15:07 hjy2588818