Java相似度计算案例

wen java案例 3

本文目录导读:

Java相似度计算案例

  1. 余弦相似度计算
  2. 编辑距离(Levenshtein距离)
  3. Jaccard相似度
  4. 完整示例:文本匹配系统
  5. 使用第三方库(Apache Commons Text)

我来介绍几种常见的Java文本相似度计算方法及案例:

余弦相似度计算

import java.util.HashMap;
import java.util.Map;
import java.util.HashSet;
import java.util.Set;
public class CosineSimilarity {
    /**
     * 计算两个字符串的余弦相似度
     */
    public static double cosineSimilarity(String text1, String text2) {
        // 分词
        String[] words1 = text1.split("\\s+");
        String[] words2 = text2.split("\\s+");
        // 构建词频向量
        Map<String, Integer> freqMap1 = new HashMap<>();
        Map<String, Integer> freqMap2 = new HashMap<>();
        for (String word : words1) {
            freqMap1.put(word, freqMap1.getOrDefault(word, 0) + 1);
        }
        for (String word : words2) {
            freqMap2.put(word, freqMap2.getOrDefault(word, 0) + 1);
        }
        // 获取所有词汇
        Set<String> allWords = new HashSet<>(freqMap1.keySet());
        allWords.addAll(freqMap2.keySet());
        // 计算点积和模长
        double dotProduct = 0.0;
        double norm1 = 0.0;
        double norm2 = 0.0;
        for (String word : allWords) {
            int freq1 = freqMap1.getOrDefault(word, 0);
            int freq2 = freqMap2.getOrDefault(word, 0);
            dotProduct += freq1 * freq2;
            norm1 += freq1 * freq1;
            norm2 += freq2 * freq2;
        }
        if (norm1 == 0 || norm2 == 0) {
            return 0.0;
        }
        return dotProduct / (Math.sqrt(norm1) * Math.sqrt(norm2));
    }
    public static void main(String[] args) {
        String text1 = "Java is a programming language";
        String text2 = "Java is a programming tool";
        double similarity = cosineSimilarity(text1, text2);
        System.out.println("余弦相似度: " + similarity); // 约0.75
    }
}

编辑距离(Levenshtein距离)

public class LevenshteinDistance {
    /**
     * 计算编辑距离
     */
    public static int levenshteinDistance(String str1, String str2) {
        int m = str1.length();
        int n = str2.length();
        int[][] dp = new int[m + 1][n + 1];
        // 初始化
        for (int i = 0; i <= m; i++) {
            dp[i][0] = i;
        }
        for (int j = 0; j <= n; j++) {
            dp[0][j] = j;
        }
        // 动态规划
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                int cost = (str1.charAt(i - 1) == str2.charAt(j - 1)) ? 0 : 1;
                dp[i][j] = Math.min(Math.min(
                    dp[i - 1][j] + 1,  // 删除
                    dp[i][j - 1] + 1   // 插入
                ), dp[i - 1][j - 1] + cost);  // 替换
            }
        }
        return dp[m][n];
    }
    /**
     * 计算相似度(基于编辑距离)
     */
    public static double similarity(String str1, String str2) {
        int distance = levenshteinDistance(str1, str2);
        int maxLen = Math.max(str1.length(), str2.length());
        return maxLen == 0 ? 1.0 : 1.0 - (double) distance / maxLen;
    }
    public static void main(String[] args) {
        String str1 = "kitten";
        String str2 = "sitting";
        int distance = levenshteinDistance(str1, str2);
        double similarity = similarity(str1, str2);
        System.out.println("编辑距离: " + distance); // 3
        System.out.println("相似度: " + similarity); // 0.571...
    }
}

Jaccard相似度

