物料准备:
1.ansj_seg和hanlp的依赖
2.定义工具类,用来计算两段文本的相似度,以及从文本中提取关键词(摘要)
3.配置ansj_seg框架需要的dic词典
<dependency>
<groupId>org.ansjgroupId>
<artifactId>ansj_segartifactId>
<version>5.1.6version>
dependency>
<dependency>
<groupId>com.hankcsgroupId>
<artifactId>hanlpartifactId>
<version>portable-1.6.8version>
dependency>
import cn.hutool.core.date.StopWatch;
import com.hankcs.hanlp.seg.common.Term;
import com.hankcs.hanlp.tokenizer.StandardTokenizer;
import org.ansj.app.keyword.Keyword;
import org.ansj.app.summary.SummaryComputer;
import org.ansj.app.summary.pojo.Summary;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class TextStrUtil {
/**
* 单个分词 求hash
*
* @param termStr String 单个分词
* @return BigInteger hash值
*/
private static BigInteger computeTermStrHash(String termStr) {
if (termStr == null || termStr.length() == 0) {
return new BigInteger("0");
} else {
//当 termStr 的长度过短,会导致hash算法失效,因此需要对过短的词补偿
while (termStr.length() < 3) {
termStr = termStr + termStr.charAt(0);
}
char[] sourceArray = termStr.toCharArray();
BigInteger x = BigInteger.valueOf(((long) sourceArray[0]) << 7);
BigInteger m = new BigInteger("1000003");
BigInteger mask = new BigInteger("2").pow(64).subtract(
new BigInteger("1"));
for (char item : sourceArray) {
BigInteger temp = BigInteger.valueOf((long) item);
x = x.multiply(m).xor(temp).and(mask);
}
x = x.xor(new BigInteger(String.valueOf(termStr.length())));
if (x.equals(new BigInteger("-1"))) {
x = new BigInteger("-2");
}
return x;
}
}
/**
* 长字符串求hash
*
* @param str String 长字符串
* @return BigInteger hash值
*/
private static BigInteger computeStrHash(String str) {
int[] v = new int[64]; //哈希位数,设置64
// 利用hanlp 对字符串进行分词
List<Term> termList = StandardTokenizer.segment(str);
// 对分词的一些特殊处理 : 比如: 根据词性添加权重 , 过滤掉标点符号 , 过滤超频词汇等;
Map<String, Integer> weightOfNature = new HashMap<String, Integer>(); // 词性的权重
weightOfNature.put("n", 2); // 给名词的权重是2;
weightOfNature.put("nr", 5); // 给人名的权重是5;
weightOfNature.put("ns", 5); // 给地名的权重是5;
// 停用的词性
Map<String, String> stopNatures = new HashMap<String, String>();
// 如一些标点符号之类的;
stopNatures.put("w", "");
// 设定超频词汇的界限 ;
int overCount = 5;
Map<String, Integer> wordCount = new HashMap<>();
for (Term term : termList) {
// 分词字符串
String word = term.word;
// 分词属性;
String nature = term.nature.toString();
// 过滤超频词
if (wordCount.containsKey(word)) {
int count = wordCount.get(word);
if (count > overCount) {
continue;
}
wordCount.put(word, count + 1);
} else {
wordCount.put(word, 1);
}
// 过滤停用词性
if (stopNatures.containsKey(nature)) {
continue;
}
// 将每一个分词hash为一组固定长度的数列.比如 64bit 的一个整数.
BigInteger t = computeTermStrHash(word);
for (int i = 0; i < 64; i++) {
BigInteger bitmask = new BigInteger("1").shiftLeft(i);
// 建立一个长度为64的整数数组(假设要生成64位的数字指纹,也可以是其它数字),
// 对每一个分词hash后的数列进行判断,如果是1000...1,那么数组的第一位和末尾一位加1,
// 中间的62位减一,也就是说,逢1加1,逢0减1.一直到把所有的分词hash数列全部判断完毕.
int weight = 1; // 添加权重
if (weightOfNature.containsKey(nature)) {
weight = weightOfNature.get(nature);
}
if (t.and(bitmask).signum() != 0) {
// 这里是计算整个文档的所有特征的向量和
v[i] += weight;
} else {
v[i] -= weight;
}
}
}
BigInteger fingerprint = new BigInteger("0");
for (int i = 0; i < 64; i++) {
if (v[i] >= 0) {
fingerprint = fingerprint.add(new BigInteger("1").shiftLeft(i));
}
}
return fingerprint;
}
/**
* 计算海明距离,海明距离越小说明字符串内容越相似
*
* @param str1Hash 字符串1的hash值
* @param str2Hash 字符串2的hash值
* @return 海明距离
*/
private static int computeHammingDistance(BigInteger str1Hash, BigInteger str2Hash) {
BigInteger m = new BigInteger("1")
.shiftLeft(64) //hash位数
.subtract(new BigInteger("1"));
//xor运算
BigInteger x = str1Hash.xor(str2Hash).and(m);
int tot = 0;
while (x.signum() != 0) {
tot += 1;
x = x.and(x.subtract(new BigInteger("1")));
}
return tot;
}
/**
* 求2个长文本字符串的内容相似度百分比
*
* @param s1 String
* @param s2 String
* @return double 文本相似度百分比
*/
public static double getSemblance(String s1, String s2) {
StopWatch sw1 = StopWatch.create("c1");
sw1.start();
BigInteger str1Hash = computeStrHash(s1);
System.out.println("字符串1的hash值" + str1Hash);
BigInteger str2Hash = computeStrHash(s2);
System.out.println("字符串2的hash值" + str2Hash);
sw1.stop();
System.out.println("字符串hash计算耗时" + sw1.getTotalTimeMillis());
double i = (double) computeHammingDistance(str1Hash, str2Hash);
return 1 - i / 64;
}
/**
* 利用ansj框架 提取文本里的关键词 或 摘要
*
* @param strContent String
* @return String
*/
public static String getKeyWords(String strContent) {
String strReturn = "";
//限制关键词长度300词
SummaryComputer summaryComputer = new SummaryComputer(300, "",
strContent);
Summary summary = summaryComputer.toSummary();
//提取出的关键词列表
List<Keyword> strKeylist = summary.getKeyWords();
for (int i = 0; i < strKeylist.size(); ++i) {
if (i == 0) {
strReturn = String.format("%s%s", strReturn, strKeylist.get(i).getName());
} else {
strReturn = String.format("%s、%s", strReturn, strKeylist.get(i).getName());
}
}
return strReturn;
}
public static void main(String[] args) {
StopWatch stopWatch = StopWatch.create("t1");
stopWatch.start();
String s1 = "腾讯首款回合MMO手游大作《梦幻诛仙(微博)》超多内容强势爆料,在近期成为了游戏圈的一大热点。现又有消息称《梦幻诛仙》手游即将公开自己的游戏主题曲,谁将代表这款经典之作,唱响诛仙情缘,也成了玩家间热议的话题。从小说到电视剧,从端游再到如今的手游,诛仙热还将继续,谁将成为众望所归的演唱者呢?手Q兴趣部落更多组图谁将献唱梦幻诛仙 玩家猜想不二人选《梦幻诛仙》手游作为一款基于诛仙小说以及同名端游改编的移动游戏,2D回合制MMORPG玩法也很符合许多玩家的胃口。而近期《梦幻诛仙》宣布即将公开自己的游戏主题曲,谁将受邀演唱手游主题曲也吊住了玩家们的胃口。诛仙仙气十足的故事内核,搭配上古风古韵的音乐主题,女歌手演唱主题曲似乎是一个很好的选择,而演唱近期诛仙IP电视剧青云志片尾曲《时光笔墨》的张碧晨,就成了许多玩家心中的不二人选。张碧晨的气质与仙侠风契合,并多次受邀演唱电视剧古风曲目,且凭借好声音夺冠在内地乐坛人气颇高,如果张碧晨能携手《梦幻诛仙》发声,相信也会是场不错的视听体验。音乐才子是否助力 男歌手选择有点说完了女歌手,再说说男歌手。如果《梦幻诛仙》想邀请一个男歌手进行这次的主题曲创作,玩家们心中的答案又会是谁呢?回顾近些年热门IP音乐产品的创作史,大陆创作奇才汪苏泷可谓是炙手可热。汪苏泷可算是大热影视剧OST的承包户,《花千骨》、《微微一笑很倾城》等热门电视剧的音乐创作均有他的身影,而他创作的《年轮》更是登顶QQ音乐7周,由他创作演唱的《微微一笑很倾城》插曲《下一秒》近期还登陆了各大榜单前三,也让他再度进入了大家的视野。结合之前预测的女歌手张碧晨,两者的契合度也非常高,合作推出的两首歌曲均有不俗的成绩,如果能再度合作为《梦幻诛仙》发声,相信也会带来不小的惊喜。更多候选引发热议 手游发声悬念重重除了上述说到的张碧晨和汪苏泷,曾为《梦幻诛仙》端游版本演唱过歌曲的胡歌,亦或近期诛仙电视剧中的男主角新晋小生李易峰,还有曾为诛仙游戏演唱过单曲的任贤齐,也纷纷在玩家们的猜想名单之列。诛仙这个有多年情怀底蕴的热门IP,凭借电视剧在近期掀起的诛仙热潮,也让《梦幻诛仙》手游的一举一动牵动着玩家们的心。无论最终会是谁为《梦幻诛仙》手游演唱主题曲,相信都会让诛仙情缘再度绽放,让玩家们的青春跨越时空,在全新的游戏世界中随着音乐苏醒。“下一回合,遇见不凡”。《梦幻诛仙》手游移植移动平台,在传承经典玩法的同时,游戏主题曲的公开倒计时,也为玩家们留足了悬念,究竟最终谁将唱响诛仙情缘,敬请玩家们拭目以待。获取梦幻诛仙最新资讯动态,请登录梦诛官网:http://mhzx.qq.com ,或扫描下方二维码,即刻关注《梦幻诛仙》手游微信公众号和手Q兴趣部落。";
String s2 = "【重磅新闻】腾讯首款回合MMO手游大作《梦幻诛仙(微博)》超多内容强势爆料,在近期成为了游戏圈的一大热点。现又有消息称《梦幻诛仙》手游即将公开自己的游戏主题曲,谁将代表这款经典之作,唱响诛仙情缘,也成了玩家间热议的话题。从小说到电视剧,从端游再到如今的手游,诛仙热还将继续,谁将成为众望所归的演唱者呢?手Q兴趣部落更多组图谁将献唱梦幻诛仙 玩家猜想不二人选《梦幻诛仙》手游作为一款基于诛仙小说以及同名端游改编的移动游戏,2D回合制MMORPG玩法也很符合许多玩家的胃口。而近期《梦幻诛仙》宣布即将公开自己的游戏主题曲,谁将受邀演唱手游主题曲也吊住了玩家们的胃口。诛仙仙气十足的故事内核,搭配上古风古韵的音乐主题,女歌手演唱主题曲似乎是一个很好的选择,而演唱近期诛仙IP电视剧青云志片尾曲《时光笔墨》的张碧晨,就成了许多玩家心中的不二人选。张碧晨的气质与仙侠风契合,并多次受邀演唱电视剧古风曲目,且凭借好声音夺冠在内地乐坛人气颇高,如果张碧晨能携手《梦幻诛仙》发声,相信也会是场不错的视听体验。音乐才子是否助力 男歌手选择有点说完了女歌手,再说说男歌手。如果《梦幻诛仙》想邀请一个男歌手进行这次的主题曲创作,玩家们心中的答案又会是谁呢?回顾近些年热门IP音乐产品的创作史,大陆创作奇才汪苏泷可谓是炙手可热。汪苏泷可算是大热影视剧OST的承包户,《花千骨》、《微微一笑很倾城》等热门电视剧的音乐创作均有他的身影,而他创作的《年轮》更是登顶QQ音乐7周,由他创作演唱的《微微一笑很倾城》插曲《下一秒》近期还登陆了各大榜单前三,也让他再度进入了大家的视野。结合之前预测的女歌手张碧晨,两者的契合度也非常高,合作推出的两首歌曲均有不俗的成绩,如果能再度合作为《梦幻诛仙》发声,相信也会带来不小的惊喜。更多候选引发热议 手游发声悬念重重除了上述说到的张碧晨和汪苏泷,曾为《梦幻诛仙》端游版本演唱过歌曲的胡歌,亦或近期诛仙电视剧中的男主角新晋小生李易峰,还有曾为诛仙游戏演唱过单曲的任贤齐,也纷纷在玩家们的猜想名单之列。诛仙这个有多年情怀底蕴的热门IP,凭借电视剧在近期掀起的诛仙热潮,也让《梦幻诛仙》手游的一举一动牵动着玩家们的心。无论最终会是谁为《梦幻诛仙》手游演唱主题曲,相信都会让诛仙情缘再度绽放,让玩家们的青春跨越时空,在全新的游戏世界中随着音乐苏醒。“下一回合,遇见不凡”。《梦幻诛仙》手游移植移动平台,在传承经典玩法的同时,游戏主题曲的公开倒计时,也为玩家们留足了悬念,究竟最终谁将唱响诛仙情缘,敬请玩家们拭目以待。获取梦幻诛仙最新资讯动态,请登录梦诛官网:http://mhzx.qq.com ,或扫描下方二维码,即刻关注《梦幻诛仙》手游微信公众号和手Q兴趣部落。";
System.out.println("两段文本的相似度:" + getSemblance(s1, s2));
stopWatch.stop();
System.out.println("相似度计算程序总耗时:" + stopWatch.getTotalTimeMillis());
StopWatch sw3 = StopWatch.create("t2");
sw3.start();
System.out.println("提取文本s1里的关键词:" + getKeyWords(s1));
System.out.println("提取文本s2里的关键词:" + getKeyWords(s2));
sw3.stop();
System.out.println("关键词提取程序耗时:" + sw3.getTotalTimeMillis());
}
}
在maven项目根目录下的library目录里
配置
ambiguity.dic
default.dic
regex.dic
stop.dic
synonyms.dic
字符串1的hash值14366090094003174383
字符串2的hash值14366090094003172335
字符串hash计算耗时1295
两段文本的相似度:0.984375
相似度计算程序总耗时:1297
19:02:38.955 [main] WARN org.ansj.util.MyStaticValue - not find library.properties in classpath use it by default !
19:02:38.963 [main] INFO org.ansj.dic.impl.File2Stream - path to stream library/ambiguity.dic
19:02:38.964 [main] DEBUG org.ansj.library.AmbiguityLibrary - begin init ambiguity
19:02:38.969 [main] INFO org.ansj.library.AmbiguityLibrary - load dic use time:5 path is : library/ambiguity.dic
19:02:38.970 [main] DEBUG org.ansj.library.DicLibrary - begin init dic !
19:02:38.970 [main] INFO org.ansj.dic.impl.File2Stream - path to stream library/default.dic
19:02:39.808 [main] INFO org.ansj.library.DicLibrary - load dic use time:838 path is : library/default.dic
19:02:39.811 [main] DEBUG org.ansj.library.CrfLibrary - begin init crf model!
19:02:41.883 [main] INFO org.ansj.app.crf.Model - load crf model ok ! use time :2065
19:02:41.884 [main] INFO org.ansj.library.CrfLibrary - load crf use time:2073 path is : jar://crf.model
19:02:42.766 [main] INFO org.ansj.library.DATDictionary - init core library ok use time : 790
19:02:43.166 [main] INFO org.ansj.library.NgramLibrary - init ngram ok use time :394
提取文本s1里的关键词:诛仙、手游、梦幻、主题曲、张碧晨、端游、游戏、演唱、男歌手、热议
提取文本s2里的关键词:诛仙、手游、梦幻、主题曲、张碧晨、端游、游戏、演唱、男歌手、热议
关键词提取程序耗时:8290