简介:通过IK分词器分词并生成词云。

本文主要介绍如何通过 IK 分词器进行词频统计。使用分词器对文章的词频进行统计,主要目的是实现如下图所示的词云功能,可以找到文章内的重点词汇。后续也可以对词进行词性标注,实体识别以及对实体的情感分析等功能。

词频统计服务具体模块如下:

数据输入:文本信息

数据输出:词 - 词频(TF-IDF等) - 词性等内容

使用的组件:分词器、语料库、词云展示组件等

功能点:白名单,黑名单,同义词等

现存的中文分词器有 IK、HanLP、jieba 和 NLPIR 等几种,不同分词器各有特点,本文使用 IK 实现,因为 ES 一般使用 medcl 等大佬封装的 IK 分词器插件作为中文分词器。

由于 ES 的 IK 分词器插件深度结合了 ES,仅对文本分词使用不到 ES 的内容,所以文本采用申艳超大佬版本的 IK

1. IK 分词统计代码

IK 的代码相对比较简单,东西不多,将 String 拆分为词并统计代码如下:

  1. 单纯统计词频:
/**
* 全文本词频统计
*
* @param content 文本内容
* @param useSmart 是否使用 smart
* @return 词,词频
* @throws IOException
*/
private static Map<String, Integer> countTermFrequency(String content, Boolean useSmart) throws IOException {
// 输出结果 Map
Map<String, Integer> frequencies = new HashMap<>();
if (StringUtils.isBlank(content)) {
return frequencies;
}
DefaultConfig conf = new DefaultConfig();
conf.setUseSmart(useSmart);
// 使用 IKSegmenter 初始化文本信息并加载词典
IKSegmenter ikSegmenter = new IKSegmenter(new StringReader(content), conf);
Lexeme lexeme;
while ((lexeme = ikSegmenter.next()) != null) {
if (lexeme.getLexemeText().length() > 1) {// 过滤单字,也可以过滤其他内容,如数字和单纯符号等内容
final String term = lexeme.getLexemeText();
// Map 累加操作
frequencies.compute(term, (k, v) -> {
if (v == null) {
v = 1;
} else {
v += 1;
}
return v;
});
}
}
return frequencies;
}

  1. 统计词频和文档频率:
/**
* 文本列表词频和词文档频率统计
*
* @param docs 文档列表
* @param useSmart 是否使用只能分词
* @return 词频列表 词-[词频,文档频率]
* @throws IOException
*/
private static Map<String, Integer[]> countTFDF(List<String> docs, boolean useSmart) throws IOException {
// 输出结果 Map
Map<String, Integer[]> frequencies = new HashMap<>();
for (String doc : docs) {
if (StringUtils.isBlank(doc)) {
continue;
}
DefaultConfig conf = new DefaultConfig();
conf.setUseSmart(useSmart);
// 使用 IKSegmenter 初始化文本信息并加载词典
IKSegmenter ikSegmenter = new IKSegmenter(new StringReader(doc), conf);
Lexeme lexeme;
// 用于文档频率统计的 Set
Set<String> terms = new HashSet<>();
while ((lexeme = ikSegmenter.next()) != null) {
if (lexeme.getLexemeText().length() > 1) {
final String text = lexeme.getLexemeText();
// 进行词频统计
frequencies.compute(text, (k, v) -> {
if (v == null) {
v = new Integer[]{1, 0};
} else {
v[0] += 1;
}
return v;
});
terms.add(text);
}
}
// 进行文档频率统计:无需初始化 Map,统计词频后 Map 里面必有该词记录
for (String term : terms) {
frequencies.get(term)[1] += 1;
}
}
return frequencies;
}

2. 获取词云 TopN 个词

获取 TopN 个词用于词云展示有多种排序方式,可以直接根据词频、文档频率或者 TF-IDF 等算法进行排序,本文仅根据词频求取 TopN。

M 个数字获取 TopN 有以下算法:

  • M 小 N 小:快速选择算法
  • M 大 N 小:小顶堆
  • M 大 N 大:归并排序

本文采用小顶堆方式实现,对应JAVA中的优先队列数据结构 PriorityQueue:

/**
* 按出现次数,从高到低排序取 TopN
*
* @param data 词和排序数字对应的 Map
* @param TopN 词云展示的 TopN
* @return 前 N 个词和排序值
*/
private static List<Map.Entry<String, Integer>> order(Map<String, Integer> data, int topN) {
PriorityQueue<Map.Entry<String, Integer>> priorityQueue = new PriorityQueue<>(data.size(), new Comparator<Map.Entry<String, Integer>>() {
@Override
public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
return o2.getValue().compareTo(o1.getValue());
}
});
for (Map.Entry<String, Integer> entry : data.entrySet()) {
priorityQueue.add(entry);
}
//TODO 当前100词频一致时(概率极低)的处理办法,if( list(0).value == list(99).value ){xxx}
List<Map.Entry<String, Integer>> list = new ArrayList<>();
//统计结果队列size和topN值取较小值列表
int size = priorityQueue.size() <= topN ? priorityQueue.size() : topN;
for (int i = 0; i < size; i++) {
list.add(priorityQueue.remove());
}
return list;
}

