怎样在PHP项目中实现相似度分析?

wen java案例 1

本文目录导读:

怎样在PHP项目中实现相似度分析?

  1. 文本相似度分析
  2. 数组/集合相似度
  3. 使用扩展库(推荐)
  4. 中文文本相似度
  5. 完整示例:文本相似度分析服务
  6. 性能优化建议
  7. 选择合适的算法

在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() 就足够了。

抱歉,评论功能暂时关闭!