内容提要

  • 1 分词概述
  • 2 算法分类
    • 2.1 字符匹配
    • 2.2 理解法
    • 2.3 统计法
  • 3 常见项目
  • 4 知更鸟分词实现
    • 4.1 算法描述
    • 4.2 数据结构
    • 4.3 部分代码
    • 4.4 运行结果
  • 5 对比验证
    • 5.1 分词速度对比
    • 5.2 分词结果对比
  • 6 总结

  本文设计了一种带逆向回退策略的正向最大匹配。

1 分词概述

  英文文本的处理相对简单,每一个单词之间有空格或标点符号隔开。如果不考虑短语,仅以单词作为唯一的语义单元的话,处理英文单词切分相对简单,只需要分类多有单词,去除标点符号。中文自然语言处理首先要解决的难题就是中文分词技术。
  中文分词(Chinese Word Segmentation) 指的是将一个汉字序列切分成一个个单独的词。分词就是将连续的字序列按照一定的规范重新组合成词序列的过程。

2 算法分类

  现有的分词算法可分为三大类:基于字符串匹配的分词方法、基于理解的分词方法和基于统计的分词方法。按照是否与词性标注过程相结合,又可以分为单纯分词方法和分词与标注相结合的一体化方法。

2.1 字符匹配

  这种方法又叫做机械分词方法,它是按照一定的策略将待分析的汉字串与一个“充分大的”机器词典中的词条进行配,若在词典中找到某个字符串,则匹配成功(识别出一个词)。按照扫描方向的不同,串匹配分词方法可以分为正向匹配和逆向匹配;按照不同长度优先匹配的情况,可以分为最大(最长)匹配和最小(最短)匹配。
常用的几种机械分词方法如下:
  1)正向最大匹配法(由左到右的方向);
  2)逆向最大匹配法(由右到左的方向);
  3)最少切分(使每一句中切出的词数最小);
  4)双向最大匹配法(进行由左到右、由右到左两次扫描)

2.2 理解法

  这种分词方法是通过让计算机模拟人对句子的理解,达到识别词的效果。其基本思想就是在分词的同时进行句法、语义分析,利用句法信息和语义信息来处理歧义现象。它通常包括三个部分:分词子系统、句法语义子系统、总控部分。在总控部分的协调下,分词子系统可以获得有关词、句子等的句法和语义信息来对分词歧义进行判断,即它模拟了人对句子的理解过程。这种分词方法需要使用大量的语言知识和信息。由于汉语语言知识的笼统、复杂性,难以将各种语言信息组织成机器可直接读取的形式,因此目前基于理解的分词系统还处在试验阶段。

2.3 统计法

  从形式上看,词是稳定的字的组合,因此在上下文中,相邻的字同时出现的次数越多,就越有可能构成一个词。因此字与字相邻共现的频率或概率能够较好的反映成词的可信度。可以对语料中相邻共现的各个字的组合的频度进行统计,计算它们的互现信息。定义两个字的互现信息,计算两个汉字X、Y的相邻共现概率。互现信息体现了汉字之间结合关系的紧密程度。当紧密程度高于某一个阈值时,便可认为此字组可能构成了一个词。这种方法只需对语料中的字组频度进行统计,不需要切分词典,因而又叫做无词典分词法或统计取词方法。但这种方法也有一定的局限性,会经常抽出一些共现频度高、但并不是词的常用字组,例如“这一”、“之一”、“有的”、“我的”、“许多的”等,并且对常用词的识别精度差,时空开销大。实际应用的统计分词系统都要使用一部基本的分词词典(常用词词典)进行串匹配分词,同时使用统计方法识别一些新的词,即将串频统计和串匹配结合起来,既发挥匹配分词切分速度快、效率高的特点,又利用了无词典分词结合上下文识别生词、自动消除歧义的优点。

3 常见项目

极易分词(JE)
  MMAnalyzer极易中文分词组件,由中科院提供的中文极易分词器。比较完善的中文分词器。
  支持英文、数字、中文(简体)混合分词。
  常用的数量和人名的匹配。
  超过22万词的词库整理。
  实现正向最大匹配算法。

IKAnalyzer(IK)
  IKAnalyzer是一个开源的,基于java语言开发的轻量级的中文分词工具包。从2006年12月推出1.0版开始,IKAnalyzer已经推出了3个大版本。最初,它是以开源项目Luence为应用主体的,结合词典分词和文法分析算法的中文分词组件。新版本的IKAnalyzer3.0则发展为面向Java的公用分词组件,独立于Lucene项目,同时提供了对Lucene的默认优化实现。
Paoding(PD)
  Paoding(庖丁解牛分词)基于Java的开源中文分词组件,提供lucene和solr 接口,具有极 高效率和 高扩展性。引入隐喻,采用完全的面向对象设计,构思先进。
  高效率:在PIII 1G内存个人机器上,1秒可准确分词 100万汉字。
  采用基于不限制个数的词典文件对文章进行有效切分,使能够将对词汇分类定义。
  能够对未知的词汇进行合理解析。
  仅支持Java语言。
MMSEG4J(MS)
  MMSEG4J基于Java的开源中文分词组件,提供lucene和solr 接口:
  1.mmseg4j 用 Chih-Hao Tsai 的 MMSeg 算法实现的中文分词器,并实现 lucene 的 analyzer 和 solr 的TokenizerFactory 以方便在Lucene和Solr中使用。
  2.MMSeg 算法有两种分词方法:Simple和Complex,都是基于正向最大匹配。Complex 加了四个规则过虑。官方说:词语的正确识别率达到了 98.41%。mmseg4j 已经实现了这两种分词算法。
smallseg(SS)
  开源的,基于DFA的轻量级的中文分词工具包。
  特点:可自定义词典、切割后返回登录词列表和未登录词列表、有一定的新词识别能力。

4 知更鸟分词实现

  中文分词既然作为自然语言处理的基本工具,那么我们就来实现一个基于字符匹配的中文分词,用我的英文名(Robin)给她起个名字,就叫做——知更鸟分词器(RS/Robin-Segmenter)

4.1 算法描述

  基本实现算法:
  (1)正向最大匹配;
  (2)逆向最大匹配;
  (3)逆向回退策略的正向最大匹配(重点)。
  支持以下功能:

  • 新词发现、新词标注;
  • 字符转换、格式统一;
  • 自定义分割符;
  • 特殊符号保留;
  • 检索分词模式;
  • 合并拆分模式;

4.2 数据结构

  基于字典字符匹配匹配的分词算法,重点是字典数据结构的设计。好的字典数据结构能够极大提升匹配检索的效率。
  采用基本容器HashMap实现的一种变种字典树(Trie)结构。其基本的思想如图。

