ㅤㅤㅤ
ㅤㅤㅤ
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ(生活只有在平淡无味的人看来才是空虚而平淡无味的。 —— 车尔尼雪夫斯基)
ㅤㅤㅤ
ㅤㅤㅤ
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ

中文分词器

引用百度的说明 ~~

中文分词就是将连续的字序列按照一定的规范重新组合成词序列的过程。我们知道,在英文的行文中,单词之间是以空格作为自然分界符的,而中文只是字、句和段能通过明显的分界符来简单划界,唯独词没有一个形式上的分界符,虽然英文也同样存在短语的划分问题,不过在词这一层上,中文比之英文要复杂得多、困难得多

  • 与英文为代表的拉丁语系语言相比,英文以空格作为天然的分隔符,而中文由于继承自古代汉语的传统,词语之间没有分隔。 古代汉语中除了连绵词和人名地名等,词通常就是单个汉字,所以当时没有分词书写的必要。而现代汉语中双字或多字词居多,一个字不再等同于一个词。
  • 在中文里,“词”和“词组”边界模糊
    现代汉语的基本表达单元虽然为“词”,且以双字或者多字词居多,但由于人们认识水平的不同,对词和短语的边界很难去区分。
    例如:“对随地吐痰者给予处罚”,“随地吐痰者”本身是一个词还是一个短语,不同的人会有不同的标准,同样的“海上”“酒厂”等等,即使是同一个人也可能做出不同判断,如果汉语真的要分词书写,必然会出现混乱,难度很大。
    中文分词的方法其实不局限于中文应用,也被应用到英文处理,如手写识别,单词之间的空格就不很清楚,中文分词方法可以帮助判别英文单词的边界

NodeJS中的中文分词器

  • mmseg-node

https://github.com/zzdhidden/mmseg-node
一个基于 libmmseg 的 NodeJS 驱动

安装流程

sudo apt-get install make gcc g++ automake libtool
wget http://www.coreseek.cn/uploads/csft/3.2/mmseg-3.2.14.tar.gz
sudo tar zxvf mmseg-3.2.14.tar.gz
cd mmseg-3.2.14
./bootstrap
./configure
make && make install
npm install mmseg

示例代码

const mmseg = require("mmseg");
const q = mmseg.open('/usr/local/etc/');
console.log(q.segmentSync("我是中文分词"));

从该包的下载量和issue的解决程度来看,不推荐使用,很容易碰到问题,而没有得到有效的解决

  • nseg

https://github.com/mountain/nseg
Chih-Hao Tsai发明的MMSG,一种非常流行的中文分词算法。许多实现可在不同的平台上使用,包括Python,Java等

安装流程

npm install nseg

示例代码

const dict  = require('../data/dict'),freq  = require('../data/freq'),date  = require('../lex/datetime'),sina  = require('../lex/sina');const opts  = {dict: dict,freq: freq,lexers: [date, sina],};const nseg = require('nseg').normal(opts);nseg('研究生源计划', (result) => {console.log(result);
});

mmseg一样,虽然在其他环境(比如Java,Python)有着较为成熟的应用和场景,但包的维护者重心可能不在nodejs上,所以还是不太建议使用…

  • node-segment

https://github.com/leizongmin/node-segment
盘古分词组件中的词库为基础, 算法设计也部分参考了盘古分词组件中的算法

具有以下特点

  • 纯JavaScript编写,可以在任何支持ECMAScript5的引擎上执行(需要稍微修改部分代码)
  • 基于词性进行联想识别
  • 可使用JavaScript编写自定义的分词模块

安装流程

npm install segment --save

示例代码

const Segment = require('segment');
const segment = new Segment();
segment.useDefault(); // 载入默认词典
segment.loadDict('test.text'); // 载入字典,详见dicts目录,或者是自定义字典文件的绝对路径
const text = "欢迎来到CSDN开发者博客论坛~~";
console.log(segment.doSegment(text, {stripPunctuation: true //去除标点符号
}));