3. IK 代码浅析

核心主类为IKSegmenter,需要关注的点有dic包也就是词典相关内容以及字符处理工具类CharacterUtilidentifyCharType()方法,目录结构如下:

IKSegmenter类结构如下图,其中 init() 为私有方法,初始化加载词典采用非懒加载模式,在第一次初始化IKSegmenter实例时会调用并加载词典,代码位于结构图下方。

// IKSegmenter 类构造方法
public IKSegmenter(Reader input, Configuration cfg) {
this.input = input;
this.cfg = cfg;
this.init();
}
// IKSegmenter 类初始化
private void init() {
//初始化词典单例
Dictionary.initial(this.cfg);
//初始化分词上下文
this.context = new AnalyzeContext(this.cfg);
//加载子分词器
this.segmenters = this.loadSegmenters();
//加载歧义裁决器
this.arbitrator = new IKArbitrator();
} // Dictionary 类初始化词典
public static Dictionary initial(Configuration cfg) {
if (singleton == null) {
synchronized (Dictionary.class) {
if (singleton == null) {
singleton = new Dictionary(cfg);
return singleton;
}
}
}
return singleton;
}

词典私有构造方法Dictionary()内会加载 IK 自带的词典以及扩展词典,我们也可以把自己线上不变的词典放到这里这样IKAnalyzer.cfg.xml中就只需要配置经常变更词典即可。

private Dictionary(Configuration cfg) {
this.cfg = cfg;
this.loadMainDict();// 主词典以及扩展词典
this.loadmiaozhenDict();// 自定义词典加载,仿照其他方法即可
this.loadStopWordDict();// 扩展停词词典
this.loadQuantifierDict();// 量词词典
}

IKSegmenter类调用next()方法获取下一个词元时,会调用CharacterUtil类中的identifyCharType()方法识别字符种类,这里我们也可以自定义一些字符种类针对处理新兴的网络语言,如@、##等内容:

static int identifyCharType(char input) {
if (input >= '0' && input <= '9') {
return CHAR_ARABIC;
} else if ((input >= 'a' && input <= 'z') || (input >= 'A' && input <= 'Z')) {
return CHAR_ENGLISH;
} else {
Character.UnicodeBlock ub = Character.UnicodeBlock.of(input);
//caster 增加#为中文字符
if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
|| ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
|| ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A ||input=='#') {
//目前已知的中文字符UTF-8集合
return CHAR_CHINESE; } else if (ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS //全角数字字符和日韩字符
//韩文字符集
|| ub == Character.UnicodeBlock.HANGUL_SYLLABLES
|| ub == Character.UnicodeBlock.HANGUL_JAMO
|| ub == Character.UnicodeBlock.HANGUL_COMPATIBILITY_JAMO
//日文字符集
|| ub == Character.UnicodeBlock.HIRAGANA //平假名
|| ub == Character.UnicodeBlock.KATAKANA //片假名
|| ub == Character.UnicodeBlock.KATAKANA_PHONETIC_EXTENSIONS) {
return CHAR_OTHER_CJK; }
}
//其他的不做处理的字符
return CHAR_USELESS;
}

由于 IK 内容不多,建议大家可以从头捋一遍,包括各个实现ISegmenter接口的各个自分词器等内容。

4. 进行词云展示

词云展示可以使用 Kibana 自带的词云 Dashboard,或者比较热门的 WordCloud。自己测试可以使用线上的微词云快速便捷查看词云效果:导入两列的 XLS 文件即可,左侧控制栏也可以对形状字体等进行配置美化。

展示效果如下图所示:

5. 总结

本文主要通过 IK 分词器实现了词频统计功能,用于词云的展示,不仅仅适用于 ES,任何数据源文档都可以进行词频统计。但是功能比较基础,感兴趣的同学可以实现一下词排序方式变更(tf/idf)、词性标注、实体识别和情感分析等功能;IK 分词器较为局限,需要使用 HanLP(自带词性标注)等更高级的分词器以及 NLP 相关知识来辅助,也可以参考百度 AI 的词法分析模块。

原文链接

本文为阿里云原创内容,未经允许不得转载。