Trie树型结构之正向最大匹配过程

  假设词典:中国 | 中南海 | 人民 | 人民币 | 人情 | 银行 | 中国人民 | 中国人民银行 | 中国人寿保险 | ……
  例如:“中国人民银行行长易纲。”这样一条文本的匹配过程如图示红线路径。分词结果应该示“中国人民银行 行长 易纲”。
  由于中文词首字分布比较均匀,并且查询首字的概率远大于其他非首字,根节点采用map数组方式,数组下标为字符的Unicode码减去最小中文汉字 Unicode码。数组维度为汉字的Unicode码范围。

4.3 部分代码

Unicode工具类:

package com.robin.segment.robinseg;import com.robin.config.ConfigUtil;
import com.robin.file.FileUtil;
import java.util.HashSet;
import java.util.Set;/*** <DT><B>描述:</B></DT>* <DD>Unicode 编码工具类</DD>** @version Version1.0* @author Robin* @version <I> V1.0 Date:2018-01-28</I>* @author  <I> E-mail:xsd-jj@163.com</I>*/
public class Unicode {/** 量词配置路径 */private static final String QUANTIFIER_PATH;/** 量词集合 */private static Set<Character> quantifierSet;/** 中文数词路径 */private static final String NUMERAL_PATH;/** 中文数词集合 */private static Set<Character> numeralSet;/** 词典文件编码 */private static final String DIC_ENCODING;/** 空字符 Unicode */public static final int NULL = 0x0;/** 半角空格 Unicode */public static final int DBC_BLANK = 0x20;/** 半角句点 Unicode */public static final int DBC_POINT = 0x2E;/** 半角0 Unicode */public static final int DBC_0 = 0x30;/** 半角9 Unicode */public static final int DBC_9 = 0x39;/** 半角A Unicode */public static final int DBC_A = 0x41;/** 半角Z Unicode */public static final int DBC_Z = 0x5A;/** 半角a Unicode */public static final int DBC_LA = 0x61;/** 半角z Unicode */public static final int DBC_LZ = 0x7A;/** 普通最小中文汉字 Unicode */public static final int MIN_CHINESE = 0x4E00;/** 普通最大中文汉字 Unicode */public static final int MAX_CHINESE = 0x9FA5;/** 全角空格 Unicode */public static final int SBC_BLANK = 0x3000;//0xFF00也是全角空格/** 关注全角下限 Unicode */public static final int SBC_LOW_LIMIT = 0xFF00;/** 关注全角上限 Unicode */public static final int SBC_UP_LIMIT = 0xFF5E;/** 全角句点 Unicode */public static final int SBC_POINT = 0xFF0E;/** 全角0 Unicode */public static final int SBC_0 = 0xFF10;/** 全角9 Unicode */public static final int SBC_9 = 0xFF19;/** 全角A Unicode */public static final int SBC_A = 0xFF21;/** 全角Z Unicode */public static final int SBC_Z = 0xFF3A;/** 全角a Unicode */public static final int SBC_LA = 0xFF41;/** 全角z Unicode */public static final int SBC_LZ = 0xFF5A;/** 半角全角数字或字母 Unicode 编码偏移 */public static final int OFFSET_DBC_SBC = 0xFEE0;/** 英文大小写字母 Unicode 编码偏移 */public static final int OFFSET_UP_LOW = 0x20;static {QUANTIFIER_PATH = ConfigUtil.getConfig("dic.quantifier");NUMERAL_PATH = ConfigUtil.getConfig("dic.numeral");DIC_ENCODING = ConfigUtil.getConfig("dic.encoding");initQantifierSet();initNumeralSet();}/*** Unicode 字符类型*/public enum CharType {/** 控制符 */CONTROL,/** 半角数字 */DBC_DIGIT,/** 半角大写字母 */DBC_UPPER_CASE,/** 半角小写字母 */DBC_LOWER_CASE,/** 中文 */COMMON_CHINESE,/** 全角字符 */SBC_CHAR,/** 全角字母 */SBC_CASE,/** 全角数字 */SBC_DIGIT,/** 全角大写字母 */SBC_UPPER_CASE,/** 全角小写字母 */SBC_LOWER_CASE,/** 小数点 */DECIMAL_POINT,/** 数字后缀 */DECIMAL_SUFFIX,/** 百分比符号 */PERCENT_CHAR,/** 空白符 */BLANK_CHAR,/** 其他 */OTHER_CHAR,}/*** 通过字符判断其类型** @param ch Unicode字符* @return 字符类型*/public static CharType getCharType(char ch) {int value = ch;//Unicode 普通中文汉字区if ((value >= MIN_CHINESE) && (value <= MAX_CHINESE)) {return CharType.COMMON_CHINESE;}//空白符、控制字符、半角空格0x20、全角空格0x3000if ((value <= DBC_BLANK) || (value == SBC_BLANK)) {return CharType.BLANK_CHAR;}//半角数字0-9:0x30-0x39if ((value >= DBC_0) && (value <= DBC_9)) {return CharType.DBC_DIGIT;}//半角字母a-z:0x61-0x7Aif ((value >= DBC_LA) && (value <= DBC_LZ)) {return CharType.DBC_LOWER_CASE;}//半角字母A-Z:0x41-0x5Aif ((value >= DBC_A) && (value <= DBC_Z)) {return CharType.DBC_UPPER_CASE;}//小数点:半角0x2Eif (value == DBC_POINT) {return CharType.DECIMAL_POINT;}//数字后缀if ((value == (int) ('%'))|| (value == (int) ('$'))|| (value == (int) ('¥'))) {return CharType.DECIMAL_SUFFIX;}//关注的全角区:0xFF00-0xFF5E  与半角相距FEE0if ((value >= SBC_LOW_LIMIT) && (value <= SBC_UP_LIMIT)) {return CharType.SBC_CHAR;}//说明:全角其他子区可以不判断了,为扩展保留//全角数字0-9:0xFF10-0xFF19  与半角相距FEE0if ((value >= SBC_0) && (value <= SBC_9)) {return CharType.SBC_CHAR;}//全角字母A-Z:0xFF21-0xFF3A  与半角相距FEE0if ((value >= SBC_A) && (value <= SBC_Z)) {return CharType.SBC_CHAR;}//全角字母a-z:0xFF41-0xFF5A  与半角相距FEE0if ((value >= SBC_LA) && (value <= SBC_LZ)) {return CharType.SBC_CHAR;}//其他字符return CharType.OTHER_CHAR;}/*** 判断字符否是数字类型字符。** @param ch 字符* @return boolean true-数字类型,fasle-非数字类型*/static boolean isDecimalType(char ch) {if (Unicode.isDecimal(ch)) {return true;}if (Unicode.isPoint(ch)) {return true;}return Unicode.isDecimalSuffix(ch);}/*** 判断字符否是数字。** @param ch 字符* @return boolean true-数字,fasle-非数字*/static boolean isDecimal(char ch) {int unicode = ch;//半角或全角数字return ((unicode >= DBC_0) && (unicode <= DBC_9))|| (unicode >= SBC_0) && (unicode <= SBC_9);}/*** 判断字符是否是数字后缀。** @param ch 字符* @return boolean true-数字后缀,false-非数字后缀*/static boolean isDecimalSuffix(char ch) {int unicode = ch;//数字后缀return (unicode == (int) ('%'))|| (unicode == (int) ('$'))|| (unicode == (int) ('¥'));}/*** 判断字符是否是小数点。** @param ch 字符* @return boolean true-小数点,fasle-非小数点*/static boolean isPoint(char ch) {int unicode = ch;//半角或全角数字return (unicode == DBC_POINT) || (unicode == SBC_POINT);}/*** 初始化中文数字集合*/private static void initNumeralSet() {numeralSet = new HashSet<>();String numerals = FileUtil.readText(NUMERAL_PATH, DIC_ENCODING);char[] symbolArr = numerals.toCharArray();for (int i = 0; i < symbolArr.length; i++) {numeralSet.add(symbolArr[i]);}}/*** 判断一个字符是否是中文数字** @param ch 输入字符* @return 是否是中文数字*/static boolean isNumeral(char ch) {int unicode = ch;if ((unicode < Unicode.MIN_CHINESE) || (unicode > Unicode.MAX_CHINESE)) {return false;}return numeralSet.contains(ch);}/*** 初始化单量词集合*/private static void initQantifierSet() {quantifierSet = new HashSet<>();String quantifiers = FileUtil.readText(QUANTIFIER_PATH, DIC_ENCODING);char[] symbolArr = quantifiers.toCharArray();for (int i = 0; i < symbolArr.length; i++) {quantifierSet.add(symbolArr[i]);}}/*** 判断一个字符是否是中文量词** @param ch 输入字符* @return 是否是量词*/static boolean isQuantifier(char ch) {int unicode = ch;if ((unicode < Unicode.MIN_CHINESE) || (unicode > Unicode.MAX_CHINESE)) {return false;}return quantifierSet.contains(ch);}
}

