本文目录导读:

我来介绍几种常见的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);
}
}
这些案例涵盖了常用的文本相似度计算方法,可以根据实际需求选择合适的算法或组合使用。