ElasticSearch默认就有标准的英文分词器。
但是对于母语是非英语的人来说,光有英文分词器是远远不够的。
因此各国家的程序员都会开发对应自己母语的分词插件来增强ElasticSearch的分词功能
不管何种自然语言的分词器,无外乎由下列三部分组成
而底层依赖的都是分词算法。
本项目使用的分词算法是 HanLP
,作者何晗。
具体官网地址可见 HanLP,号称是最好的中文分词算法。
除此之外,分词器应该还具有一些附加功能,比如下列两个功能
HanLP
简单介绍HanLP
是一系列模型与算法组成的 NLP
(自然语言处理)
工具包,具备功能完善、性能高效、架构清晰、语料时新、可自定义特点,详情可参考 HanLP github
地址
选择它作为本项目底层分词算法理由如下
见下图
assemblies
: 插件打包(plugin.xml
)配置文件com.wujunshen.core
: 分词插件核心类com.wujunshen.dictionary
: 同义词字典类com.wujunshen.enumation
: 涉及的枚举com.wujunshen.exception
: 自定义异常com.wujunshen.nature
: 自然分词属性com.wujunshen.plugin
: 分词插件定义com.wujunshen.update
: 热词更新处理类com.wujunshen.utils
: 涉及的工具类resources
: 插件属性文件所在目录。包括插件配置、HanLP
的热词更新配置、Java
安全策略、logback
日志配置等文件test
下的com.wujunshen.entity
和MyAnalyzerTest
: 使用JUnit5
编写的单元测试方法其中具体说明一下私有方法 analyze
private List<Token> analyze(SegmentationType segmentationType, String text) throws IOException {
Tokens result = new Tokens();
List<Token> resultList = new ArrayList<>();
Analyzer analyzer = new MyAnalyzer(segmentationType);
TokenStream tokenStream = analyzer.tokenStream("text", text);
tokenStream.reset();
while (tokenStream.incrementToken()) {
CharTermAttribute charTermAttribute = tokenStream.getAttribute(CharTermAttribute.class);
TypeAttribute typeAttribute = tokenStream.getAttribute(TypeAttribute.class);
OffsetAttribute offsetAttribute = tokenStream.getAttribute(OffsetAttribute.class);
PositionIncrementAttribute positionIncrementAttribute =
tokenStream.getAttribute(PositionIncrementAttribute.class);
Token token = new Token();
token.setToken(charTermAttribute.toString());
token.setStartOffset(offsetAttribute.startOffset());
token.setEndOffset(offsetAttribute.endOffset());
token.setType(typeAttribute.type());
token.setPosition(positionIncrementAttribute.getPositionIncrement());
resultList.add(token);
}
tokenStream.close();
result.setTokens(resultList);
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
log.info("{}\n", objectMapper.writeValueAsString(result));
return resultList;
}
Analyzer
类是一个抽象类,是所有分词器基类,通过 TokenStream
类将文本转换为词汇单元流。
TokenStream
使用流程TokenStream
, 向 AttributeSource
添加属性(词汇单元文本text
、位置增量position
、偏移量offset
、词汇类型type
等)reset
方法, 将流(stream
)重置到原始(clean
)状态incrementToken
方法,处理 Attribute
属性信息close
方法释放资源注意 由上可知 我们需要重点关注
TokenStream
的实例化、reset
、incrementToken
和close
这几个方法实现
plugin-security.policy
文件可见前述代码结构的图里,需要放置在 resources
目录下。
这样打包后才会在插件根目录下。
但是实际执行时,ElasticSearch
的日志会报 AccessControlException
错误,这个可能是远程加载自定义分词字典(见README.md
文件中所述的nginx
静态内容网站搭建内容)
时,需要网路连接权限。
因此我在 MyTokenizer.java
中,加入了下列代码,如果显示正常,则说明远程加载分词字典成功
static {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new SpecialPermission());
}
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
Nature.create("auxiliary");
return null;
});
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
nlpSegment = HanLP.newSegment()
// 词性标注
.enablePartOfSpeechTagging(true)
// 计算偏移量
.enableOffset(true)
// 中文人名识别
.enableNameRecognize(true)
// 日本人名识别
.enableJapaneseNameRecognize(true)
// 数量词识别
.enableNumberQuantifierRecognize(true)
// 机构名识别
.enableOrganizationRecognize(true)
// 音译人名识别
.enableTranslatedNameRecognize(true);
indexSegment = HanLP.newSegment()
.enableIndexMode(true)
// 词性标注
.enablePartOfSpeechTagging(true)
// 计算偏移量
.enableOffset(true);
// 在此处显示调用一下分词,使得加载词典、缓存词典的操作可以正确执行
log.info(String.valueOf(nlpSegment.seg("HanLP中文分词工具包!")));
log.info(String.valueOf(indexSegment.seg("HanLP中文分词工具包!")));
return null;
});
}
本项目功能可总结为下列这些
nginx
静态内容网站)本项目单元测试类 MyAnalyzerTest.java 所使用的文本解析内容,来源于倪匡老先生的小说: 卫斯理系列中的《透明光》第一章
老先生的具体生平可见 百度百科
向刚去世不久的倪匡老先生致以崇高的敬意~
R.I.P
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。