分词器参数配置:

package com.robin.segment.robinseg;/*** <DT><B>描述:</B></DT>* <DD>Robin分词器参数配置类</DD>** @version 1.0* @author Robin* @version <I> V1.0 Date:2018-01-30</I>* @author  <I> E-mail:xsd-jj@163.com</I>*/
public class SegmentArgs {/** 词结束符 */static final char END_MARK = Unicode.NULL;/** 分词方法 */SegAlgorithm segMethod = SegAlgorithm.FORWARD;/** 符号标志 */boolean cleanSymbolFlag = true;/** 新词标注标志 */boolean markNewWordFlag = false;/** 大小写转换 */boolean downCasingFlag = true;/** 分词合并模式-字典中未出现的孤立子合并 */boolean mergePatternFlag = true;/** 分词检索模式 */boolean retrievalPatternFlag = false;/** 分隔符 */String separator = " ";/** 词标符号 */private static final String WORD_MARK = "⊙";/** 新词标记 */static final String NEW_WORD_MARK = "[" + WORD_MARK + "新词]";/** 拼接词标记 */static final String SPLICE_WORD_MARK = "[" + WORD_MARK + "拼接词]";/** 混合词标记 */static final String CN_EN_MIX_MARK = "[" + WORD_MARK + "混合词]";/*** Robin分词方法枚举类型*/public enum SegAlgorithm {/** 带回退策略的正向最大匹配 */FORWARD,/** 简单反向最大匹配 */REVERSE}/*** 词的类别*/enum WordClass {STANDARD,/** 英文词,自动识别 */ENGLISH,/** 数量词,包括自动识别的中文数量词 */QUANTIFIER,/** 新词,识别的含有中文字符的新词 */NEW_WORD,/** 中英文混合词 */CN_EN_MIX,/** 拼接新词,标准词与孤立字符拼接出来的新词 */SPLICE_WORD,/** 孤立中文字符 */ISOLATED_CN,/** 其他,上述之外 */OTHER}/*** 构造方法*/public SegmentArgs() {}/*** 重置默认配置参数*/public void resetDefaultArgs() {this.segMethod = SegAlgorithm.FORWARD;this.cleanSymbolFlag = true;this.markNewWordFlag = false;this.downCasingFlag = true;this.mergePatternFlag = true;this.retrievalPatternFlag = false;}/*** 设置分词分隔符** @param separator 分隔符*/void setSeparator(String separator) {this.separator = separator;}/*** 设置删除符号标志** @param flag 是否删除*/public void setCleanSymbolFlag(boolean flag) {this.cleanSymbolFlag = flag;}/*** 设置是否检索型分词** @param flag 是否检索型分词*/public void setRetrievalPatternFlag(boolean flag) {this.retrievalPatternFlag = flag;}/*** 设置拼接模式标志** @param flag 是否拼接模式*/public void setMergePatternFlag(boolean flag) {this.mergePatternFlag = flag;}/*** 设置新词标注开关** @param flag 是否标注*/public void setMarkNewWordFlag(boolean flag) {this.markNewWordFlag = flag;}/*** 设置分词算法 目前支持正向最大匹配、反向最大匹配 分词算法修改需要重新加载词典** @param segAlgorithm 分词算法*/public void setSegAlgorithm(SegAlgorithm segAlgorithm) {this.segMethod = segAlgorithm;}/*** 设置是否大-小写字母转换** @param flag 是否转换*/public void setDowncasingFlag(boolean flag) {this.downCasingFlag = flag;}
}

词典类:

package com.robin.segment.robinseg;import com.robin.config.ConfigUtil;
import com.robin.log.RobinLogger;
import com.robin.file.FileUtil;
import com.robin.segment.robinseg.Unicode.CharType;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;/*** <DT><B>描述:</B></DT>* <DD>词典类</DD>** @version Version1.0* @author Robin* @version <I> V1.0 Date:2018-01-28</I>* @author  <I> E-mail:xsd-jj@163.com</I>*/
class Dictionary {private static final Logger LOGGER = RobinLogger.getLogger();// 词典路径private static final String DIC_PATH;// 词典文件编码private static final String DIC_ENCODING;// 词典MapTreeprivate static Map<Character, Object> reverseDicMap = null;// 词典MapTree数组private static Map[] forwardDicArr = null;static {DIC_PATH = ConfigUtil.getConfig("dic.base");if (DIC_PATH == null) {LOGGER.log(Level.SEVERE, "dictionary file path config err.");}String encoding = ConfigUtil.getConfig("dic.encoding");if (null == encoding) {DIC_ENCODING = "UTF-8";} else {DIC_ENCODING = encoding;}loadForwardDictionary();loadReverseDictionary();}static Map<Character, Object> getReverseDicMap() {return reverseDicMap;}static Map[] getForwardDicArr() {return forwardDicArr;}/*** 加载正向词典mapTree数组*/private static void loadForwardDictionary() {if (null != forwardDicArr){return;}//代码略LOGGER.log(Level.INFO, "Load forward dictionary successfully.");}/*** 加载反向词典mapTree*/private static void loadReverseDictionary() {if (null != reverseDicMap) {return;}// 代码略LOGGER.log(Level.INFO, "Load reverse dictionary successfully.");}/*** 获取分词全字符字典** @return 分词字典*/public String getDicAllTrems() {buildTrems(reverseDicMap);return dicBuilder.toString();}private List<Character> wordList = new ArrayList<>();private StringBuilder dicBuilder = new StringBuilder();/*** 递归构建全字符词典** @param map Map + Tree 格式词典*/private void buildTrems(Map<Character, Object> map) {if (null == map) {for (int i = 0; i < wordList.size(); i++) {Character character = wordList.get(i);dicBuilder.append(character);}dicBuilder.append("\n");return;}Iterator<Character> it = map.keySet().iterator();while (it.hasNext()) {Character character = it.next();wordList.add(character);Map<Character, Object> nextMap = (Map<Character, Object>) map.get(character);buildTrems(nextMap);wordList.remove(wordList.size() - 1);}}
}

分词器部分代码:

package com.robin.segment.robinseg;import com.robin.segment.robinseg.SegmentArgs.SegAlgorithm;
import com.robin.segment.AbstractSegmenter;
import com.robin.segment.robinseg.SegmentArgs.WordClass;
import com.robin.segment.robinseg.Unicode.CharType;
import java.util.Map;/*** <DT><B>描述:</B></DT>* <DD>Robin分词类</DD>* <DD>实现:正向最大匹配算法,反向最大匹配(simple)</DD>* <DD>默认:带逆向回退策略的正向最大匹配</DD>** @version Version1.0* @author Robin* @version <I> V1.0 Date:2018-01-28</I>* @author  <I> E-mail:xsd-jj@163.com</I>*/
public class RobinSeg extends AbstractSegmenter {//分词实例private static AbstractSegmenter instance = null;//分词配置项private static final SegmentArgs SEG_CONG = new SegmentArgs();//遍历字符序列的标记前一记录private Record last = new Record();//遍历字符序列的标记当前记录private Record curr = new Record();//存放已经分好词的序列private StringBuilder splited;// 当前最大索引(已经扫描到的最前索引,主要用于检索分词)private int currMaxIndex = -1;private final Map[] forwardDicArr;private final Map<Character, Object> reverseDicMap;/*** 构造方法*/private RobinSeg() {forwardDicArr = Dictionary.getForwardDicArr();reverseDicMap = Dictionary.getReverseDicMap();}/*** * @return*/public SegmentArgs getSegmentConfInstance() {return SEG_CONG;}/*** 调用具体分词方法** @param text 输入待分词文本* @param separator 分隔符* @return 已分词文本*/@Overridepublic String segment(String text, String separator) {synchronized (this) {if (SEG_CONG.segMethod.equals(SegAlgorithm.FORWARD)) {return forwardMaxMatch(text, separator);} else if (SEG_CONG.segMethod.equals(SegAlgorithm.REVERSE)) {return reverseMaxMatch(text, separator);}}assert false : "算法类型参数错误,检查参数设置。";return "";}/*** 词的记录私有类*/private class Record {//词的类别WordClass wordClass = WordClass.OTHER;//以一个字符开头一条字符序列最多可能形成的词的数目,先估计最大不超过10个private static final int MAX_NUM = 10;int start = 0;int maxIdx = -1;int[] end = new int[MAX_NUM];boolean continued = false;Record next = null;/*** 重置记录项*/public void init(int start) {this.start = start;}/*** 记录构成词的游标位置 仅标准词(词典存在的词)才会调用此方法*/public void addIndex(int cursor) {assert (maxIdx < MAX_NUM - 1) : "字符序列成词数目越界,扩大词数目.";end[++maxIdx] = cursor;}/*** 重置记录项*/public void reset() {continued = false;wordClass = WordClass.OTHER;for (int i = 0; i <= maxIdx; i++) {end[i] = 0;}maxIdx = -1;}}/*** 记录前移,交换角色*/private void moveRocord() {Record swap = last;last = curr;curr = swap;curr.reset();}/*** 判断当前字符序列是否在字典中构成一个完整的词** @return boolean 是否在字典中构成一个完整的词*/private boolean isStandardWord(char[] wordArr) {//代码略}/*** 判断当前字符在字符序列里是否是孤立字符(不能够成为中文词首)** @return boolean 是否是孤立字符*/private boolean isIsoLatedChar(char[] charArray, int cursor) {// 代码略}/*** 文本分词 正向最大匹配改进算法** @param text 输出待分词文本* @param separator 分隔符* @return 使用分隔符隔开的词文本*/private String forwardMaxMatch(String text, String separator) {assert SEG_CONG.segMethod.equals(SegAlgorithm.FORWARD) : "算法类型设置错误。";//代码略}/*** 根据条件增加分隔符** @param start 下一记录起始位置*/private void addSeparator(int start) {//如果还未分割if (curr.continued) {if (SEG_CONG.markNewWordFlag) {switch (curr.wordClass) {case NEW_WORD:splited.append(SegmentArgs.NEW_WORD_MARK);break;case CN_EN_MIX:splited.append(SegmentArgs.CN_EN_MIX_MARK);break;case SPLICE_WORD:splited.append(SegmentArgs.SPLICE_WORD_MARK);break;default:break;}}splited.append(SEG_CONG.separator);curr.addIndex(start);moveRocord();curr.init(start);}}/*** 处理(阿拉伯数字)数量词** @param charArray 字符序列* @param cursor 输入游标位置* @return boolean 是否完成*/private boolean handleQuantifier(char[] charArray, int cursor) {int start = cursor;char currChar = charArray[cursor];//正向最大匹配的数字前一个是未分割if (cursor > 0) {//考虑前一个字符Character prev = charArray[cursor - 1];if (!Unicode.isDecimal(prev) && !Unicode.isPoint(prev)) {addSeparator(start);}}//正向最大匹配的数字+量词if (cursor < charArray.length - 1) {//正向的考虑后一个字符Character next = charArray[++cursor];if (Unicode.isQuantifier(next)) {splited.append(currChar);splited.append(next);splited.append(SEG_CONG.separator);curr.continued = false;curr.wordClass = WordClass.QUANTIFIER;cursor++;curr.addIndex(cursor);moveRocord();return true;}}return false;}/*** 词典中查找匹配的词** @param charArray 字符序列* @param cursor 当前游标* @return boolean 是否搜索到*/private boolean searchInDictionary(char[] charArray, int cursor) {//代码略}/*** 处理中文数字** @param charArray 字符序列* @param cursor 输入游标位置* @return cursor 输出游标位置*/private int handleCNNumeral(char[] charArray, int cursor) {int start = cursor;char currChar = charArray[cursor];addSeparator(start);splited.append(currChar);cursor++;curr.wordClass = WordClass.QUANTIFIER;while (cursor < charArray.length) {currChar = charArray[cursor];if (Unicode.isNumeral(currChar)) {splited.append(currChar);cursor++;} else if (Unicode.isQuantifier(currChar)) {splited.append(currChar);cursor++;break;} else {break;}}splited.append(SEG_CONG.separator);curr.end[0] = cursor;curr.maxIdx = 0;moveRocord();return cursor;}/*** 处理中文孤立字符** @param charArray 字符序列* @param cursor 输入游标位置* @return int 输出游标位置*/private int handleIsoLatedCNChar(char[] charArray, int cursor) {// 代码略}/*** 文本分词 反向** @param text 输出待分词文本* @param separator 分隔符* @return 使用分隔符隔开的词文本*/private String reverseMaxMatch(String text, String separator) {assert SEG_CONG.segMethod.equals(SegAlgorithm.REVERSE) : "算法类型设置错误。";//代码略}/*** 获取 RobinSeg 分词类的实例** @return 分词类的单实例*/public static AbstractSegmenter getInstance() {if (null == instance) {instance = new RobinSeg();}return instance;}
}

