JAVA-计算两篇文章的相似度

article/2025/5/16 22:55:31

1.场景:

        在很多公司的文件管理系统中,都有类似于对比多篇文章的相似度,例如在写公众号推文时,如果标记了原创,就会对比当前文章和库里已存在文章的相似程度,如果相似度过于高,则标记为原创的文章无法实现推送,那么,该功能是如何实现的呢?可以参考如下思路。


2.算法:

        此例子借助的是海明距离的实现方式,具体原理请移步(海明距离的定义与说明),此处不做过多的阐述。


3.工具类:SimilarityTwoUtils

package com.alex.examples.utils;import com.hankcs.hanlp.seg.common.Term;
import com.hankcs.hanlp.tokenizer.StandardTokenizer;
import org.apache.commons.lang.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.safety.Whitelist;import java.math.BigInteger;
import java.util.*;/*** 对比多篇文章中内容相似度算法工具类*/
public class SimilarityTwoUtils {/*** 标题名称*/private String topicName;/*** 分词向量*/private BigInteger bigSimHash;/*** 初始桶大小* 备注:对每条文本根据SimHash 算出签名后,再计算两个签名的海明距离(两个二进制异或后1的个数)即可。根* 据经验值,对64位的SimHash,海明距离在3以内的可以认为相似度比较高。* 假设对64位的SimHash,查找海明距离在3以内的所有签名。* 可以把64位的二进制签名均分成4块,每块16位。根据鸽巢原理(也称抽屉原理,见组合数学),如果两个签名的海明距离在3以内,它们必有一块完全相同。* 把上面分成的4块中的每一个块分别作为前16位来进行查找。建立倒排索引。*/private Integer hashCount = 64;/*** 分词最小长度限制*/private static final Integer WORD_MIN_LENGTH = 3;private static final BigInteger ILLEGAL_X = new BigInteger("-1");public SimilarityTwoUtils(String topicName, Integer myHashCount) {this.topicName = topicName;this.bigSimHash = this.simHash();//如果myHashCount为null,则默认64if (null != myHashCount) {this.hashCount = myHashCount;}}/*** 分词计算向量** @return BigInteger*/private BigInteger simHash() {// 清除特殊字符this.topicName = this.clearSpecialCharacters(this.topicName);int[] hashArray = new int[this.hashCount];// 对内容进行分词处理List<Term> terms = StandardTokenizer.segment(this.topicName);// 配置词性权重Map<String, Integer> weightMap = new HashMap<>(16, 0.75F);weightMap.put("n", 1);// 设置停用词Map<String, String> stopMap = new HashMap<>(16, 0.75F);stopMap.put("w", "");// 设置超频词上线Integer overCount = 5;// 设置分词统计量Map<String, Integer> wordMap = new HashMap<>(16, 0.75F);for (Term term : terms) {// 获取分词字符串String word = term.word;// 获取分词词性String nature = term.nature.toString();// 过滤超频词if (wordMap.containsKey(word)) {Integer count = wordMap.get(word);if (count > overCount) {continue;} else {wordMap.put(word, count + 1);}} else {wordMap.put(word, 1);}// 过滤停用词if (stopMap.containsKey(nature)) {continue;}// 计算单个分词的Hash值BigInteger wordHash = this.getWordHash(word);for (int i = 0; i < this.hashCount; i++) {// 向量位移BigInteger bitMask = new BigInteger("1").shiftLeft(i);// 对每个分词hash后的列进行判断,// 例如:1000...1,则数组的第一位和末尾一位加1,中间的62位减一,//       也就是,逢1加1,逢0减1,一直到把所有的分词hash列全部判断完// 设置初始权重Integer weight = 1;if (weightMap.containsKey(nature)) {weight = weightMap.get(nature);}// 计算所有分词的向量if (wordHash.and(bitMask).signum() != 0) {hashArray[i] += weight;} else {hashArray[i] -= weight;}}}// 生成指纹BigInteger fingerPrint = new BigInteger("0");for (int i = 0; i < this.hashCount; i++) {if (hashArray[i] >= 0) {fingerPrint = fingerPrint.add(new BigInteger("1").shiftLeft(i));}}return fingerPrint;}/*** 计算单个分词的hash值** @return BigInteger*/private BigInteger getWordHash(String word) {if (StringUtils.isEmpty(word)) {// 如果分词为null,则默认hash为0return new BigInteger("0");} else {// 分词补位,如果过短会导致Hash算法失败while (word.length() < SimilarityTwoUtils.WORD_MIN_LENGTH) {word = word + word.charAt(0);}// 分词位运算char[] wordArray = word.toCharArray();BigInteger x = BigInteger.valueOf(wordArray[0] << 7);BigInteger m = new BigInteger("1000003");// 初始桶pow运算BigInteger mask = new BigInteger("2").pow(this.hashCount).subtract(new BigInteger("1"));for (char item : wordArray) {BigInteger temp = BigInteger.valueOf(item);x = x.multiply(m).xor(temp).and(mask);}x = x.xor(new BigInteger(String.valueOf(word.length())));if (x.equals(ILLEGAL_X)) {x = new BigInteger("-2");}return x;}}/*** 过滤特殊字符** @return BigInteger*/private String clearSpecialCharacters(String topicName) {// 将内容转换为小写topicName = StringUtils.lowerCase(topicName);// 过来HTML标签topicName = Jsoup.clean(topicName, Whitelist.none());// 过滤特殊字符String[] strings = {" ", "\n", "\r", "\t", "\\r", "\\n", "\\t", "&nbsp;", "&amp;", "&lt;", "&gt;", "&quot;", "&qpos;"};for (String string : strings) {topicName = topicName.replaceAll(string, "");}return topicName;}/*** 获取标题内容的相似度** @return Double*/public Double getSimilar(SimilarityTwoUtils simHashUtil) {// 获取海明距离Double hammingDistance = (double) this.getHammingDistance(simHashUtil);// 求得海明距离百分比Double scale = (1 - hammingDistance / this.hashCount) * 100;Double formatScale = Double.parseDouble(String.format("%.2f", scale));return formatScale;}/*** 获取标题内容的海明距离** @return Double*/private int getHammingDistance(SimilarityTwoUtils simHashUtil) {// 求差集BigInteger subtract = new BigInteger("1").shiftLeft(this.hashCount).subtract(new BigInteger("1"));// 求异或BigInteger xor = this.bigSimHash.xor(simHashUtil.bigSimHash).and(subtract);int total = 0;while (xor.signum() != 0) {total += 1;xor = xor.and(xor.subtract(new BigInteger("1")));}return total;}}

4.测试类:ArticleSimilarityTest

package com.alex.examples;import cn.hutool.core.io.FileUtil;
import com.alex.examples.utils.SimilarityTwoUtils;public class ArticleSimilarityTest {public static void main(String[] args) {// 简单模拟,此处【库里已存在的文章】可以通过数据库查询后,再做对比String str1 = FileUtil.readString("你当前的文章", "utf-8");String str2 = FileUtil.readString("库里已存在的文章", "utf-8");// 计算相似度SimilarityTwoUtils mySimHash_1 = new SimilarityTwoUtils(str1, 64);SimilarityTwoUtils mySimHash_2 = new SimilarityTwoUtils(str2, 64);Double similar = mySimHash_1.getSimilar(mySimHash_2);System.out.println("两个文件的相似度相似度:" + similar);if (similar >= 95L) { // 这个相似度值的界限,根据公司的要求定义即可System.out.println("相似度过于高!!!");}}
}

4.运行结果:


5.鸽巢原理(对文章出现的鸽巢原理进行讲解):

        鸽巢原理也称为抽屉原理,是组合数学中一个重要的原理。

        抽屉原理的含义:如果每个抽屉代表一个集合,每一个皮球代表一个元素,假如有N+1个元素放到N个集合中,其实必定有一个集合里至少含有两个元素,如图:

 


http://chatgpt.dhexx.cn/article/aHcssqVh.shtml

相关文章

免费好用的文章相似度检测软件推荐

相信很多人在写作的时候都会遇到这样的问题&#xff0c;就是怕自己写出的文章被抄袭。为了保证自己的原创性&#xff0c;我们需要使用一些文章相似度检测软件来帮助我们检测文章是否被抄袭。那么&#xff0c;有哪些免费好用的文章相似度检测软件呢&#xff1f;下面就为大家介绍…

判断两篇文章的相似度

判断相似度 基于jieba 关键字提取的方法textrank关键字的提取代码&#xff1a;tf-idf关键字的提取代码&#xff1a;统计数据统计数据的代码&#xff1a;完整代码&#xff1a; 基于jieba 关键字提取的方法 textrank 1&#xff0c;将待抽取关键词的文本进行分词 2&#xff0c;以…

检测文章相似度的方法?文章原创度检测工具免费

免费检测文章相似度的软件&#xff0c;什么是检测文章相似度的软件&#xff0c;简单来说就是原创检测工具&#xff0c;相信不少的朋友都在利用这个功能来检测自己文章的原创度是多少&#xff1f;要做好一篇文章真的只需要检测文章的相似度吗&#xff1f;答案&#xff1a;肯定是…

[将小白进行到底] 如何比较两篇文章的相似度

其实这个题目已经有很多人写过了&#xff0c;数学之美里就有&#xff0c;最近阮一峰的博客里也写了&#xff0c;本文基本上遵循的就是他的思路&#xff0c;只是让其看起来再小白一点点。其实说白了就是用自己的话&#xff0c;再把同样一件事描述一下&#xff0c;顺便扩扩句&…

文本相似度的检测

项目原理 基于词频:统计文章中词频,构建词频特征向量,利用特征向量夹角的余弦值表示文本的相似度。两篇文章最大相似度为1,特征向量夹角为0。 基于词频的文本相似度检测步骤: 文本1和文本2分词—去停用词统计两篇文章的词频词频向量1和词频向量2相似度的计算分词:例:“…

网页抓取:PHP实现网页爬虫方式小结

抓取某一个网页中的内容&#xff0c;需要对DOM树进行解析&#xff0c;找到指定节点后&#xff0c;再抓取我们需要的内容&#xff0c;过程有点繁琐。LZ总结了几种常用的、易于实现的网页抓取方式&#xff0c;如果熟悉JQuery选择器&#xff0c;这几种框架会相当简单。 一、Ganon …

php中取页面的值_php如何抓取网页上的数据

php中抓取网页内容的实例详解 方法一&#xff1a;使用file_get_contents方法实现$url "http://news.sina.com.cn/c/nd/2016-10-23/doc-ifxwztru6951143.shtml"; $html file_get_contents($url); //如果出现中文乱码使用下面代码 //$getcontent iconv("gb2312…

关于如何使用PHP抓取网页数据并进行处理的经验

在网络时代&#xff0c;数据是无处不在的。很多时候&#xff0c;我们需要从网页上获取特定的数据&#xff0c;以便进行进一步的处理和分析。而PHP作为一种强大的编程语言&#xff0c;提供了丰富的函数和库来帮助我们实现这个目标。本文将分享一些关于如何使用PHP抓取网页数据并…

php根据URL获得网页内容

php 中根据url来获得网页内容非常的方便&#xff0c;可以通过系统内置函数file_get_contents(),传入url,即可返回网页的内容&#xff0c;比如获得百度首页的内容代码为&#xff1a; <?php $html file_get_contents(http://www.baidu.com/);echo $html; 就可以显示出百度首…

php抓取网页内容,获取网页数据

php通过simple_html_dom实现抓取网页内容&#xff0c;获取核心网页数据&#xff0c;将网页数据写入本地 xxx.json 文件 其代码实现逻辑&#xff1a; 1. 引入simple_html_dom.php文件 require_once simple_html_dom-master/simple_html_dom.php; 2. 获取远程或者本地html文件…

PS Adobe软件使用 快捷键

两年前学的&#xff0c;为了考一个高新 怕自己忘了 仅为防止以后自己忘记而做的备忘笔记&#xff0c;请勿吐槽 图片类型 JPEG 有损压缩格式(能够将图像压缩在很小的储存空间&#xff0c;图像中重复或不重要的资料会被丢失&#xff0c;因此容易造成图像数据的损伤。尤其是…

html选区控制怎么用,ps载入选区的快捷键是什么?

ps载入选区的快捷键是&#xff1a;ALTSO。在ps中&#xff0c;使用“ALTSO”快捷键&#xff0c;会弹出“载入选区”对话框&#xff0c;然后选择相应的通道&#xff0c;点击“确定”&#xff0c;即可载入选区。 ps载入选区有三种方法&#xff1a;右键菜单、ps载入选区快捷键、以及…

计算机中的PS颜色填充快捷键,ps颜色填充快捷键【设置办法】

喜欢使用电脑的小伙伴们一般都会遇到win7系统ps颜色填充快捷键的问题&#xff0c;突然遇到win7系统ps颜色填充快捷键的问题就不知道该怎么办了&#xff0c;其实win7系统ps颜色填充快捷键的解决方法非常简单&#xff0c;按照 1&#xff1a;首先我们先打开打开ps软件&#xff0c;…

html自由变换图形,ps自由变换的快捷键是什么?

在当前图层中&#xff0c;执行“编辑”——“自由变换”&#xff0c;或者使用ps自由变换快捷键ctrlT&#xff0c;周围会出现变换控件定界框。 当我们使用ps自由变换快捷键ctrlT&#xff0c;开启自由变换之后&#xff0c;然后再配合Ctrl、Shift、Alt&#xff0c;可以对图像进行缩…

计算机中的PS颜色填充快捷键,ps颜色填充快捷键【解决技巧】

很多小伙伴都遇到过ps颜色填充快捷键的困惑吧&#xff0c;一些朋友看过网上零散的ps颜色填充快捷键的处理方法&#xff0c;并没有完完全全明白ps颜色填充快捷键是如何解决的&#xff0c;今天小编准备了简单的解决办法&#xff0c;只需要按照 1&#xff1a;首先我们先打开打开ps…

计算机中的PS颜色填充快捷键,ps中填充颜色的快捷键是什么(填充Shift+F5)

很多小伙伴都遇到过ps颜色填充快捷键的困惑吧&#xff0c;一些朋友看过网上零散的ps颜色填充快捷键的处理方法&#xff0c;并没有完完全全明白ps颜色填充快捷键是如何解决的&#xff0c;今天小编准备了简单的解决办法&#xff0c;只需要按照下面方法操作就行。 PS填充快捷键是S…

PS常用快捷键

PS常用快捷键 1. PS工具快捷键2. 常用的通用快捷键2.1 文档操作2.2 画面显示操作2.3 其他操作 3. 图层操作的快捷键4. 图像调整操作快捷键5. 移动工具模式快捷键6. 选区类工具模式快捷键6.1 选框工具模式6.2 套索工具模式6.3 快速选择工具模式 7. 画笔工具模式快捷键 声明&…

html5如何快速选择工具,PS快速选择工具怎么使用?快捷键是什么?

快速选择工具是创建选区时使用频率相当高的一个工具&#xff0c;不但使用起来十分方便&#xff0c;创建的选区精度也十分高。下面我们就一起来看看PS快速选择工具怎么使用&#xff1f;快捷键是什么吧&#xff01; 1、快速选择工具 快速选择工具使用一个可以调节大小的原型笔尖来…

Ps怎么进行反选

Ps怎么进行反选&#xff0c;ps是我们日常生活中也会经常用到的一款强大的图像处理软件&#xff0c;不论是美工还是平面设计师、插画设计师等等&#xff0c;都会用到ps软件&#xff0c;那么在ps软件里面&#xff0c;怎么样对图像进行反选&#xff1f;其实也很简单哦&#xff01;…

应用商店的ASO和搜索引擎的SEO的区别

ASO和SEO&#xff0c;目标相似&#xff0c;有着异曲同工之妙&#xff0c;两者都是提高搜索排名的方式&#xff0c;具体有什么区别呢&#xff1f;今天柚鸥ASO给大家做一下总结。 SEO是指搜索引擎优化&#xff0c;利用搜索引擎的规则来提高网站&#xff08;例如&#xff1a;百度…