elasticsearch 的分词器的介绍和使用

2,276 阅读5分钟

什么是分词器

我们上一篇文章讲过倒排索引,比如我们搜 明月 ,可能会根据倒排索引 查到静夜思 这篇古诗,对吧,这里面的明月 低头 月光 ,就是分词器给我们分的词,我的理解就是,我们通过分词器给某篇文章打上了分词的tag ,然后根据tag 可以找到对应的标题,比如 新手机 华为,如果没有分词的话,我们查找 新手机华为 可能 华为新手机 就不会被搜索到,因为顺序的问题。

分词器的组成

  • character filter(字符过滤器) 在对一段文本分词之前,要先清洗一遍原始数据吧,比如html标签,什么加黑加粗加长加大中划线下划线啥的,其实我要的就是 里面的 一个词,比如 我是一个帅哥啊 其实我只需要拿到 我很帅 三个字 给分词器就行了
  • 分词器 就是 tokenizers 字符串过滤器把内容【我是一个帅哥啊】给分词器,分词器 就开始分词,比如分成了 我 是 一个 帅哥 啊

但是这里面有一些词并不是关键词,你拿这个词搜索也没有意义,比如 你想搜 我感冒了怎么办啊,为了让搜索更高效,让用户看起来更专业,我们拿到的关键词 应该是 感冒 怎么办 而不是 怎么办啊 或者啊,所以需要对分词之后的结果再进行过滤,这个时候就要用到分词过滤器

  • token filers 就是 分词过滤器,完成对无用词的过滤

Elastic 默认支持九种不同的分词模式

  • stardard(过滤标点符号) 在这里插入图片描述

  • simple (过滤标点符号和数字,只剩下字母了) 在这里插入图片描述

  • whitespace (空格分词,不过滤内容) 在这里插入图片描述

  • stop(过滤标点符号,数字,过滤语气词,停顿词) 在这里插入图片描述

  • keyword (将内容作为一个整体,不做任何处理,所以这也是为什么keyword 用于精准匹配) 在这里插入图片描述

  • patter(正则匹配,参考java的正则匹配规则) 在该栗子中,只过滤数字 在这里插入图片描述

  • fingerprint(转小写 去重 过滤停止词,排序) 在这里插入图片描述

  • 支持30多种常见语言的分词器(没有中文)

  • 支持自定义分词器

IK分词器

  • 此处我们再解释一遍为什么要用分词,如果不用分词,我们其实也可以搜素,比如下面这个栗子,我搜索华为的时候,我爱中华的文档也被搜索了出来,我显然不是我要的,但是为什么会出现这种取情况呢?我们看中文返回的分词是什么

在这里插入图片描述

在这里插入图片描述 我们发现es对汉字默认是单个拆分的,你搜索华为,本来搜索的是华为相关的条目,单个拆分之后 ,就会把包含华和为两个字的都查找出来,这明显不是我们想要的,所以我们需要分词来达到更精准的匹配

  • ElasticSearch 对于英文分词天生就有了,因为老外生来就用外语,那么中文怎么办呢?IK分词器在2006年推出了1.0版本。 IK Analyzer是一个开源的,基于java语言开发的轻量级的中文分词工具包。被一个叫medcl(曾勇 elastic开发工程师与布道师,elasticsearch开源社区负责人,2015年加入elastic)的人集成到了elasticsearch中, 并支持自定义字。 IK分词器的安装github上面搜索github.com/medcl/elast… 或者官方网站下载包,博主被第三方的包坑了两三个小时

  • 装过ik 分词之后我们再查看

  • 在这里插入图片描述

  • 但是,此时你搜索华为 是搜索不出来的,因为在创建文档的时候就没有 对 我爱华为 建立 华为的分词索引,我们删除重新创建 在这里插入图片描述

搜索华为的时候 我爱中华 条目没有出现,只找到了一条我爱华为,记住,文档在创建的时候生成倒排索引,所以我们在创建文档的时候最好是先 勾勒出来你需要的数据模型,根据模型选择数据字段的类型,合适的分词,有了合适的结构才会有合适的索引,有了合适的索引才会提供合适发服务。之前我见有朋友没有mapping就插入数据,其实这个时候系统也动态生成了mapping ,但是这个maping 不一定符合你的要求。比如咱们刚才的分词,你创建索引的时候就是 按照 单个字 创立的索引,那么这个时候你搜索 华为 作为一个词去匹配,就会匹配不到。

在这里插入图片描述

IK分词器的相关配置

  • 我们看一下目录
[elastic@localhost config]$ ls
extra_main.dic  extra_single_word.dic  extra_single_word_full.dic  extra_single_word_low_freq.dic  extra_stopword.dic  IKAnalyzer.cfg.xml  main.dic  preposition.dic  quantifier.dic  stopword.dic  suffix.dic  surname.dic
[elastic@localhost config]$ pwd
/home/elastic/elasticsearch2/plugins/ik/config

IKAnalyzer.cfg.xml:用来配置自定义词库

<?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">dic/hehe.dic;dic/haha.dic</entry>
         <!--用户可以在这里配置自己的扩展停止词字典 比如 啊 呢 哦 无效词 -->
     <entry key="ext_stopwords">dic/stop.dic</entry>
        <!--用户可以在这里配置远程扩展字典 配置自己的远程扩展词 -->
    <entry key="remote_ext_dict">http://m.dic.cn/ext.txt</entry>
        <!--用户可以在这里配置远程扩展停止词字典-->
        <!-- <entry key="remote_ext_stopwords">http://m.dic.cn/stop.txt</entry> -->
</properties>
  • 这里可以简单举个栗子看一下,比如 香菇蓝瘦,我们先来看一下 在这里插入图片描述
  • 我现在来配置一下文件,使用远程扩展词库(注意,如果修改或者新增了远程词库的地址,则需要重启,如果地址没变,只是进行了补充,则无需重启)
  • 看一下我的远程地址(注意,为了避免浏览器访问txt 乱码,在nginx的server里面加上charset 'utf-8';在这里插入图片描述 我的配置文件如下,配置了一个远程扩展词典
<?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"></entry>
         <!--用户可以在这里配置自己的扩展停止词字典-->
        <entry key="ext_stopwords"></entry>
        <!--用户可以在这里配置远程扩展字典 -->
        <entry key="remote_ext_dict">https://0e2d-222-129-5-131.ngrok.io/ext.txt</entry>
        <!--用户可以在这里配置远程扩展停止词字典-->
        <!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>

在这里插入图片描述

  • 我在远程词典添加一个词 技术小虫 在这里插入图片描述

在这里插入图片描述

main.dic

ik原生内置的中文词库,总共有27万多条,只要是这些单词,都会被分在一起

quantifier.dic

放了一些单位相关的词

suffix.dic

放了一些后缀

surname.dic

中国的姓氏

stopword.dic

英文停用词