4.4 运行结果

分词效果

-----------------------------分词效果-------------------------------
【-用例原始文本-】:马云,中国著名企业家,浙江绍兴人,阿里巴巴集团主要创始人之一。现任阿里巴巴集团主席和首席执行官,他是《福布斯》杂志创办50多年来成为封面人物的首位大陆企业家,曾获选为未来全球领袖。董事等职务。2013年3月11日,阿里巴巴集团董事局主席兼CEO马云昨日发出内部邮件称,集团首席数据官陆兆禧将接任CEO一职。
【拼接-分类-模式】:马云[⊙新词]|中国|著名|企业家|浙江|绍兴|人|阿里巴巴|集团|主要|创始人|之一|现任|阿里巴巴|集团|主席|和|首席执行官|他是|福布斯|杂志|创办|50|多年来|成为|封面人物|的|首位|大陆|企业家|曾|获选|为|未来|全球|领袖|董事|等|职务|2013年|3月|11日|阿里巴巴|集团|董事局|主席|兼|ceo马云[⊙混合词]|昨日|发出|内部|邮件|称|集团|首席|数据|官[⊙新词]|陆兆|禧|将|接任|ceo|一|职|
【拼接-检索-模式】:马云[⊙新词]|中|中国|著名|企业|企业家|浙江|绍兴|人|阿|阿里|阿里巴巴|巴巴|集团|主要|要|创始|创始人|人|之|之一|现任|任|阿|阿里|阿里巴巴|巴巴|集团|主席|和|首席|首席执行官|执行|执行官|他|他是|是|福布斯|杂志|创办|办|50|多|多年|多年来|年来|来|成|成为|为|封面|封面人物|面人|人|人物|的|首位|大|大陆|企业|企业家|曾|获选|选|选为|为|未来|来|全球|领|领袖|董事|等|职务|2013年|3月|11日|阿|阿里|阿里巴巴|巴巴|集团|董事|董事局|主席|兼|ceo马云[⊙混合词]|昨日|日|发|发出|出|内部|邮件|称|集团|首席|数|数据|据|官[⊙新词]|陆兆|禧|将|接|接任|任|ceo|一|职|
-------------------------------------------------------------------
【-用例原始文本-】:阿拉伯金额数字万位和元位是"0",或者数字中间连续有几个"0",万位、元位也是"0",但千位、角位不是"0"时,中文大写金额中可以只写一个零字,也可以不写"零"字。如¥1680.32,应写成人民币壹仟陆佰捌拾元零叁角贰分,或者写成人民币壹仟陆佰捌拾元叁角贰分,又如¥107000.53,应写成人民币壹拾万柒仟元零伍角叁分,或者写成人民币壹拾万零柒仟元伍角叁分。
【拼接-分类-模式】:阿拉伯|金额|数字|万位[⊙新词]|和|元位[⊙拼接词]|是|0|或者|数字|中间|连续|有几个|0|万位[⊙新词]|元位[⊙拼接词]|也是|0|但|千位[⊙新词]|角位[⊙拼接词]|不是|0|时|中文|大写|金额|中|可以|只写|一个|零字|也可以|不|写|零|字|如|1680.32|应|写成|人民币|壹仟|陆佰|捌拾元|零叁角|贰分|或者|写成|人民币|壹仟|陆佰|捌拾元|叁角|贰分|又如|107000.53|应|写成|人民币|壹拾万|柒仟|元|零伍角|叁分|或者|写成|人民币|壹拾万|零柒仟|元|伍角|叁分|
-------------------------------------------------------------------
【-用例原始文本-】:p非v IBM研究院 IBM非 VC维 VC银翘片,魅族MX系列。我很喜欢陈述高的演讲,我很不喜欢陈述高调的样子。人们向林俊德表示深切的问候。中华人民共和国
【拼接-分类-模式】:p非v[⊙混合词]|ibm|研究院|ibm非[⊙混合词]|vc维[⊙混合词]|vc银翘片[⊙混合词]|魅族mx[⊙混合词]|系列|我很|喜欢|陈述高[⊙拼接词]|的|演讲|我很|不喜欢|陈述|高调|的|样子|人们|向|林俊德[⊙新词]|表示|深切|的|问候|中华人民共和国|
-------------------------------------------------------------------
【-用例原始文本-】:姚明退役了。草泥马的,据路透社报道,印度尼西亚社会事务部一官员星期二(29日)表示,日惹市附近当地时间27日晨5时53分发生的里氏6.2级地震已经造成至少5427人死亡,20000余人受伤,近20万人无家可归。
【拆分-分类-模式】:姚明|退役|了|草泥马[⊙新词]|的|据|路透社|报道|印度尼西亚|社会|事务部|一|官员|星期二|29日|表示|日惹|市|附近|当地时间|27日|晨|5时|53分|发生|的|里氏|6.2级|地震|已经|造成|至少|5427|人|死亡|20000|余人|受伤|近|20万|人|无家可归|
【拼接-分类-模式】:姚明|退役|了|草泥马[⊙新词]|的|据|路透社|报道|印度尼西亚|社会|事务部|一|官员|星期二|29日|表示|日惹市[⊙拼接词]|附近|当地时间|27日|晨|5时|53分|发生|的|里氏|6.2级|地震|已经|造成|至少|5427|人|死亡|20000|余人|受伤|近|20万|人|无家可归|
-------------------------------------------------------------------
【-用例原始文本-】:歧义和同义词:研究生命起源,混合词: 做B超检查身体,本质是X射线,单位和全角: 2009年8月6日开始大学之旅,中文数字: 四分之三的人都交了六十五块钱班费,那是一九九八年前的事了,四川麻辣烫很好吃,五四运动留下的五四精神。笔记本五折包邮亏本大甩卖。人名识别: 我是陈鑫,也是jcesg的作者,三国时期的诸葛亮是个天才,我们一起给刘翔加油,罗志高兴奋极了因为老吴送了他一台笔记本。配对标点: 本次『畅想杯』黑客技术大赛的得主为电信09-2BF的张三,奖励C++程序设计语言一书和【畅想网络】的『PHP教程』一套。特殊字母: 【Ⅰ】(Ⅱ),英文数字: bug report chenxin619315@gmail.com or visit http://code.google.com/p/jcseg, 15% of the day's time i will be there.特殊数字: ① ⑩ ⑽ ㈩.
【拆分-分类-模式】:歧义|和|同义词|研究生|命|起源|混合|词|做|b超[⊙混合词]|检查|身体|本质|是|x|射线|单位|和|全角|2009年|8月|6日|开始|大学|之旅|中文数字|四分之三|的|人|都|交了|六十五块|钱|班费|那是|一九九八年|前|的|事|了|四川|麻辣烫|很好|吃|五四运动|留下|的|五四|精神|笔记本|五折|包|邮|亏本|大|甩卖|人名|识别|我是|陈鑫[⊙新词]|也是|jcesg|的|作者|三国|时期|的|诸葛亮[⊙新词]|是个|天才|我们|一起|给|刘翔[⊙新词]|加油|罗志[⊙新词]|高兴|奋|极了|因为|老吴|送了|他|一台|笔记本|配对|标点|本次|畅想|杯|黑客|技术|大赛|的|得主|为|电信|09|2bf|的|张三|奖励|c|程序设计语言|一书|和|畅想|网络|的|php|教程|一套|特殊|字母|英文|数字|bug|report|chenxin|619315|gmail|com|or|visit|http|code|google|com|p|jcseg|15%|of|the|day|s|time|i|will|be|there|特殊|数字|
【拼接-分类-模式】:歧义|和|同义词|研究|生命|起源|混合词[⊙拼接词]|做|b超[⊙混合词]|检查|身体|本质|是|x|射线|单位|和|全角|2009年|8月|6日|开始|大学|之旅|中文数字|四分之三|的|人|都|交了|六十五块|钱|班费|那是|一九九八年|前|的事[⊙拼接词]|了|四川|麻辣烫|很好|吃|五四运动|留下|的|五四|精神|笔记本|五折|包邮[⊙拼接词]|亏本|大|甩卖|人名|识别|我是|陈鑫[⊙新词]|也是|jcesg|的|作者|三国|时期|的|诸葛亮[⊙新词]|是个|天才|我们|一起|给|刘翔[⊙新词]|加油|罗志[⊙新词]|高兴奋[⊙拼接词]|极了|因为|老吴|送了|他|一台|笔记本|配对|标点|本次|畅想杯[⊙拼接词]|黑客|技术|大赛|的|得主|为|电信|09|2bf|的|张三|奖励|c|程序设计语言|一书|和|畅想|网络|的|php|教程|一套|特殊|字母|英文|数字|bug|report|chenxin|619315|gmail|com|or|visit|http|code|google|com|p|jcseg|15%|of|the|day|s|time|i|will|be|there|特殊|数字|
-------------------------------------------------------------------
【-用例原始文本-】: ENGLISH CHInese WhAt are you doING!. The state investigation that followed the AJC’s analyses of test scores depicted a culture that rewarded cheaters, punished whistle-blowers and covered up improprieties.
【拼接-分类-模式】:english|chinese|what|are|you|doing|the|state|investigation|that|followed|the|ajc|s|analyses|of|test|scores|depicted|a|culture|that|rewarded|cheaters|punished|whistle|blowers|and|covered|up|improprieties|
-------------------------------------------------------------------
【-用例原始文本-】:全角半角、大小写转换 小数:5条狗,4.5个 6.3 6.7 0.6 7.8 1.5 ENglIsH ChineSE. TExt.SEGMenT 0.1%2.3$4.5¥6.7%8.9¥ 11.2 %¥$
【拆分-分类-模式】:全角|半角|大小写|转换|小数|5条|狗|4.5个|6.3|6.7|0.6|7.8|1.5|english|chinese|text|segment|0.1%|2.3$|4.5¥|6.7%|8.9¥|11.2|
-------------------------------------------------------------------

