【中文分词】简单高效的MMSeg
最近碰到一个分词匹配需求——给定一个关键词表,作为自定义分词词典,用户query文本分词后,是否有词落入这个自定义词典中?现有的大多数Java系的分词方案基本都支持添加自定义词典,但是却不支持HDFS路径的。因此,我需要寻找一种简单高效的分词方案,稍作包装即可支持HDFS。MMSeg分词算法正是完美地契合了这种需求。
1. MMseg简介
MMSeg是蔡志浩(Chih-Hao Tsai)提出的基于字符串匹配(亦称基于词典)的中文分词算法。基于词典的分词方案无法解决歧义问题,比如,“武汉市长江大桥”是应分词“武汉/市长/江大桥”还是“武汉市/长江/大桥”。基于此,有人提出了正向最大匹配策略,但是可能会出现分词错误的情况,比如:若词典中有“武汉市长”,则原句被分词成“武汉市长/江大桥”。单纯的最大匹配还是无法完美地解决歧义,因而MMSeg在正向最大匹配的基础上设计了四个启发式规则。isnowfy大神的《浅谈中文分词》对于各种主流的分词算法做了精辟的论述。
MMSeg的字符串匹配算法分为两种:
- Simple,简单的正向最大匹配,即按能匹配上的最长词做切分;
- Complex,在正向最大匹配的基础上,考虑相邻词的词长,设计了四个去歧义规则(Ambiguity Resolution Rules)指导分词。
在complex分词算法中,MMSeg将切分的相邻三个词作为词块(chunk),应用如下四个消歧义规则:
- 备选词块的长度最大(Maximum matching),即三个词的词长之和最大;
- 备选词块的平均词长最大(Largest average word length),即要求词长分布尽可能均匀;
- 备选词块的词长变化最小(Smallest variance of word lengths );
- 备选词块中(若有)单字的出现词自由度最高(Largest sum of degree of morphemic freedom of one-character words)。
这篇文章《mmseg分词算法及实现》对于这四个规则做了更为细致的介绍,本文无再赘言了。
2. 实战
MMSeg的Java实现有mmseg4j,本地路径添加自定义词典分词:
String txt = "在一起并发生了中文分词.";
// user-defined dictionary parent-path
Dictionary dic = Dictionary.getInstance("src\\resources\\dict");
Seg seg = new ComplexSeg(dic);
MMSeg mmSeg = new MMSeg(new StringReader(txt), seg);
Word word = null;
while ((word = mmSeg.next()) != null) {
System.out.print(word + "|");
}
mmseg4j("com.chenlb.mmseg4j" % "mmseg4j-core" % "1.10.0")没有wiki,通过分析源码才知道getInstance方法的路径参数应是父目录,并且词典文件的命名应符合规范:chars.dic(单字词表)、wordsXXX.dic(词长>1词表)。mmseg4j所加载的分词词典为类Dictionary数据成员Map<Character, CharNode> dict,其中Character为词的首字,CharNode是一棵trie树,存储拥有共同前缀(首字)的词。loadWord方法为加载自定义词表。
基于上面的代码分析,封装添加HDFS路径词典的Scala代码如下:
import com.chenlb.mmseg4j.CharNode
import org.apache.hadoop.conf.Configuration
import org.apache.hadoop.fs.{FSDataInputStream, FileSystem, Path}
import scala.io.Source
/**
* @author rain
*/
object MMSegUtil {
// str[1:-1], the last len(str)-1 characters
def tail(str: String): Array[Char] = {
str.toCharArray.takeRight(str.length - 1)
}
// load user-define word dictionary
def loadWord(path: String, dic: java.util.Map[Character, CharNode]) = {
val fs = FileSystem.get(new Configuration)
val in: FSDataInputStream = fs.open(new Path(path))
Source.fromInputStream(in).getLines()
.filter(_.length > 1)
.foreach { line =>
val cn: CharNode = dic.get(line.charAt(0))
cn match {
case null => dic.put(line.charAt(0), cn)
case _ => cn.addWordTail(tail(line))
}
}
}
}
即可在Spark程序中调用分词:
val dictionary = Dictionary.getInstance()
MMSegUtil.loadWord(dicPath, dictionary.getDict)
val seg = new ComplexSeg(dictionary)
值得指出,ComplexSeg类有List remove操作,因而不适于做成广播变量,不然则报ConcurrentModificationException。推荐的做法,配合RDD的mapPartitions在for yield外层new ComplexSeg;相当于每个Partition都有一个ComplexSeg。
mmseg4j存在分词不准确的情况,比如,『培养并发挥热忱的特性』被分词成『培养/并发/挥/热忱/的/特性』。这是因为mmseg4j的chars词典中,挥 20429的词频高于并 2789(针对于MMSeg的规则4)。基于词典的分词方案的准确性,严重依赖于词典;必须要有好的词典,才会有好的分词结果。
【中文分词】简单高效的MMSeg的更多相关文章
- crf++实现中文分词简单例子 (Windows crf++0.58 python3)
学习自然语言处理的同学都知道,条件随机场(crf)是个好东西.虽然它的原理确实理解起来有点困难,但是对于我们今天用到的这个crf工具crf++,用起来却是挺简单方便的. 今天只是简单试个水,参考别人的 ...
- Sphinx+MySQL5.1x+SphinxSE+mmseg中文分词
什么是Sphinx Sphinx 是一个全文检索引擎,一般而言,Sphinx是一个独立的搜索引擎,意图为其它应用提供快速.低空间占用.高结果相关度的全文搜索功能.Sphinx能够很easy的与SQL数 ...
- Python环境下NIPIR(ICTCLAS2014)中文分词系统使用攻略
一.安装 官方链接:http://pynlpir.readthedocs.org/en/latest/installation.html 官方网页中介绍了几种安装方法,大家根据个人需要,自行参考!我采 ...
- NLP舞动之中文分词浅析(一)
一.简介 针对现有中文分词在垂直领域应用时,存在准确率不高的问题,本文对其进行了简要分析,对中文分词面临的分词歧义及未登录词等难点进行了介绍,最后对当前中文分词实现的算法原理(基于词表. ...
- 关于Solr搜索标点与符号的中文分词你必须知道的(mmseg源码改造)
关于Solr搜索标点与符号的中文分词你必须知道的(mmseg源码改造) 摘要:在中文搜索中的标点.符号往往也是有语义的,比如我们要搜索“C++”或是“C#”,我们不希望搜索出来的全是“C”吧?那样对程 ...
- 基于MMSeg算法的中文分词类库
原文:基于MMSeg算法的中文分词类库 最近在实现基于lucene.net的搜索方案,涉及中文分词,找了很多,最终选择了MMSeg4j,但MMSeg4j只有Java版,在博客园上找到了*王员外*(ht ...
- Mmseg中文分词算法解析
Mmseg中文分词算法解析 @author linjiexing 开发中文搜索和中文词库语义自己主动识别的时候,我採用都是基于mmseg中文分词算法开发的Jcseg开源project.使用场景涉及搜索 ...
- scws简单中文分词
demo如下: /** * 中文分词 * @param $keyword * @param $getTop * @param $limit * @return array */ function sp ...
- 30.IK中文分词器的安装和简单使用
在之前我们学的都是英文,用的也是英文的standard分词器.从这一节开始,学习中文分词器.中国人基本上都是中文应用,很少是英文的,而standard分词器是没有办法对中文进行合理分词的,只是将每个中 ...
随机推荐
- 学习笔记:因为java匿名类学习到接口的一些小用法
在看CometD的示例代码时发现了许多有意思的代码,但说实话看别人的代码确实是件很累的事情,所以就看到这个知识点做一下记录吧. 先看一段代码: 代码1 这段代码中有一个new的操作,而且是在方 ...
- Union-Find 检测无向图有无环路算法
不相交集合数据结构(Disjoint-set data structure)是一种用于跟踪集合被分割成多个不相交的子集合的数据结构,每个集合通过一个代表来标识,代表即集合中的某个成员. Union-F ...
- Hadoop学习笔记—15.HBase框架学习(基础知识篇)
HBase是Apache Hadoop的数据库,能够对大型数据提供随机.实时的读写访问.HBase的目标是存储并处理大型的数据.HBase是一个开源的,分布式的,多版本的,面向列的存储模型,它存储的是 ...
- ASP.NET MVC 路由(二)
ASP.NET MVC路由(二) 前言 在上一篇中,提及了Route.RouteCollection对象的一些信息,以及它们的结构所对应的关系.按照处理流程走下来还有遗留的疑问没有解决这个篇幅就来讲 ...
- [Unity][Heap sort]用Unity动态演示堆排序的过程(How Heap Sort Works)
[Unity][Heap sort]用Unity动态演示堆排序的过程 How Heap Sort Works 最近做了一个用Unity3D动态演示堆排序过程的程序. I've made this ap ...
- 如何使用Worktile进行敏捷项目开发管理
Worktile在任务管理上采用了看板视图,非常适合进行敏捷项目开发管理.事实上,在开发Worktile的过程中,我们也是自产自销,使用Worktile管理Worktile本身的开发过程,在本文中跟大 ...
- Module Zero之角色管理
返回<Module Zero学习目录> 角色实体 角色管理者 多租户 角色实体 角色实体代表了该应用的一个角色.它应该派生自AbpRole类,如下所示: public class Role ...
- UIColor 使用起来的坑
我们一般会用 UIColor 的RGB来生成颜色: [UIColor colorWithRed:220/255 green:220/255 blue:220/255 alpha:1.0];//这样生成 ...
- 防止SQL注入攻击
了解了SQL注入的方法,如何能防止SQL注入?如何进一步防范SQL注入的泛滥?通过一些合理的操作和配置来降低SQL注入的危险. 使用参数化的过滤性语句 要防御SQL注入,用户的输入就绝对不能直接被嵌入 ...
- 兼容各浏览器的js判断上传文件大小
由于项目需要,在网上找了一个JS判断上传文件大小的程序,经测试兼容IE6-,Firefox10,Opera11.,safari5.,chrome17 <!DOCTYPE html> < ...