定制化示例文件 .text

0x00100000代表16进制的词性,但在返回时转换为了十进制来标识

  • 名词 十进制:1048576 十六进制:0x00100000
  • 动词 十进制:4096 十六进制:0x00001000
  • 机构团体 十进制:20 十六进制:0x00000020
  • 时间 十进制:16384 十六进制:0x00004000
  • 人名 十进制:128 十六进制:0x00000080
  • 标点符号 十进制:2048 十六进制:0x00000800

101代表了这个词语的权重,在后续匹配词语时,若匹配到近似词,则以权重优先匹配

架构师|0x00100000|101
程序员|0x00100000|101
运维工程师|0x00100000|101

该包使用纯JavaScript编写,github上的star量有1k,但通过查看issue,该包的维护着似乎已经不太关心这个包了。但如果对性能要求没那么高,且多关注内存,使用得当的话,还是可以考虑的

  • nodejieba

https://github.com/yanyiwu/nodejieba
NodeJieba是"结巴(jieba)"中文分词的 Node.js 版本实现, 由CppJieba提供底层分词算法实现, 是兼具高性能和易用性两者的 Node.js 中文分词组件

具有以下特点

  • 词典载入方式灵活,无需配置词典路径也可使用,需要定制自己的词典路径时也可灵活定制。
  • 底层算法实现是C++,性能高效。
  • 支持多种分词算法,各种分词算法见CppJieba的README.md介绍。
  • 支持动态补充词库。

安装流程

npm install nodejieba

但在安装该包的时候可能会遇到npm下载权限的问题,因为底层使用了CppJieba,当使用sudo npm安装时会提示权限不足

github issue问题

  • https://github.com/nodejs/node-gyp/issues/454

npm 官方解释

  • https://docs.npmjs.com/misc/config#unsafe-perm

解决办法

  1. 单独下载该包文件
    sudo npm install nodejieba --unsafe-perm
  2. 将该包缓存至全局
    sudo npm install nodejieba -g --unsafe-perm
  3. 配置npm
    sudo su -
    npm config set unsafe-perm
  4. 切换至root身份运行
    sudo su -
    npm i

示例代码

jieba词性

  • 获取文本分词标注结果
  • n 名词
  • v 动词
  • nt 机构名称
  • t 时间
  • nr 人名

示例自定义文件 .utf-8

客户模板 n
客户状态 n
客户手机号 n
自定义 n
自定义字段 n
云通讯 n
const nodejieba = require("nodejieba");
jieba.load({ userDict: `self.utf-8`}); // 自定义词典
const text = '红掌拨清波';
const tags = ['n', 'v', 'nt', 'nr', 't'];
const docuemnt = jieba.tag(text).filter((v) => tags.includes(v.tag)).map((v) => v.word);
console.log(docuemnt);

目前NodeJS中性能最强的分词器,且github上star量达到2k+,但开发者可能会遇到安装的问题,因为底层依赖了python g++,如果版本过低或者过高,在安装时会比较棘手。但如果能够将机器环境配置好的话,还是推荐使用该工具的,毕竟性能很强~~

性能对比

起初在使用nodejieba时,遇到了很多安装的问题,比如npm权限,g++版本不匹配等等,期间也尝试了node-segment,但因为服务对性能的要求较高,所以还是选择克服机器配置的问题,使用了nodejieba

node-sgement和nodejieba的性能对比以及代码分析

示例代码

'use strict';
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const Segment = require('segment');
const segment = new Segment();
const nodejieba = require('nodejieba');
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
segment.useDefault();
segment.loadDict('test.text');
app.post('/', function (req, res, next) {const text = req.body.text;const type = req.body.type;const num = req.body.num;let str = '';let array = [];for (let index = 0; index < num; index++) {str += text;}const tags = ['n', 'v', 'nt', 'nr', 't'];if (type === 'nodejieba') {array = nodejieba.tag(str).filter((v) => tags.includes(v.tag)).map((v) => v.word)} else {array = segment.doSegment(str).map((v) => v.w);}console.log(array);res.send(array);
});app.listen(3000);

