Java利用hanlp完成语句相似度分析的案例详解
分享一篇hanlp分词工具使用的小案例,即利用hanlp分词工具分析两个中文语句的相似度的案例。供大家一起学习参考!
在做考试系统需求时,后台题库系统提供录入题目的功能。在录入题目的时候,由于题目来源广泛,且参与录入题目的人有多位,因此容易出现录入重复题目的情况。所以需要实现语句相似度分析功能,从而筛选出重复的题目并人工处理之。
下面介绍如何使用Java实现上述想法,完成语句相似度分析:
1、使用HanLP完成分词:
首先,添加HanLP的依赖:(jsoup是为了处理题干中的html标签,去除html标签得到纯文本的题干内容)

分词代码如下,需要处理html标签和标点符号:
private static List<String> getSplitWords(String sentence) {
// 去除掉html标签
sentence = Jsoup.parse(sentence.replace(" ","")).body().text();
// 标点符号会被单独分为一个Term,去除之
return HanLP.segment(sentence).stream().map(a -> a.word).filter(s -> !"`~!@#$^&*()=|{}':;',\\[\\].<>/?~!@#¥……&*()——|{}【】‘;:”“'。,、? ".contains(s)).collect(Collectors.toList());
}
2、合并分词结果,列出所有的词:

3、统计词频,得到词频构成的向量:
代码如下,其中allWords是上一步中得到的所有的词,sentWords是第一步中对单个句子的分词结果:

4、计算相似度(两个向量的余弦值):