分词性能

⊙字符总数:[  17.25 ]W. 用时:[   18 ]ms。 速度:[  958W ]字符/秒。文件名:data/凯文凯利-失控.txt
失控|全人类|的|最终|命运|和|结局|作者|美|凯文[⊙新词]|凯利[⊙新词]|著|东西|文库|译|出版社|新星|出版社|出版|时间|2010|12|1|版次|1|页数|700|字数|500000|印刷|时间|2010|12|1|开本|16开|纸张|胶版纸|印次|1|isbn|9787513300711|包装|平装|内容简介|这是|黑客帝国|主要|演员|的|必读物[⊙拼接词]|之一|这本|关于|
-------------------------------------------------------------------
⊙字符总数:[  37.10 ]W. 用时:[   34 ]ms。 速度:[ 1091W ]字符/秒。文件名:data/绝影-疯狂的程序员.txt
疯狂|的|程序员|绝影[⊙新词]|1|hello|world|天|已经|七分|黑了|屋里|却|还没|开灯|这个|全身|黑衣服|的|男子|突然|像|想起|什么|从|包里[⊙拼接词]|掏出烟[⊙拼接词]|抽出|一只|递给|旁边|的|人|兄弟|抽烟|么|那烟[⊙拼接词]|是|红塔山|旁边|那人|连忙|一边|摆手|一边|说|不|不|语气|有点|紧张|好像|那|黑衣服|递过来|的|不是烟[⊙拼接词]|是|海
-------------------------------------------------------------------
⊙字符总数:[   4.27 ]W. 用时:[    5 ]ms。 速度:[  853W ]字符/秒。文件名:data/高晓松-如丧.txt
如丧[⊙拼接词]|我们|终于|老得|可以|谈谈|未来|序|时隔|十二年|为|出版|第二|本|文集|坐在|洛杉矶|垂垂[⊙新词]|夕阳|下|校对|文稿|看到|歌词|部分|时|忽然|瞥见|好多年|前|给|叶蓓|的|几句词[⊙拼接词]|夕阳|你|温暖|的|肩膀|我|柔软的|心房|大地|以及|忧伤|每一|天|在|我心|上|我为你舞[⊙拼接词]|在|远方|我是|你的|花|我不|管|春天|有多|长|正好在|夕
-------------------------------------------------------------------
⊙字符总数:[ 235.73 ]W. 用时:[  238 ]ms。 速度:[  990W ]字符/秒。文件名:data/谭松波-体育-2805P.txt
1|跳水队[⊙拼接词]|老大哥|熊倪[⊙新词]|在|一个|集体|跳水|的|动作|中|因|队友|失手|不|配合|头撼[⊙新词]|对方|的|臀部|而|伤|及|後颈[⊙新词]|香港电[⊙拼接词]|高台|集体|跳水|失手|奥运|巨星|熊倪[⊙新词]|伤颈[⊙拼接词]|万众瞩目|的|中国|跳水队[⊙拼接词]|昨天|首次|在|九龙|公园|表演|时|险|生|悲剧|跳水队[⊙拼接词]|老大哥|熊倪[⊙新词]|在|
-------------------------------------------------------------------
⊙字符总数:[  14.01 ]W. 用时:[   14 ]ms。 速度:[ 1001W ]字符/秒。文件名:data/塞林格-麦田里的守望者.txt
麦田|里的|守望|者|作者|塞林格[⊙新词]|状态|全本|内容简介|本书|的|主人公|霍尔顿[⊙拼接词]|是个|中学生|出身|于|富裕|的|中产阶级|家庭|他|虽|只有|16岁[⊙新词]|但|比|常人|高出|一头|整日|穿着|风雨衣|戴着|鸭舌帽|游游荡荡|不愿|读书|他对|学校|里的|一切|老师|同学|功课|球赛|等等|全都|腻烦|透了|3次[⊙新词]|被|学校|开除|又一个|学期结束|了|他|
-------------------------------------------------------------------

