本文目录导读:

在PHP项目中实现相似度分析,常见的有以下几种方法,具体选择取决于你的数据类型和场景:
文本相似度分析
1 余弦相似度(最常用)
适用于长文本、文档比较。
function cosineSimilarity($text1, $text2) {
// 分词
$words1 = str_word_count(strtolower($text1), 1);
$words2 = str_word_count(strtolower($text2), 1);
// 创建词频向量
$vector = array_unique(array_merge($words1, $words2));
$vec1 = array_fill_keys($vector, 0);
$vec2 = array_fill_keys($vector, 0);
foreach ($words1 as $word) {
$vec1[$word]++;
}
foreach ($words2 as $word) {
$vec2[$word]++;
}
// 计算点积和模长
$dotProduct = 0;
$magnitude1 = 0;
$magnitude2 = 0;
foreach ($vector as $word) {
$dotProduct += $vec1[$word] * $vec2[$word];
$magnitude1 += pow($vec1[$word], 2);
$magnitude2 += pow($vec2[$word], 2);
}
$magnitude1 = sqrt($magnitude1);
$magnitude2 = sqrt($magnitude2);
if ($magnitude1 * $magnitude2 == 0) return 0;
return $dotProduct / ($magnitude1 * $magnitude2);
}
2 Jaccard 相似度
适用于短文本、关键词比较。
function jaccardSimilarity($text1, $text2) {
$words1 = array_unique(str_word_count(strtolower($text1), 1));
$words2 = array_unique(str_word_count(strtolower($text2), 1));
$intersection = array_intersect($words1, $words2);
$union = array_unique(array_merge($words1, $words2));
if (empty($union)) return 0;
return count($intersection) / count($union);
}
3 Levenshtein 距离(编辑距离)
适用于字符串精确匹配。
function levenshteinSimilarity($str1, $str2) {
$maxLen = max(strlen($str1), strlen($str2));
if ($maxLen == 0) return 1;
$distance = levenshtein($str1, $str2);
return 1 - ($distance / $maxLen);
}
数组/集合相似度
function arraySimilarity(array $arr1, array $arr2) {
$intersection = array_intersect($arr1, $arr2);
$union = array_unique(array_merge($arr1, $arr2));
return count($intersection) / count($union);
}
使用扩展库(推荐)
1 使用 php-text-similarity 包
通过 Composer 安装:
composer require jacobemerick/text-similarity
示例代码:
use Jacobemerick\TextSimilarity\CosineSimilarity;
use Jacobemerick\TextSimilarity\JaccardSimilarity;
$cosine = new CosineSimilarity();
$similarity = $cosine->getSimilarity('Hello world', 'Hello there');
$jaccard = new JaccardSimilarity();
$similarity = $jaccard->getSimilarity('Hello world', 'Hello there');
2 使用 php-similarity 包
composer require dipcode/php-similarity
use Dipcode\PhpSimilarity\CosineSimilarity;
$similarity = new CosineSimilarity();
$score = $similarity->calculate('phrase 1', 'phrase 2');
中文文本相似度
对于中文,需要先进行分词:
// 使用 jieba-php 分词
composer require fukuball/jieba-php
require_once __DIR__ . '/vendor/autoload.php';
use Fukuball\Jieba\Jieba;
use Fukuball\Jieba\Finalseg;
Jieba::init();
Finalseg::init();
function chineseCosineSimilarity($text1, $text2) {
// 分词
$words1 = Jieba::cut($text1);
$words2 = Jieba::cut($text2);
// 使用 TF-IDF 向量化
$tfidf1 = getTfIdf($words1);
$tfidf2 = getTfIdf($words2);
// 计算余弦相似度
return cosineSimilarityForVectors($tfidf1, $tfidf2);
}
完整示例:文本相似度分析服务
class TextSimilarityService {
/**
* 计算文本相似度
*/
public function calculateSimilarity($text1, $text2, $method = 'cosine') {
switch ($method) {
case 'cosine':
return $this->cosineSimilarity($text1, $text2);
case 'jaccard':
return $this->jaccardSimilarity($text1, $text2);
case 'levenshtein':
return $this->levenshteinSimilarity($text1, $text2);
default:
throw new InvalidArgumentException("Unknown method: $method");
}
}
/**
* 批量比较多个文本
*/
public function batchCompare($baseText, array $texts, $method = 'cosine') {
$results = [];
foreach ($texts as $id => $text) {
$results[$id] = [
'text' => $text,
'similarity' => $this->calculateSimilarity($baseText, $text, $method)
];
}
// 按相似度排序
usort($results, function($a, $b) {
return $b['similarity'] <=> $a['similarity'];
});
return $results;
}
/**
* 查找相似文本(超过阈值)
*/
public function findSimilar($baseText, array $texts, $threshold = 0.5, $method = 'cosine') {
$results = $this->batchCompare($baseText, $texts, $method);
return array_filter($results, function($item) use ($threshold) {
return $item['similarity'] >= $threshold;
});
}
private function cosineSimilarity($text1, $text2) {
// 前面定义的余弦相似度函数
}
private function jaccardSimilarity($text1, $text2) {
// 前面定义的 Jaccard 相似度函数
}
private function levenshteinSimilarity($str1, $str2) {
// 前面定义的 Levenshtein 相似度函数
}
}
// 使用示例
$service = new TextSimilarityService();
$similarity = $service->calculateSimilarity('Hello world', 'Hello PHP', 'cosine');
性能优化建议
- 缓存分词结果:如果频繁处理相同文本
- 使用向量数据库:对于大规模数据,使用 Elasticsearch 或 Milvus
- 异步处理:大批量数据时使用队列
- 预处理文本:去除标点、停用词、统一大小写
选择合适的算法
| 场景 | 推荐算法 |
|---|---|
| 长文档比较 | 余弦相似度 + TF-IDF |
| 短文本/关键词 | Jaccard 相似度 |
| 字符串精确匹配 | Levenshtein 距离 |
| 英文文本 | 余弦相似度 |
| 中文文本 | 分词 + 余弦相似度 |
| 代码比较 | Levenshtein 距离 |
根据你的具体需求选择最适合的方法,对于简单的应用场景,内置函数如 similar_text() 和 levenshtein() 就足够了。
版权声明:足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播