以上所有方法的完整代码如下,使用SimilarityUtil.getSimilarity(String s1,String s2)即可得到s1和s2的语句相似度:
package com.yuantu.dubbo.provider.questionRepo.utils;
import com.hankcs.hanlp.HanLP;
import com.hankcs.hanlp.dictionary.CustomDictionary;
import org.jsoup.Jsoup;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
public class SimilarityUtil {
static {
CustomDictionary.add("子类");
CustomDictionary.add("父类");
}
private SimilarityUtil() {
}
/**
* 获得两个句子的相似度
*
* @param sentence1
* @param sentence2
* @return
*/
public static double getSimilarity(String sentence1, String sentence2) {
List<String> sent1Words = getSplitWords(sentence1);
System.out.println(sent1Words);
List<String> sent2Words = getSplitWords(sentence2);
System.out.println(sent2Words);
List<String> allWords = mergeList(sent1Words, sent2Words);
int[] statistic1 = statistic(allWords, sent1Words);
int[] statistic2 = statistic(allWords, sent2Words);
double dividend = 0;
double divisor1 = 0;
double divisor2 = 0;
for (int i = 0; i < statistic1.length; i++) {
dividend += statistic1[i] * statistic2[i];
divisor1 += Math.pow(statistic1[i], 2);
divisor2 += Math.pow(statistic2[i], 2);
}
return dividend / (Math.sqrt(divisor1) * Math.sqrt(divisor2));
}
private static int[] statistic(List<String> allWords, List<String> sentWords) {
int[] result = new int[allWords.size()];
for (int i = 0; i < allWords.size(); i++) {
result[i] = Collections.frequency(sentWords, allWords.get(i));
}
return result;
}
private static List<String> mergeList(List<String> list1, List<String> list2) {
List<String> result = new ArrayList<>();
result.addAll(list1);
result.addAll(list2);
return result.stream().distinct().collect(Collectors.toList());
}
private static List<String> getSplitWords(String sentence) {
// 去除掉html标签
sentence = Jsoup.parse(sentence.replace(" ","")).body().text();
// 标点符号会被单独分为一个Term,去除之
return HanLP.segment(sentence).stream().map(a -> a.word).filter(s -> !"`~!@#$^&*()=|{}':;',\\[\\].<>/?~!@#¥……&*()——|{}【】‘;:”“'。,、? ".contains(s)).collect(Collectors.toList());
}
}
---------------------
Java利用hanlp完成语句相似度分析的案例详解的更多相关文章
- 《java入门第一季》之面向对象(面向对象案例详解)
通过几个小案例理重新回顾一下前面所写的内容,对面向对象的理解更加深刻的目的: 案例一: /* 需求: 定义一个员工类,自己分析出几个成员, 然后给出成员变量,构造方法,getXxx()/setXxx( ...
- Android Telephony分析(二) ---- RegistrantList详解
前言 本文主要讲解RegistrantList的原理,以及如何快速分析RegistrantList相关的代码流程.在Telephony模块中,在RIL.Tracker(ServiceStateTrac ...
- 《手把手教你》系列基础篇(九十六)-java+ selenium自动化测试-框架之设计篇-跨浏览器(详解教程)
1.简介 从这一篇开始介绍和分享Java+Selenium+POM的简单自动化测试框架设计.第一个设计点,就是支持跨浏览器测试. 宏哥自己认为的支持跨浏览器测试就是:同一个测试用例,支持用不同浏览器去 ...
- 提高Java代码质量的Eclipse插件之Checkstyle的使用详解
提高Java代码质量的Eclipse插件之Checkstyle的使用详解 CheckStyle是SourceForge下的一个项目,提供了一个帮助JAVA开发人员遵守某些编码规范的工具.它能够自动化代 ...
- 【集合框架】JDK1.8源码分析之ArrayList详解(一)
[集合框架]JDK1.8源码分析之ArrayList详解(一) 一. 从ArrayList字表面推测 ArrayList类的命名是由Array和List单词组合而成,Array的中文意思是数组,Lis ...
- Java集合中List,Set以及Map等集合体系详解
转载请注明出处:Java集合中List,Set以及Map等集合体系详解(史上最全) 概述: List , Set, Map都是接口,前两个继承至collection接口,Map为独立接口 Set下有H ...
- java 日志体系(三)log4j从入门到详解
java 日志体系(三)log4j从入门到详解 一.Log4j 简介 在应用程序中添加日志记录总的来说基于三个目的: 监视代码中变量的变化情况,周期性的记录到文件中供其他应用进行统计分析工作: 跟踪代 ...
- 利用Intellij+MAVEN搭建Spring+Mybatis+MySql+SpringMVC项目详解
http://blog.csdn.net/noaman_wgs/article/details/53893948 利用Intellij+MAVEN搭建Spring+Mybatis+MySql+Spri ...
- Android Telephony分析(五) ---- TelephonyRegistry详解
本文紧接着上一篇文章<Android Telephony分析(四) —- TelephonyManager详解 >的1.4小节.从TelephonyRegistry的大部分方法中: 可以看 ...
随机推荐
- 解决The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request "accept" headers.
SpringMVC中当在浏览器中输入对应的MappingUrl时,报The resource identified by this request is only capable of generat ...
- 《统计学习方法》笔记(3):k近邻
k近邻(KNN)是相对基本的机器学习方法,特点是不需要建立模型,而是直接根据训练样本的数据对测试样本进行分类. 1.k近邻的算法? 算法对测试样本进行分类的一般过程如下: 1)根据给定的k值,搜索与测 ...
- PAT 乙级1003. 我要通过!(20)
“答案正确”是自动判题系统给出的最令人欢喜的回复.本题属于PAT的“答案正确”大派送 —— 只要读入的字符串满足下列条件,系统就输出“答案正确”,否则输出“答案错误”. 得到“答案正确”的条件是: 1 ...
- Java技术体系
Shell 解释型编程语言(脚本语言都是解释型语言) Shell通过解释器/bin/bash 解释,运行在进程中 Java 编译型解释型语言(先编译再解释) Java通过编译器转换成字节码语言,再用过 ...
- Python之路,第八篇:Python入门与基础8
python3 字典(dict) 概念:1 ,字典是一种可变的容器,可以存储任意类型的数据: 2, 字典中的每个数据都是用“键”(key)进行索引,而不像序列可以用下标进行索引: 3, 字典中的 ...
- 九度OJ1122题-吃巧克力
题目1122:吃糖果 时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:2453 解决:1957 题目描述: 名名的妈妈从外地出差回来,带了一盒好吃又精美的巧克力给名名(盒内共有 N 块巧克力 ...
- 动手动脑-Java的继承与多态
一. class Grandparent { public Grandparent() { System.out.println("GrandParent Created."); ...
- #include<bits/stdc++.h>的使用
#include<bits/stdc++.h>包含了C++里面所有的库函数,因此在写任何程序的时候只需要加上#include<bits/stdc++.h>即可.
- Codeforces Div3 #501 A-E(2) F以后补
感觉自己有点强迫症 不都写出来就找理由不写题解 http://codeforces.com/contest/1015 题目链接 A. Points in Segments 题目意思 n个线段 ...
- Apache Kafka 源码剖析
Getting Start 下载 http://kafka.apache.org/ 优点和应用场景 Kafka消息驱动,符合发布-订阅模式,优点和应用范围都共通 发布-订阅模式优点 解耦合 : 两个应 ...