Springboot整合HanLP【自然语言处理库】实现两段文字语义的识别、比对
【代码】Springboot整合HanLP【自然语言处理库】实现两段文字语义识别、比对。
·
Springboot整合HanLP实现两段文字语义比对
一、maven
<!-- jdk8专用 -->
<dependency>
<groupId>org.apache.opennlp</groupId>
<artifactId>opennlp-tools</artifactId>
<version>1.9.4</version>
</dependency>
<dependency>
<groupId>com.hankcs</groupId>
<artifactId>hanlp</artifactId>
<version>portable-1.8.4</version>
</dependency>
二、中文向量模型
提供百度网盘:
cc.zh.300.zip
提取码:6783
三、引入
- 将下载好的cc.zh.300.vec模型放到一个目录,大小4.4G。
- 由于模型太大,有200w的向量词,后期在加载模型时,只加载50w的向量词。或者用其他方法提高加载速度。
四、工具类
1、yml配置:
hanlp:
vector:
# 相似度阈值
threshold: 0.8
# 模型存放目录
sourcePath: D:\***\cc.zh.300.vec
# 向量词加载50万
maxWords: 500000
preload: true
2、工具类
import com.hankcs.hanlp.HanLP;
import org.springframework.beans.factory.annotation.Value;
import java.io.*;
import java.nio.file.*;
import java.util.*;
import java.util.stream.*;
public class FastTextChineseSimilarity {
private final Map<String, float[]> wordVectors;
private final int vectorSize = 300; // FastText词向量维度
private final float[] zeroVector = new float[vectorSize];
@Value("${hanlp.vector.maxWords}")//50w
private int maxWords;
// 初始化加载词向量模型
public FastTextChineseSimilarity(String modelPath) throws IOException {
this.wordVectors = new HashMap<>();
loadModel(modelPath);
}
// 加载FastText词向量模型
private void loadModel(String modelPath) throws IOException {
System.out.println("开始加载词向量模型...");
long start = System.currentTimeMillis();
try (BufferedReader reader = Files.newBufferedReader(Paths.get(modelPath))) {
// 跳过第一行(词数和维度信息)
String firstLine = reader.readLine();
System.out.println("模型信息: " + firstLine);
String line;
int count = 0;
while ((line = reader.readLine()) != null) {
//只加载50w的向量词
if (wordVectors.size() >= maxWords) return;
String[] parts = line.split(" ");
if (parts.length != vectorSize + 1) continue;
String word = parts[0];
float[] vector = new float[vectorSize];
for (int i = 0; i < vectorSize; i++) {
vector[i] = Float.parseFloat(parts[i + 1]);
}
wordVectors.put(word, vector);
if (++count % 100000 == 0) {
System.out.println("已加载 " + count + " 个词向量");
}
}
}
System.out.printf("模型加载完成,耗时 %.2f秒,总词向量数: %d%n",
(System.currentTimeMillis() - start) / 1000.0, wordVectors.size());
}
// 中文分词(简单实现,实际应用建议使用专业分词器)
private List<String> segmentChinese(String text) {
if (text == null || text.isEmpty()) {
return Collections.emptyList();
}
return HanLP.segment(text).stream()
.map(term -> term.word)
.collect(Collectors.toList());
}
// 获取句子向量(词向量平均值)
public float[] getSentenceVector(String sentence) {
List<String> words = segmentChinese(sentence);
float[] sum = new float[vectorSize];
int validWords = 0;
for (String word : words) {
float[] vector = wordVectors.get(word);
if (vector != null) {
for (int i = 0; i < vectorSize; i++) {
sum[i] += vector[i];
}
validWords++;
}
}
if (validWords > 0) {
for (int i = 0; i < vectorSize; i++) {
sum[i] /= validWords;
}
return sum;
}
return zeroVector;
}
// 计算余弦相似度
public double cosineSimilarity(float[] vec1, float[] vec2) {
if (vec1 == null || vec2 == null || vec1.length != vec2.length) {
return 0.0;
}
double dotProduct = 0.0;
double norm1 = 0.0;
double norm2 = 0.0;
for (int i = 0; i < vec1.length; i++) {
dotProduct += vec1[i] * vec2[i];
norm1 += Math.pow(vec1[i], 2);
norm2 += Math.pow(vec2[i], 2);
}
if (norm1 == 0 || norm2 == 0) {
return 0.0;
}
return dotProduct / (Math.sqrt(norm1) * Math.sqrt(norm2));
}
// 计算两段文本的语义相似度
public double calculateSimilarity(String text1, String text2) {
float[] vec1 = getSentenceVector(text1);
float[] vec2 = getSentenceVector(text2);
return cosineSimilarity(vec1, vec2);
}
}
五、使用
相似度由自己定
//初始化模型
FastTextChineseSimilarity similarity = new FastTextChineseSimilarity(modelUrl);
String text1 = map.get("text1");
String text2 = map.get("text2");
//计算语义相似度(基于关键词匹配)
double distance = similarity.calculateSimilarity(text1, text2);
System.out.printf("语义相似度: %.3f%n", distance); //越接近 1 表示语义相似,自己配置阈值
/**
* 余弦相似度值 相似程度描述 适用场景示例
* 0.8 ~ 1.0 高度相似 重复文本、轻微改写的句子
* 0.6 ~ 0.8 中度相似 主题一致但表述不同的段落
* 0.4 ~ 0.6 低相似 部分关键词重叠但主题关联较弱
* 0 ~ 0.4 不相似 主题或关键词几乎无重叠
*/
六、测试
public static void main(String[] args) {
try {
FastTextChineseSimilarity similarity = new FastTextChineseSimilarity("D:\\***\\cc.zh.300.vec");
String text1 = "我是一个中国人";
String text2 = "我是一个有中国身份证的人";
double similarityScore = similarity.calculateSimilarity(text1, text2);
System.out.println("文本相似度: " + similarityScore);
} catch (IOException e) {
e.printStackTrace();
}
}
开始加载词向量模型...
模型信息: 2000000 300
已加载 100000 个词向量
已加载 200000 个词向量
已加载 300000 个词向量
已加载 400000 个词向量
已加载 500000 个词向量
文本相似度: 0.9012756555329973
更多推荐
所有评论(0)