5 对比验证

  本文通过与其它前述几种分词器对比验证分类效果。

5.1 分词速度对比

  实测环境说明
  (1)测试样本

样本分类 名称 字符数(万)
电子书 塞林格-《麦田里的守望者》 14
绝影-《疯狂的程序员》 37
凯文凯利-《失控——全人类的最终命运和结局》 49
高晓松-《如丧》片段 4.3
网页语料 2805篇体育类新闻 236
819篇财经类新闻 148
1040篇科技类新闻 108
2943篇电脑类新闻 238

  样本分成8个字符串序列,字数总计834万,字节大小 15.91 MB(按照java字符内码占两个字节估计).
  (2)测试说明
  每一种分类器都将上述样本分三次求得平均分词速度,分词速度统计都不包括文本加载时间。各分类器预先都进行短文本分词预热,避免首次加载词典等初始化操作造成的时间误差。所有分词算法都采用单线程测试。
  (3)测试机

机器 CPU OS
服务器 Xeon E5-2670 2.6GHz Ubuntu 14.04.5 LTS
PC Core i5-3210 2.5GHz Windows 7

  服务器运行输出结果如下:

  PC机运行输出结果如下:

  分词速度对比如图所示:

5.2 分词结果对比

  两段短文本在各分词器上的分词效果如下所示:

--------------------------------------------------------------------------------------------------------------------------------
原始文本:时隔十二年,为出版第二本文集,坐在洛杉矶垂垂夕阳下校对文稿,看到歌词部分时忽然瞥见好多年前给叶蓓的几句词。
--------------------------------------------------------------------------------------------------------------------------------
[RS]分词:时隔|十二年|为|出版|第二|本|文集|坐在|洛杉矶|垂垂|夕阳|下|校对|文稿|看到|歌词|部分|时|忽然|瞥见|好多年|前|给|叶蓓|的|几句词|
[IK]分词:时隔|十二年|年|为|出版|第二|第|二|本文|本|文集|坐在|洛杉矶|垂|垂|夕阳|下|校对|对文|文稿|看到|歌词|部分|分时|忽然|瞥见|见好|好多年|多年前|多|年前|年|给|叶蓓|的|几句|几|句词|句|
[JE]分词:时隔|十二年|出版|第二本|文集|坐在|洛杉矶|垂|垂|夕阳|校对|文稿|看到|歌词部|分时|忽然|瞥见|好多|年前|给|叶蓓|几|句词|
[MS]分词:时隔|十二|年|为|出版|第二|本|文集|坐在|洛杉矶|垂|垂|夕阳|下|校对|文稿|看到|歌词|部分|时|忽然|瞥见|好多|年前|给|叶|蓓|的|几句|词|
[PD]分词:时|隔|十|年|二年|出|版|第|第二|本|文|文集|坐|坐在|洛杉矶|垂垂|夕阳|阳下|对|校对|文|文稿|看到|歌词|部|分|时|忽然|瞥见|见好|多|好多|年|前|叶蓓|句|几句|句词|
[SS]分词:时隔|十|二年|为|出版|第二|本|文集|坐在|洛杉矶|垂垂|夕阳|下|校对|文稿|看到|歌词|部|分时|忽然|瞥见|好多|年前|给|叶蓓|的|几|句词|
--------------------------------------------------------------------------------------------------------------------------------
原始文本:据路透社报道,印度尼西亚社会事务部一官员星期二(29日)表示,日惹市附近当地时间27日晨5时53分发生的里氏6.2级地震已经造成至少5427人死亡,20000余人受伤,近20万人无家可归。
--------------------------------------------------------------------------------------------------------------------------------
[RS]分词:据|路透社|报道|印度尼西亚|社会|事务部|一|官员|星期二|29日|表示|日惹市|附近|当地时间|27日|晨|5时|53分|发生|的|里氏|6.2级|地震|已经|造成|至少|5427|人|死亡|20000|余人|受伤|近|20万|人|无家可归|
[IK]分词:据|路透社|路|报道|印度尼西亚|社会事务|事务部|一|官员|星期二|二|29|日|表示|日|惹|市|附近|当地时间|27|日|晨|5|时|53|分发|分|发生|的|里氏|6.2|级|地震|已经|造成|至少|5427|人|死亡|20000|余人|余|人|受伤|近|20|万人|万|人|无家可归|
[JE]分词:据|路透社|报道|印度尼西亚|社会|事务部|官员|星期二|29日|表示|日惹市|附近|当地时间|27日|晨|5时|53分发|生的|里氏|6.2级|地震|已经|造成|至少|5427人|死亡|20000|余人|受伤|近|20万人|无家可归|
[MS]分词:据|路透社|报道|印度尼西亚|社会事务|部|一|官员|星期二|29|日|表示|日|惹|市|附近|当地时间|27|日|晨|5|时|53|分发|生的|里|氏|6|2|级|地震|已经|造成|至少|5427|人|死亡|20000|余|人|受伤|近|20|万人|无家可归|
[PD]分词:路透社|道|报道|印度|印度尼西|西亚|会|社会|事|事务|部|1|官员|星期|星期二|29|日|表示|日|日惹|日惹市|近|附近|地|时|间|当地时间|27|日|晨|5|时|53|分|发|生|生的|里氏|6.2|级|地|地震|经|已经|造|成|至少|5427|人|死|死亡|20000|余人|受|伤|近|200000|人|家|归|无家可归|
[SS]分词:据|路透社|报道|印度尼西亚|社会|事务部|一|官员|星期二|29|日|表示|日惹|市|附近|当地时间|27|日|晨|5|时|53|分发|生的|里氏|6.2|级|地震|已经|造成|至少|5427|人|死亡|20000|余人|受伤|近|20|万|人|无家可归|

  下图红色底色标示的分词结果“明显错误”,灰色的“具有争议”,可以看出知更鸟分词器(RS)分词有非常好的准确度。