import java.util.HashSet;
import java.util.Set;
public class JaccardSimilarity {
    /**
     * 计算Jaccard相似度
     */
    public static double jaccardSimilarity(String text1, String text2) {
        // 分词并去重
        String[] words1 = text1.split("\\s+");
        String[] words2 = text2.split("\\s+");
        Set<String> set1 = new HashSet<>();
        Set<String> set2 = new HashSet<>();
        for (String word : words1) {
            set1.add(word.toLowerCase());
        }
        for (String word : words2) {
            set2.add(word.toLowerCase());
        }
        // 计算交集
        Set<String> intersection = new HashSet<>(set1);
        intersection.retainAll(set2);
        // 计算并集
        Set<String> union = new HashSet<>(set1);
        union.addAll(set2);
        if (union.isEmpty()) {
            return 0.0;
        }
        return (double) intersection.size() / union.size();
    }
    public static void main(String[] args) {
        String text1 = "Java Python JavaScript";
        String text2 = "Java Python Ruby";
        double similarity = jaccardSimilarity(text1, text2);
        System.out.println("Jaccard相似度: " + similarity); // 0.5
    }
}

完整示例:文本匹配系统

import java.util.*;
import java.util.stream.Collectors;
public class TextSimilaritySystem {
    // 文档类
    static class Document {
        String id;
        String content;
        Document(String id, String content) {
            this.id = id;
            this.content = content;
        }
    }
    // 相似度计算接口
    interface SimilarityCalculator {
        double calculate(String text1, String text2);
    }
    // 搜索引擎
    static class SearchEngine {
        private List<Document> documents;
        private SimilarityCalculator calculator;
        private double threshold;
        SearchEngine(List<Document> documents, SimilarityCalculator calculator, double threshold) {
            this.documents = documents;
            this.calculator = calculator;
            this.threshold = threshold;
        }
        List<Map.Entry<String, Double>> search(String query) {
            return documents.stream()
                .map(doc -> {
                    double similarity = calculator.calculate(query, doc.content);
                    return new AbstractMap.SimpleEntry<>(doc.id, similarity);
                })
                .filter(entry -> entry.getValue() >= threshold)
                .sorted((e1, e2) -> Double.compare(e2.getValue(), e1.getValue()))
                .collect(Collectors.toList());
        }
    }
    public static void main(String[] args) {
        // 准备文档
        List<Document> documents = Arrays.asList(
            new Document("doc1", "Java is a programming language"),
            new Document("doc2", "Python is a scripting language"),
            new Document("doc3", "Java and Python are both programming languages"),
            new Document("doc4", "JavaScript is for web development")
        );
        // 创建搜索引擎(使用余弦相似度,阈值0.3)
        SearchEngine engine = new SearchEngine(
            documents, 
            CosineSimilarity::cosineSimilarity,
            0.3
        );
        // 执行搜索
        String query = "Java programming language";
        List<Map.Entry<String, Double>> results = engine.search(query);
        System.out.println("搜索: \"" + query + "\"");
        System.out.println("结果:");
        for (Map.Entry<String, Double> result : results) {
            System.out.printf("  %s: %.4f%n", result.getKey(), result.getValue());
        }
    }
}

使用第三方库(Apache Commons Text)

<!-- Maven依赖 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-text</artifactId>
    <version>1.10.0</version>
</dependency>
import org.apache.commons.text.similarity.CosineDistance;
import org.apache.commons.text.similarity.LevenshteinDistance;
import org.apache.commons.text.similarity.JaccardSimilarity;
public class ApacheTextSimilarity {
    public static void main(String[] args) {
        String text1 = "Hello World";
        String text2 = "Hello Java";
        // 余弦相似度
        CosineDistance cosineDist = new CosineDistance();
        Double cosineSimilarity = 1.0 - cosineDist.apply(text1, text2);
        System.out.println("余弦相似度: " + cosineSimilarity);
        // 编辑距离
        LevenshteinDistance levenshtein = new LevenshteinDistance();
        Integer distance = levenshtein.apply(text1, text2);
        System.out.println("编辑距离: " + distance);
        // Jaccard相似度
        JaccardSimilarity jaccard = new JaccardSimilarity();
        Double jaccardSim = jaccard.apply(text1, text2);
        System.out.println("Jaccard相似度: " + jaccardSim);
    }
}

这些案例涵盖了常用的文本相似度计算方法,可以根据实际需求选择合适的算法或组合使用。

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