Java實(shí)現(xiàn)文本查重的方法詳解
ansj 分詞法介紹
Ansj 是一個(gè)開源的 Java 中文分詞工具,基于中科院的 ictclas 中文分詞算法,采用隱馬爾科夫模型(HMM),比其他常用的開源分詞工具(如 MMseg4j)的分詞準(zhǔn)確率更高。作者為孫?。╝nsjsun),目前實(shí)現(xiàn)了中文分詞、中文姓名識(shí)別、用戶自定義詞典、關(guān)鍵字提取、自動(dòng)摘要、關(guān)鍵字標(biāo)記等功能,適用于對(duì)分詞效果要求高的各種項(xiàng)目。 雖然 Ansj 分詞的基本原理與 ictclas 的一樣,但是 Ansj 做了一些工程上的優(yōu)化,比如:用 DAT 高效地實(shí)現(xiàn)檢索詞典、鄰接表實(shí)現(xiàn)分詞 DAG、支持自定義詞典與自定義消歧義規(guī)則等。
Ansj 分詞器 git地址: github.com/NLPchina/ansj_seg
配置文件
在ansj中配置文件名為library.properties,這是一個(gè)不可更改的約定。
| 字段名 | 默認(rèn)值 | 說明 |
|---|---|---|
| isNameRecognition | true | 是否開啟人名識(shí)別 |
| isNumRecognition | true | 是否開啟數(shù)字識(shí)別 |
| isQuantifierRecognition | true | 是否數(shù)字和量詞合并 |
| isRealName | false | 是否取得真實(shí)的詞,默認(rèn)情況會(huì)取得標(biāo)注化后的 |
| isSkipUserDefine | false | 是否用戶辭典不加載相同的詞 |
| dic | library/default.dic | 自定義詞典路徑 |
| dic_[key] | 你的詞典路徑 | 針對(duì)不同語料調(diào)用不同的自定義詞典 |
| ambiguity | library/ambiguity.dic | 歧義詞典路徑 |
| ambiguity_[key] | library/ambiguity.dic | 歧義詞典路徑 |
| crf | null | crf 詞典路徑,不設(shè)置為默認(rèn) |
| crf_[key] | 你的模型路徑 | 針對(duì)不同語料調(diào)用不同的分詞模型 |
| synonyms | 默認(rèn)的同義詞典 | 針對(duì)不同語料調(diào)用不同的分詞模型 |
| synonyms_[key] | 你的同義詞典路徑 | 針對(duì)不同語料調(diào)用不同的分詞模型 |
默認(rèn)的配置文件:
#path of userLibrary this is default library dic=library/default.dic #redress dic file path ambiguityLibrary=library/ambiguity.dic #set real name isRealName=true #isNameRecognition default true isNameRecognition=true #isNumRecognition default true isNumRecognition=true #digital quantifier merge default true isQuantifierRecognition=true
目前支持的分詞策略:
| 名稱 | 用戶自定義詞典 | 數(shù)字識(shí)別 | 人名識(shí)別 | 機(jī)構(gòu)名識(shí)別 | 新詞發(fā)現(xiàn) |
|---|---|---|---|---|---|
| BaseAnalysis | X | X | X | X | X |
| ToAnalysis | √ | √ | √ | X | X |
| DicAnalysis | √ | √ | √ | X | X |
| IndexAnalysis | √ | √ | √ | X | X |
| NlpAnalysis | √ | √ | √ | √ | √ |
計(jì)算余弦相似度
余弦相似度是常見的相似度衡量手段,能夠用以比對(duì)兩個(gè)向量間的相似水準(zhǔn)。如下代碼呈現(xiàn)了計(jì)算兩篇論文之余弦相似度的方式:
余弦相似度是一種常用的計(jì)算兩個(gè)向量相似性的方法。它基于向量的點(diǎn)積和向量的模。
計(jì)算余弦相似度的原理如下:
- 向量表示:將需要比較的對(duì)象表示為向量。
- 點(diǎn)積運(yùn)算:計(jì)算兩個(gè)向量的點(diǎn)積,即對(duì)應(yīng)元素相乘后再求和。
- 向量模的計(jì)算:分別計(jì)算每個(gè)向量的模,通常使用歐幾里得范數(shù)。
- 計(jì)算余弦相似度:用兩個(gè)向量的點(diǎn)積除以它們的模的乘積。
具體公式為:
余弦相似度 = 向量 A 與向量 B 的點(diǎn)積 / (向量 A 的模 × 向量 B 的模)
余弦相似度的取值范圍在 -1 到 1 之間:
- 值為 1:表示兩個(gè)向量完全相同,即具有最大相似度。
- 值為 0:表示兩個(gè)向量相互垂直,即沒有相似性。
- 值為 -1:表示兩個(gè)向量完全相反,即具有最小相似度。
余弦相似度的優(yōu)點(diǎn)包括:
- 不受向量大小影響:它比較的是向量的方向,而不是它們的絕對(duì)大小。
- 對(duì)噪聲相對(duì)不敏感:在存在一些噪聲或誤差的情況下仍能給出相對(duì)合理的相似度度量。
在實(shí)際應(yīng)用中,余弦相似度常用于:
- 文本相似性度量:比較文本向量的相似度。
- 圖像相似性分析:衡量圖像特征向量的相似程度。
- 推薦系統(tǒng):找到用戶或物品之間的相似性。
/**
* 計(jì)算余弦相似度
* @param vec1 map1
* @param vec2 map2
* @return 相似度
*/
public double calculateCosSimilarity(Map<String, Integer> vec1, Map<String, Integer> vec2) {
double dotProduct = 0.0;
double norm1 = 0.0;
double norm2 = 0.0;
for (Map.Entry<String, Integer> entry : vec1.entrySet()) {
String word = entry.getKey();
int count = entry.getValue();
dotProduct += count * vec2.getOrDefault(word, 0);
norm1 += Math.pow(count, 2);
}
for (Map.Entry<String, Integer> entry : vec2.entrySet()){
int count = entry.getValue();
norm2 += Math.pow(count, 2);
}
return dotProduct / (Math.sqrt(norm1) * Math.sqrt(norm2));
}
/**
* 計(jì)算余弦相似度
* @param context1 文本1
* @param context2 文本2
* @return 相似度
*/
public double calculateCosSimilarity(String context1, String context2){
return calculateCosSimilarity(participleNlp(context1).stream().collect(Collectors.groupingBy(o -> o, Collectors.summingInt(o -> 1))),
participleNlp(context2).stream().collect(Collectors.groupingBy(o -> o, Collectors.summingInt(o -> 1))));
}
具體實(shí)現(xiàn)看這里
mavaen 依賴
采用 ansj 5.1.6的版本
<dependency>
<groupId>org.ansj</groupId>
<artifactId>ansj_seg</artifactId>
<version>5.1.6</version>
</dependency>
util 代碼如下
package cn.ideamake.business.tools.util;
import lombok.experimental.UtilityClass;
import org.ansj.domain.Term;
import org.ansj.splitWord.analysis.NlpAnalysis;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @author Barcke
* @version 1.0
* @projectName business-tools
* @className TextPlagiarismCheckUtil
* @date 2024/4/16 09:40
* @slogan: 源于生活 高于生活
* @description: 文本查重工具 分詞采用 ansj 分詞方法
**/
@UtilityClass
public class TextPlagiarismCheckUtil {
// 分詞方法 可替換!??! start
/**
* Nlp分詞方式
* @param context 文本信息
* @return 分詞后的list
*/
public List<String> participleNlp(String context){
return participleNlpToTerm(context).stream().map(Term::getName).collect(Collectors.toList());
}
/**
* Nlp分詞方式
* @param context 文本信息
* @return 分詞后的Term
*/
public List<Term> participleNlpToTerm(String context){
return NlpAnalysis.parse(context).getTerms();
}
// 分詞方法 可替換?。?! end
/**
* 計(jì)算余弦相似度
* @param vec1 map1
* @param vec2 map2
* @return 相似度
*/
public double calculateCosSimilarity(Map<String, Integer> vec1, Map<String, Integer> vec2) {
double dotProduct = 0.0;
double norm1 = 0.0;
double norm2 = 0.0;
for (Map.Entry<String, Integer> entry : vec1.entrySet()) {
String word = entry.getKey();
int count = entry.getValue();
dotProduct += count * vec2.getOrDefault(word, 0);
norm1 += Math.pow(count, 2);
}
for (Map.Entry<String, Integer> entry : vec2.entrySet()){
int count = entry.getValue();
norm2 += Math.pow(count, 2);
}
return dotProduct / (Math.sqrt(norm1) * Math.sqrt(norm2));
}
/**
* 計(jì)算余弦相似度
* @param context1 文本1
* @param context2 文本2
* @return 相似度
*/
public double calculateCosSimilarity(String context1, String context2){
return calculateCosSimilarity(participleNlp(context1).stream().collect(Collectors.groupingBy(o -> o, Collectors.summingInt(o -> 1))),
participleNlp(context2).stream().collect(Collectors.groupingBy(o -> o, Collectors.summingInt(o -> 1))));
}
/**
* 判斷文本是否重復(fù)
* @param context1 文本1
* @param context2 文本2
* @param threshold 閾值
* @return 是否重復(fù)
*/
public boolean ifPlagiarism(String context1, String context2, double threshold){
return calculateCosSimilarity(context1, context2) > threshold;
}
/**
* 判斷文本是否重復(fù) 默認(rèn)閾值 0.7
* @param context1 文本1
* @param context2 文本2
* @return 是否重復(fù)
*/
public boolean ifPlagiarism(String context1, String context2){
return ifPlagiarism(context1, context2, 0.7);
}
}使用案例
public static void main(String[] args) {
String str = "java實(shí)現(xiàn)論文查重,文本查重方案 采用 ansj 分詞法(barcke) -----" ;
String str2 = "java實(shí)現(xiàn)論文查重,文本查重方案 采用 ansj 分詞法(barcke) -----" ;
String str3 = "java實(shí)現(xiàn)cke) -----" ;
System.out.println("分詞數(shù)據(jù)(ansj分詞法):" + TextPlagiarismCheckUtil.participleNlp(str));
System.out.println("重復(fù)率:" + TextPlagiarismCheckUtil.calculateCosSimilarity(str, str2) + "是否重復(fù)(默認(rèn)閾值0.7):" + TextPlagiarismCheckUtil.ifPlagiarism(str, str2));
System.out.println("重復(fù)率:" + TextPlagiarismCheckUtil.calculateCosSimilarity(str, str3) + "是否重復(fù)(默認(rèn)閾值0.7):" + TextPlagiarismCheckUtil.ifPlagiarism(str, str3));
}
執(zhí)行結(jié)果:

到此這篇關(guān)于Java實(shí)現(xiàn)文本查重的方法詳解的文章就介紹到這了,更多相關(guān)Java文本查重內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JAVA代碼設(shè)置selector不同狀態(tài)下的背景顏色
這篇文章主要介紹了JAVA代碼設(shè)置selector不同狀態(tài)下的背景顏色,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-05-05
Mybatis + js 實(shí)現(xiàn)下拉列表二級(jí)聯(lián)動(dòng)效果
這篇文章給大家介紹基于Mybatis + js 實(shí)現(xiàn)下拉列表二級(jí)聯(lián)動(dòng)效果,實(shí)現(xiàn)代碼分為前端界面實(shí)現(xiàn)和后端處理方法,代碼簡(jiǎn)單易懂,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2021-06-06
Java 創(chuàng)建兩個(gè)線程模擬對(duì)話并交替輸出實(shí)現(xiàn)解析
這篇文章主要介紹了Java 創(chuàng)建兩個(gè)線程模擬對(duì)話并交替輸出實(shí)現(xiàn)解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-10-10
SpringBoot利用攔截器實(shí)現(xiàn)避免重復(fù)請(qǐng)求
Spring MVC中的攔截器(Interceptor)類似于Servlet中的過濾器(Filter),它主要用于攔截用戶請(qǐng)求并作相應(yīng)的處理。本文就將利用攔截器實(shí)現(xiàn)避免重復(fù)請(qǐng)求,感興趣的小伙伴可以了解一下2022-11-11
SpringBoot應(yīng)用啟動(dòng)流程源碼解析
這篇文章主要介紹了SpringBoot應(yīng)用啟動(dòng)流程源碼解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04