es实战-使用IK分词器进行词频统计的更多相关文章

  1. es的插件 ik分词器的安装和使用

    今天折腾了一天,在es 5.5.0 上安装ik.一直通过官方给定的命令没用安装成功,决定通过手工是形式进行安装.https://github.com/medcl/elasticsearch-analy ...

  2. Elasticsearch入门之从零开始安装ik分词器

    起因 需要在ES中使用聚合进行统计分析,但是聚合字段值为中文,ES的默认分词器对于中文支持非常不友好:会把完整的中文词语拆分为一系列独立的汉字进行聚合,显然这并不是我的初衷.我们来看个实例: POST ...

  3. Linux安装ElasticSearch7.X & IK分词器

    前言 安装ES之前,请先检查JDK版本,es使用java编写,强依赖java环境.JDK安装过程略. 安装步骤 1.下载地址 点击这里下载7.2.0 2.解压elasticsearch-7.2.0-l ...

  4. ES系列一、CentOS7安装ES 6.3.1、集成IK分词器

    Elasticsearch 6.3.1 地址: wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.3. ...

  5. 安装ik分词器以及版本和ES版本的兼容性

    一.查看自己ES的版本号与之对应的IK分词器版本 https://github.com/medcl/elasticsearch-analysis-ik/blob/master/README.md 二. ...

  6. es之IK分词器

    1:默认的分析器-- standard 使用默认的分词器 curl -XGET 'http://hadoop01:9200/_analyze?pretty&analyzer=standard' ...

  7. ES ik分词器使用技巧

    match查询会将查询词分词,然后对分词的结果进行term查询. 然后默认是将每个分词term查询之后的结果求交集,所以只要分词的结果能够命中,某条数据就可以被查询出来,而分词是在新建索引时指定的,只 ...

  8. Elasticsearch5.1.1+ik分词器+HEAD插件安装小记

    一.安装elasticsearch 1.首先需要安装好java,并配置好环境变量,详细教程请看 http://tecadmin.net/install-java-8-on-centos-rhel-an ...

  9. elasticsearch 之IK分词器安装

    IK分词器地址:https://github.com/medcl/elasticsearch-analysis-ik 安装好ES之后就可以安装分词器插件了 记住选择ES对应的版本 对应的有版本选择下载 ...

  10. 如何开发自己的搜索帝国之安装ik分词器

     Elasticsearch默认提供的分词器,会把每个汉字分开,而不是我们想要的根据关键词来分词,我是中国人 不能简单的分成一个个字,我们更希望 “中国人”,“中国”,“我”这样的分词,这样我们就需要 ...

随机推荐

  1. python面向对象(基础)

    一 面向对象介绍 面向过程: 核心是:"过程"二字 过程的终极奥义就是将程序流程化 过程是"流水化",用来分步骤解决问题的 面向对象: 核心是"对象& ...

  2. 关于volatile与指令重排序的探讨

    写在开头 在之前的学习我们了解到,为了充分利用缓存,提高程序的执行速度,编译器在底层执行的时候,会进行指令重排序的优化操作,但这种优化,在有些时候会带来 有序性 的问题. 那何为有序性呢?我们可以通俗 ...

  3. 高防dns和高防IP一样吗?

    高防DNS和高防IP一样吗? 高防DNS和高防IP在功能和目标上有所不同,因此它们并不完全相同. 高防DNS是一种针对DNS服务的防护措施,旨在保护域名解析免受DDoS攻击等网络威胁的影响.它利用高防 ...

  4. WARN o.a.t.util.scan.StandardJarScanner - Failed to scan [file:/D:/Mavencangku/com/sun/xml/bind/jaxb-core/2.3.0/jaxb-api.jar] from classloader hierarchy

    1.SpringBoot项目启动突然报错 2024-03-27 14:57:41 [restartedMain] WARN o.a.t.util.scan.StandardJarScanner - F ...

  5. 国民经济行业分类与代码(GB/T 4754-2017、GB/T 4754-2011、GB/T 4754-2002)数据下载

    2002_2011_2017国民经济行业分类与代码mysql数据四级分类文件.rar 内容:其中包含2002.2011.2017三年国民经济行业分类和代码的MySQL文件,每一个表的格式如下:例如第一 ...

  6. 通过位运算修改指定bit位的值

    通过位运算将指定位的值置0或1 问题样例 假如现在有一个8bit二进制数A,其可以为任何值,所以这里不妨先设A=(xxxxxxxx)2,{x|0,1} 现在需要你将A的几个指定位修改为1或0,例如将A ...

  7. 3个.NET开源、免费、强大的商城系统

    前言 今天大姚给大家分享3个.NET开源.免费.强大的商城系统,希望可以帮助到有商城系统开发需求的同学. nopCommerce nopCommerce是一个功能丰富.免费.灵活且可定制的开源电子商务 ...

  8. OpenHarmony加速行业应用落地,多款软件发行版正通过兼容性测评

    4 月 25 日,OpenAtom OpenHarmony(以下简称"OpenHarmony")技术日在深圳举办,大会聚焦 OpenHarmony 3.1 Release 版本核心 ...

  9. 如何利用OpenHarmony ArkUI的Canvas组件实现涂鸦功能?

    简介 ArkUI是一套UI开发框架,提供了开发者进行应用UI开发时所需具备的能力.随着OpenAtom OpenHarmony(以下简称"OpenHarmony")不断更新迭代,A ...

  10. 国产Linux发行版 Deepin 评价与主观展望 我与Deepin的故事

    全文皆属于up自己的主观臆断,有不到之处可以进行批评,共同成长. P1 编辑时间(2021-2-20) 昨天,我刷b站的时候见到一则旧闻,关于我国操作系统的.原本只是想写个1000字左右的评论的,没想 ...