vlambda博客
学习文章列表

如何自定义ES中文分词词库?调研了一周无果后,同事告诉我只需这样点两下……


背景


作为当下最流行的全文搜索引擎,ES具备丰富的文本分析能力,其中它自带的中文分词插件 Ik分词器 在日常项目中也受到了广泛应用。


IK分词器虽然解决了很多需要中文分词的场景需求,但是它终归是基于自己的一套 默认词库 做的分词,在特定行业领域或者定制化需求中,IK的分词效果往往不能尽如人意。


如何自定义ES中文分词词库?调研了一周无果后,同事告诉我只需这样点两下……


例如使用 ik_smart蓝牙耳机 进行分词后,结果为两个词元 蓝牙耳机


这是因为在IK默认的分词词库中,存在有对应两个词元的数据信息:


如何自定义ES中文分词词库?调研了一周无果后,同事告诉我只需这样点两下……


如何自定义ES中文分词词库?调研了一周无果后,同事告诉我只需这样点两下……


如果业务需求上我们不想将 蓝牙耳机 这个词拆分,这就需要去补充和 自定义IK分词词库


分词介绍


分词器

常见中文分词器


分词器

优势

劣势

IK Analyzer

简单易用,支持自定义词典和远程词典

词库需要自行维护,不支持词性识别

https://github.com/medcl/elasticsearch-analysis-ik

Ansj

分词精准度不错,支持词性识别

对标hanlp词库略少,学习成本高

https://github.com/NLPchina/elasticsearch-analysis-ansj

jieba

新词发现功能

不支持词性识别

https://github.com/sing1ee/elasticsearch-jieba-plugin

Smart Chinese Analyzer

官方插件

中文分词效果惨不忍睹

https://artifacts.elastic.co/downloads/elasticsearch-plugins/analysis-smartcn/analysis-smartcn-7.16.1.zip

Hanlp

目前词库最完善,支持的特性非常多

需要更优的分词效果,学习成本高

https://github.com/hankcs/HanLP/releases


ElasticSearch的分词器作用是从文本中提取若干词元(token)来支持索引的存储和搜索。


分词器(Analyzer)由字符过滤器(Character Filters)、分解器(Tokenizer)和过滤器(Token Filters)组成。


如何自定义ES中文分词词库?调研了一周无果后,同事告诉我只需这样点两下……


  • 字符过滤器(Character Filters)

字符过滤器以字符流的形式接收原始文本,并可以通过添加、删除或更改字符来转换,比如去除html的特殊标记符。一个 Analyzer 可能有0个或多个字符过滤器。


  • 分解器(Tokenizer)

将字符串分解成一系列词元(Token)。比如使用 whitespace 分词器,当遇到空格时会将文本拆分成token。“eating an apple” 被分词为 [eating, an, apple]。一个 Analyzer 有且仅有一个分解器。


  • 词元过滤器(Token Filters)

针对分词后的 token 进行再一步的处理,例如转小写和增加同义词等,处理后的结果成为索引词(Term),引擎会建立索引词(Term)和源文档的倒排索引(Inverted Index),这样就能根据Term很快查到源文档了。一个 Analyzer 可能有0个或多个token过滤器。


ES自带分词器


分词器

分词策略

Standard Analyzer

默认分词器按词切分,支持多语言小写处理。

Simple Analyzer

按照非字母切分小写处理。

Whitespace Analyzer

空白字符作为分隔符

Stop Analyzer

相比Simple Analyzer,去除停用词处理,停用词指语气助词等修饰性词语,如the, an, 的 等

Keyword Analyzer

不分词,直接将输入作为一个单词输出

Pattern Analyzer

通过正则表达式自定义分隔符默认是\W+,即非字词的符号作为分隔符


除了本身含有的分词器,ES还提供了很多分词器插件。


其中IK分词器是处理中文最常见、最普遍的分词器插件。它根据本地自己维护的词典进行分词,支持两种分词形式:


  • ik_smart:将一个中文字符进行最少次数的切分。


如何自定义ES中文分词词库?调研了一周无果后,同事告诉我只需这样点两下……


  • ik_max_word:将一个中文字符进行最细粒度的切分。


如何自定义ES中文分词词库?调研了一周无果后,同事告诉我只需这样点两下……


最佳实践:索引建立时使用ik_max_smart,查询时使用ik_smart


IK 词库目录


如何自定义ES中文分词词库?调研了一周无果后,同事告诉我只需这样点两下……


该目录下带有许多文件,含义如下


  • main.dic ik原生内置的中文词库,里面有275909 条现成的词语 

  • quantifier.dic 量词和单位名称,如个,斤,克,米之类的 

  • suffix.dic 常见后缀词,如江,村,省,市,局等 

  • surname.dic 中国姓氏 

  • stopword.dic 停用词,目前默认的是写的几个英文单词,如and,a,the等

  • preposition.dic 副词、语气助词,连接词等无实际含义的词语,如却,也,是,否则之类的 


6.3.1版本的IK分词器还提供了额外的词库补充文件,extra 开头的那几个就是,默认没有使用,有需要可以在配置文件IKAnalyzer.cfg.xml上添加。


最重要的是 main.dic 和 stopword.dic。stopword(停用词)在分词时会直接被干掉,不会建立在倒排索引中。



ES提供了很多类型的分词器,但是它们的分词策略都是 插件自定义 的。


很多时候我们在业务上想要使用 自定义的词典规则 进行分词查询,这样一方面会提高查询效率,另一方面可以更加精准匹配数据。



自定义词库


1. 词库准备

  • 算法团队产出

  • 互联网开源词库

  • 爬虫获取特定领域词库


2. 词库清洗

借助第三方工具或者通过程序脚本,将文本词汇 去重(每个分词占一行),并生成 .dic 文件


3. 配置

  • 进入 ES 安装目录 /config/analysis-ik/,新建 ext.dic 文件‘


  • 打开并编辑 IKAnalyzer.cfg.xml 文件


${es_home}/config/analysis-ik/IKAnalyzer.cfg.xml


  • 将 ext.dic 词库添加到 IK 配置文件中


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>IK Analyzer 扩展配置</comment>
<!--用户可以在这里配置自己的扩展字典 -->
<entry key="ext_dict">ext.dic</entry>
<!--用户可以在这里配置自己的扩展停止词字典-->
<entry key="ext_stopwords"></entry>
<!--用户可以在这里配置远程扩展字典 -->
<entry key="remote_ext_dict">words_location</entry>
<!--用户可以在这里配置远程扩展停止词字典-->
<entry key="remote_ext_stopwords">words_location</entry>
</properties>


4. 重启ES集群

重新启动 ElasticSearch节点,验证分词效果。


如何自定义ES中文分词词库?调研了一周无果后,同事告诉我只需这样点两下……


如何自定义ES中文分词词库?调研了一周无果后,同事告诉我只需这样点两下……


由于 ES分段不可修改,新拓展的词库只对拓展后写入的数据生效。


可以通过 全量重刷数据 或者 reindex 使新词库数据全部生效。


转折???


以上是基于自建的ElasticSearch服务器,如果你买的是阿里云ES服务,只需要ES后台插件配置中新增词库就好了。




阿里云首次添加词库同样需要 重启集群

另外词库添加完成之后记得重建倒排索引更新数据哈