示例请求文件 .text

{"text": "生活只有在平淡无味的人看来才是空虚而平淡无味的。","type": "segment","num": 1
}
  • 使用apach bench进行测试

测试方法:ab -n 1000 -p post.txt -c 200 -T application/json localhost:3000

  • -n 请求总数
  • -p post请求文件
  • -c 并发量
  • -T 请求格式
  • 请求返回参数说明
  • Document Path: /phpinfo.php #测试的页面
  • Document Length: 50797 bytes #页面大小
  • Concurrency Level: 200 #测试的并发数
  • Time taken for tests: 11.846 seconds #整个测试持续的时间
  • Complete requests: 1000 #完成的请求数量
  • Failed requests: 0 #失败的请求数量
  • Write errors: 0
  • Total transferred: 204586997 bytes #整个过程中的网络传输量
  • HTML transferred: 203479961 bytes #整个过程中的HTML内容传输量
  • Requests per second: 337.67 [#/sec] (mean) #最重要的指标之一,每秒处理请求数
  • Time per request: 2961.449 [ms] (mean) #最重要的指标之二,平均等待时长
  • Time per request: 2.961 [ms] (mean, across all concurrent requests) #每个连接请求实际运行时间的平均值
  • Transfer rate: 16866.07 [Kbytes/sec] received #平均每秒网络上的流量,可以帮助排除是否存在网络流量过大导致响应时间延长的问题
  • 测试版本
  • node v12
  • segment v0.1.3
  • nodejieba v2.4.1
  • 测试结果
分词类型 字符长度 请求总数 并发条数 平均每秒处理 平均等待时长(ms) 是否包含分隔符(标点符号等)
segment 60 1000 20 129.47 154.474
nodejieba 60 1000 20 2662.83 7.511
segment 60 1000 50 137.51 363.598
nodejieba 60 1000 50 2660.41 17.222
segment 60 1000 100 134.56 753.688
nodejieba 60 1000 100 2774.89 36.038
segment 60 1000 200 134.05 1491.937
nodejieba 60 1000 200 2846.30 70.267
---- ----
segment 180 1000 200 67.40 2967.466
nodejieba 180 1000 200 2390.53 83.664
segment 360 1000 200 42.55 4700.340
nodejieba 360 1000 200 1801.97 110.989
---- ----
segment 60 1000 200 88.26 2265.952
nodejieba 60 1000 200 2860.95 69.907
segment 60 200 50 101.18 494.188
nodejieba 60 200 50 2688.39 18.598
segment 120 200 50 1.73 28933.129
nodejieba 120 200 50 1551.11 32.235
segment 360 200 50 error(栈溢出) error(栈溢出)
nodejieba 360 200 50 1117.46 44.744
  • 测试结果点评
  • 从测试结果来看,nodejieba是node-sgement的20-30倍,这得益于nodejieba依赖的CppJieba,而node-sgement使用的纯JS编写,所以性能要逊色很多
  • nodejieba和node-sgement在处理分词的请求都比较稳定,但面对长文本,即便性能很强的nodejieba依然会有性能瓶颈问题
  • 面对不包含标点符号的文本,nodejieba和node-sgement性能都会有所影响
  • node-sgement在对长文本(360个无标点符号的字符)进行分词时会导致栈溢出
  • 测试过程说明

查看node-sgement源码发现 作者建议不要对较长且无任何标点符号的文本进行分词的是发生在字典分词阶段
因为分词是通过空格换行,通配符,特殊字符进行分离处理的(正是因为有了分离,所以每次分词的文本不会很长)
而segment处理一串字符是通过循环每一个字符进行递增匹配的,从而导致匹配的的次数是成倍的增长

…一开始想问原作者没有特殊符号的长文导致时间倍增的具体原因,但是他可能很久没有维护这个包了,就没有提供有用的信息,然后只能看源码去了解了

  • 提问的issue
    https://github.com/leizongmin/node-segment/issues/36

  • node-segment 分词逻辑
  • 例子 你好我是七陌,循环次数是6+5+4+3+2+1 = (1+n)*n/2
  • 第一轮对比

    你好
    你好我
  • 第二轮对比

    好我
    好我是
    好我是七

一共分为12个分词模块

  • 6个分词模块
    url识别
    通配符识别
    标点符号
    字母/数字识别
    字典识别
  • 6个优化模块
    中文姓
    人名
    中文人名
    日期时间
    词典
    邮箱地址
  • 整体执行逻辑

每次分词会把红框中的所有模块文件执行一遍

  1. 将(空格/换行)进行分组,用于后续循环匹配字符和词性,然后进行六个阶段的分词计算
  2. url识别 地址匹配,https/http… 如果命中则进行转换,并返回数据和词性,每次从当前下标开始截取协议名称字符数,如果是http则是7个。将截取的字符进行对比,直到循环非url字符时结束。此时将这段字符的前后分成三段返回
  3. 通配符识别 通过循环遍历将命中的通配符返回,并在上层匹配通配符词性
  4. 标点符号 和通配符识别逻辑相同
  5. 字母/数字识别 将匹配的英文和数字字符使用ASCII转换,如果命中ASCII区间,则将区间对应的16进制转换为10进制作为词性并分离返回,分离后的结构和请求协议的结构相同
  6. 字典识别 将字符串的字符循环和每一个字典的内的字符进行包含性对比
    第一次先从0下标开始查找,如果未命中则字符串截取数++,如果都没有命中就将对比下标向前进一位,其中重复命中的会经过一层优化(去重打分),留下词频率最高,未识别词最少的等等
  7. 中文人名识别
  8. 人名优化

总结

当然是推荐使用nodejieba了,毕竟是目前nodejs性能最强的分词,但对机器环境依赖较为苛刻,所以建议使用docker将分词服务单独部署,进行环境依赖的隔离。
但如果更改机器配置对其他服务影响较大,且服务对性能要求没那么高的话,可以考虑使用node-segment,然后加一些避免栈溢出的代码,效果还是不错的~~

Nodejs 中文分词相关推荐

  1. elasticsearch 5.6.x单机环境构建(集成head插件和IK中文分词)

    elasticsearch近几年版本更新迭代的速度之已经超出了我的想象,想着我2016,2017年还在用着2.4.x版本,最近几年直接5.x,6.x,7.x版本了,看了一下下更新迭代的小版本时间几乎几 ...

  2. es数据库集群以及中文分词

    ##1: 集群相关名词 1.集群健康状态 绿色: 所有数据都完整,并且副本数满足 黄色: 所有数据都完整,但是有的索引副本数不满足 红色: 有的数据不完整 2.节点类型 主节点: 负责调度数据分配到哪 ...

  3. PyTorch 高级实战教程:基于 BI-LSTM CRF 实现命名实体识别和中文分词

    20210607 https://blog.csdn.net/u011828281/article/details/81171066 前言:译者实测 PyTorch 代码非常简洁易懂,只需要将中文分词 ...

  4. 一个隐马尔科夫模型的应用实例:中文分词

    什么问题用HMM解决 现实生活中有这样一类随机现象,在已知现在情况的条件下,未来时刻的情况只与现在有关,而与遥远的过去并无直接关系. 比如天气预测,如果我们知道"晴天,多云,雨天" ...

  5. Python第三方库jieba(中文分词)入门与进阶(官方文档)

    jieba "结巴"中文分词:做最好的 Python 中文分词组件 github:https://github.com/fxsjy/jieba 特点 支持三种分词模式: 精确模式, ...

  6. Lucene.net中文分词探究

    一.中文分词方式: 中文分词几种常用的方式: A. 单字分词 单字分词,顾名思义,就是按照中文一个字一个字地进行分词.如:我们是中国人,效果:我/们/是/中/国/人. B. 二分法 二分法,就是按两个 ...

  7. 正向最大匹配算法 python代码_中文分词算法之最大正向匹配算法(Python版)

    最大匹配算法是自然语言处理中的中文匹配算法中最基础的算法,分为正向和逆向,原理都是一样的. 正向最大匹配算法,故名思意,从左向右扫描寻找词的最大匹配. 首先我们可以规定一个词的最大长度,每次扫描的时候 ...

  8. 基于MMSeg算法的中文分词类库

    最近在实现基于lucene.net的搜索方案,涉及中文分词,找了很多,最终选择了MMSeg4j,但MMSeg4j只有Java版,在博客园上找到了*王员外*(http://www.cnblogs.com ...

  9. 创新工场提出中文分词和词性标注模型,性能分别刷新五大数据集| ACL 2020​

    出品 | AI科技大本营(ID:rgznai100) 中文分词和词性标注是中文自然语言处理的两个基本任务.尽管以BERT为代表的预训练模型大行其道,但事实上,中文中基于全词覆盖 (whole word ...

  10. 【NLP】为什么中文分词比英文分词更难?有哪些常用算法?(附代码)

    导读:人类文明的重要标志之一是语言文字的诞生.数千年来,几乎人类所有知识的传播都是以语言和文字作为媒介. 自然语言处理是使用计算机科学与人工智能技术分析和理解人类语言的一门学科.在人工智能的诸多范畴中 ...

最新文章

  1. 一个Java方法能有多少个参数类型?这个好奇coder做了个实验
  2. Matlab R2018a 中文版安装教程(同时适用于大部分其他版本)
  3. Jquery工作常用实例——隐藏功能实现
  4. Ubuntu12.10-amd64系统上搭建Android4.2(JellyBean)源码开发环境
  5. iOS之深入解析WKWebView加载的生命周期与代理方法
  6. matlab 自定义对象,自定义类的对象显示
  7. Leetcode-204 Count Primes
  8. spring security 的 logout 功能
  9. 精通css和css权威指南_CSS中的笔触文字:权威指南
  10. STM32MP157 u-boot2021.10移植
  11. 华为机试4.20:新员工考试
  12. 多张图片合成一张jpg工具_将多张图片合并成一张图片的小工具Collagerator
  13. 华氏度与摄氏度的转化(C语言)
  14. 投影矩阵(投影变换)解惑
  15. TFBGA240+25封装尺寸图
  16. 加拿大学校申请条件获关注,雅思专家有话说
  17. CentOS版本的Linux的安装
  18. Python-FiPy有限体积安装
  19. 用图带你了解大数据框架架构之DophinScheduler
  20. 神兵利器推荐——你一定不能错过的chrome插件

热门文章

  1. 问卷与量表数据分析(SPSS+AMOS)学习笔记(六) : SPSS 描述性统计分析
  2. Hyperscan Windows 编译指南
  3. OpenRefine安装使用
  4. r语言的runmed函数_干旱指数新宠—SPEI的C语言版、R语言版与单独执行软件SPEI Calculator...
  5. SIP的几个主要标准协议
  6. 【ENVI】FLAASH大气校正工具中比例因子说明
  7. 尺与米的长度转换python_长度转换 | 长度换算 | 公里换算 | 米换算 —在线工具...
  8. jdk32位安装包下载_iTunes 企业版12.6.5,可下载应用安装包版本和支持升级iOS 12
  9. 差分相干解调 matlab,差分相干解调
  10. MUI打开App提示音,安卓手机。mui框架。提示音