6 总结

  通过上述实测结果可以看出知更鸟分词器具有良好的性能:

  • 高精度:通过各种分词器对比,看出RS分词准确度较高;
  • 高效率:单线程分词速度千万字符/秒(量级),字节处理速度15MB/s;
  • 模式多样:支持多种分词模式,有效支持中文文本分类等自然语言处理应用。
知更鸟博文推荐
上一篇 自然语言处理——文本分类概述
下一篇 文本分类——特征选择概述
推荐篇 基于Kubernetes、Docker的机器学习微服务系统设计——完整版
研究篇 RS中文分词   |   MP特征选择   |   NLV文本分类   |   快速kNN
作者简介
兴趣爱好 机器学习、云计算、自然语言处理、文本分类、深度学习
E-mail xsd-jj@163.com (欢迎交流)

参考:
[1]https://blog.csdn.net/u013063153/article/details/72904322
[2]http://blog.jobbole.com/111680/
[3]http://blog.51cto.com/tianxingzhe/1720067
[4]https://blog.csdn.net/flysky1991/article/details/73948971

版权声明:个人原创,请勿抄袭,欢迎引用,未经许可禁止转载. © 知更鸟

中文分词——知更鸟分词(RS)设计与实现相关推荐

  1. 自然语言处理系列十七》中文分词》分词工具实战》Python的Jieba分词

    注:此文章内容均节选自充电了么创始人,CEO兼CTO陈敬雷老师的新书<分布式机器学习实战>(人工智能科学与技术丛书)[陈敬雷编著][清华大学出版社] 文章目录 自然语言处理系列十七 分词工 ...

  2. 中文开源汉语分词工具

    本文转载自:http://www.scholat.com/vpost.html?pid=4477 由于中文文本词与词之间没有像英文那样有空格分隔,因此很多时候中文文本操作都涉及切词,这里整理了一些中文 ...

  3. Rstudio 实现 爬虫 文本分词 个性化词云设计--我爱中国我爱党

    Rstudio 爬虫 文本分词个性化词云设计 目录 1.环境准备,加载依赖 2.rvest 爬虫,数据爬取 3.jiebaR用于分词,词频统计 4.wordcloud2 结果可视化 ========= ...

  4. pyhanlp 中文词性标注与分词简介

    pyhanlp 中文词性标注与分词简介 pyhanlp实现的分词器有很多,同时pyhanlp获取hanlp中分词器也有两种方式 第一种是直接从封装好的hanlp类中获取,这种获取方式一共可以获取五种分 ...

  5. 中文分词器分词效果的评测方法

    [原创]中文分词器分词效果的评测方法 2013年8月27日 由 learnhard留言 » 转载请注明出处:http://www.codelast.com/ 现在有很多开源的中文分词器库,如果你的项目 ...

  6. solr配置中文IK Analyzer分词器

    1.下载IK Analyzer分词器文件 链接: https://pan.baidu.com/s/1hrA1YyK 密码: 9hpk 中文IK Analyzer分词器的相关配置使用资料: 链接:htt ...

  7. es拼音分词 大帅哥_SpringBoot集成Elasticsearch 进阶,实现中文、拼音分词,繁简体转换...

    Elasticsearch 分词 分词分为读时分词和写时分词. 读时分词发生在用户查询时,ES 会即时地对用户输入的关键词进行分词,分词结果只存在内存中,当查询结束时,分词结果也会随即消失.而写时分词 ...

  8. 公司开源的java分词,Java开源项目cws_evaluation:中文分词器分词效果评估

    通过对前文<word分词器.ansj分词器.mmseg4j分词器.ik-analyzer分词器分词效果评估>中写的评估程序进行重构改进,形成了一个新的Java开源项目cws_evaluat ...

  9. 处理中文分词 ik分词器以及拓展和停止字典

    一. 处理中文分词 以及 ik分词器的应用 解决: 1. 在es-plugins中添加安装 ik分词器 IK分词器包含两种模式: ik_smart:最少切分 ik_max_word:最细切分 2. 容 ...

最新文章

  1. 计算机删除百度云盘图标,win10系统百度云盘图标删除的操作方法
  2. html-head-body
  3. Prompt-based Language Models:模版增强语言模型小结
  4. Web前端培训:有哪些好用的前端开发工具呢?
  5. 爬虫之操作excel
  6. python delete_rows,Python:如何刪除以特定字符結尾的行?
  7. 男朋友就是要这个样子的
  8. XDUOJ 1125 Judgement of Orz Pandas
  9. SI4463软件开发记录
  10. BlackBerry 7290如何传自定义图片
  11. CIO峰会:企业私有云存储实践方案
  12. 向上滚动的文字的淡入淡出效果
  13. 贝叶斯分类器,什么是朴素贝叶斯,后续为使用贝叶斯实现海量数据的邮件筛选。带源码数据集和解决思路
  14. Python silk 库 支持微信语音
  15. 前后端分离,SpringBoot如何实现验证码操作
  16. Attributed Graph Clustering: A Deep Attentional Embedding Approach,IJCAI2019
  17. matlab把图片制作成视频
  18. 周周周报报报(药店管理系统)
  19. kali linux 命令
  20. 如何选择CDN?你需要关注这三个方面

热门文章

  1. 天猫开店,品牌的最终归宿?
  2. 【智汇珠源·筑梦曲靖】李石松李先祥与两院院士举行座谈
  3. 有重复元素的排列问题
  4. 如何使用Solidworks使得出图更加逼真
  5. javaMail学习(四)——使用javaMail给网易账户发简单邮件
  6. Spring5框架day03之JdbcTemplate
  7. 贺岁片《大腕》经典台词片段
  8. go 实现用户特权判断的例子
  9. SVG可伸缩矢量图形绘制钟表
  10. 基于三轴加速度传感器的计步算法