Elasticsearch进阶笔记第十六篇

152 阅读6分钟

Elasticsearch高手进阶篇(30)

彻底掌握IK中文分词_上机动手实战IK中文分词器的安装和使用

ik分词器

中国人,其实我们用来进行搜索的,绝大多数,都是中文应用,很少做英文的 standard没有办法对中文进行合理分词的,只是将每个中文字符一个一个的切割开来,比如说中国人 --> 中 国 人

  • 英语的也要学:所以说,我们利用核心知识篇的相关的知识,来把es这种英文原生的搜索引擎,先学一下; 因为有些知识点,可能用英文讲更靠谱

    • 比如说analyzed,palyed,students --> stemmer,analyze,play,student。有些知识点,仅仅适用于英文,不太适用于中文

从这一讲开始,大家就会觉得很爽,因为全部都是我们熟悉的中文了,没有英文了,高阶知识点,搜索,聚合,全部是中文了

在搜索引擎领域,比较成熟和流行的,就是ik分词器

  • 中国人很喜欢吃油条

    • standard:中 国 人 很 喜 欢 吃 油 条
    • ik:中国人 很 喜欢 吃 油条

在elasticsearch中安装ik中文分词器

  • git clone github.com/medcl/elast…
  • git checkout tags/v5.2.0
  • mvn package
  • 将target/releases/elasticsearch-analysis-ik-5.2.0.zip拷贝到es/plugins/ik目录下
  • 在es/plugins/ik下对elasticsearch-analysis-ik-5.2.0.zip进行解压缩
  • 重启es

image.png

ik分词器基础知识

两种analyzer,你根据自己的需要自己选吧,但是一般是选用ik_max_word

  • ik_max_word: 会将文本做最细粒度的拆分,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,中华人民,中华,华人,人民共和国,人民,人,民,共和国,共和,和,国国,国歌”,会穷尽各种可能的组合;
  • ik_smart: 会做最粗粒度的拆分,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,国歌”。

ik分词器的使用

 PUT /waws_ik_index 
 {
   "mappings": {
     "waws_type": {
       "properties": {
         "text": {
           "type": "text",
           "analyzer": "ik_max_word"
         }
       }
     }
   }
 }
  • 添加数据
 POST /waws_ik_index/waws_type/_bulk
 { "index": { "_id": "1"} }
 { "text": "男子偷上万元发红包求交女友 被抓获时仍然单身" }
 { "index": { "_id": "2"} }
 { "text": "16岁少女为结婚“变”22岁 7年后想离婚被法院拒绝" }
 { "index": { "_id": "3"} }
 { "text": "深圳女孩骑车逆行撞奔驰 遭索赔被吓哭(图)" }
 { "index": { "_id": "4"} }
 { "text": "女人对护肤品比对男票好?网友神怼" }
 { "index": { "_id": "5"} }
 { "text": "为什么国内的街道招牌用的都是红黄配?" }
  • 使用分词器进行分词
 GET /waws_ik_index/_analyze
 {
   "text": "男子偷上万元发红包求交女友 被抓获时仍然单身",
   "analyzer": "ik_max_word"
 }
 ​
 {
   "tokens": [
     {
       "token": "男子",
       "start_offset": 0,
       "end_offset": 2,
       "type": "CN_WORD",
       "position": 0
     },
     {
       "token": "偷上",
       "start_offset": 2,
       "end_offset": 4,
       "type": "CN_WORD",
       "position": 1
     },
     {
       "token": "上万",
       "start_offset": 3,
       "end_offset": 5,
       "type": "CN_WORD",
       "position": 2
     },
     {
       "token": "万元",
       "start_offset": 4,
       "end_offset": 6,
       "type": "CN_WORD",
       "position": 3
     },
     {
       "token": "万",
       "start_offset": 4,
       "end_offset": 5,
       "type": "CN_WORD",
       "position": 4
     },
     {
       "token": "元",
       "start_offset": 5,
       "end_offset": 6,
       "type": "CN_CHAR",
       "position": 5
     },
     {
       "token": "发红包",
       "start_offset": 6,
       "end_offset": 9,
       "type": "CN_WORD",
       "position": 6
     },
     {
       "token": "发红",
       "start_offset": 6,
       "end_offset": 8,
       "type": "CN_WORD",
       "position": 7
     },
     {
       "token": "发",
       "start_offset": 6,
       "end_offset": 7,
       "type": "CN_WORD",
       "position": 8
     },
     {
       "token": "红包",
       "start_offset": 7,
       "end_offset": 9,
       "type": "CN_WORD",
       "position": 9
     },
     {
       "token": "求",
       "start_offset": 9,
       "end_offset": 10,
       "type": "CN_CHAR",
       "position": 10
     },
     {
       "token": "交",
       "start_offset": 10,
       "end_offset": 11,
       "type": "CN_CHAR",
       "position": 11
     },
     {
       "token": "女友",
       "start_offset": 11,
       "end_offset": 13,
       "type": "CN_WORD",
       "position": 12
     },
     {
       "token": "抓获",
       "start_offset": 15,
       "end_offset": 17,
       "type": "CN_WORD",
       "position": 13
     },
     {
       "token": "获",
       "start_offset": 16,
       "end_offset": 17,
       "type": "CN_WORD",
       "position": 14
     },
     {
       "token": "时",
       "start_offset": 17,
       "end_offset": 18,
       "type": "CN_CHAR",
       "position": 15
     },
     {
       "token": "仍然",
       "start_offset": 18,
       "end_offset": 20,
       "type": "CN_WORD",
       "position": 16
     },
     {
       "token": "单身",
       "start_offset": 20,
       "end_offset": 22,
       "type": "CN_WORD",
       "position": 17
     }
   ]
 }
  • 进行搜索
 GET /waws_ik_index/waws_type/_search 
 {
   "query": {
     "match": {
       "text": "16岁少女结婚好还是单身好?"
     }
   }
 }
 
 {
   "took": 29,
   "timed_out": false,
   "_shards": {
     "total": 5,
     "successful": 5,
     "failed": 0
   },
   "hits": {
     "total": 3,
     "max_score": 3.603062,
     "hits": [
       {
         "_index": "waws_ik_index",
         "_type": "waws_type",
         "_id": "2",
         "_score": 3.603062,
         "_source": {
           "text": "16岁少女为结婚“变”22岁 7年后想离婚被法院拒绝"
         }
       },
       {
         "_index": "waws_ik_index",
         "_type": "waws_type",
         "_id": "4",
         "_score": 1.3862944,
         "_source": {
           "text": "女人对护肤品比对男票好?网友神怼"
         }
       },
       {
         "_index": "waws_ik_index",
         "_type": "waws_type",
         "_id": "1",
         "_score": 0.2699054,
         "_source": {
           "text": "男子偷上万元发红包求交女友 被抓获时仍然单身"
         }
       }
     ]
   }
 }

Elasticsearch高手进阶篇(31)

彻底掌握IK中文分词_IK分词器配置文件讲解以及自定义词库实战

ik配置文件

  • ik配置文件地址:es/plugins/ik/config目录

    • IKAnalyzer.cfg.xml:用来配置自定义词库
    • main.dic:ik原生内置的中文词库,总共有27万多条,只要是这些单词,都会被分在一起
    • quantifier.dic:放了一些单位相关的词
    • suffix.dic:放了一些后缀
    • surname.dic:中国的姓氏
    • stopword.dic:英文停用词
  • ik原生最重要的两个配置文件

    • main.dic:包含了原生的中文词语,会按照这个里面的词语去分词
    • stopword.dic:包含了英文的停用词
  • 停用词,stopword

    • a the and at but
    • 一般,像停用词,会在分词的时候,直接被干掉,不会建立在倒排索引中

自定义词库

  • 自己建立词库每年都会涌现一些特殊的流行词,网红,蓝瘦香菇,喊麦,鬼畜,一般不会在ik的原生词典里

    • 自己补充自己的最新的词语,到ik的词库里面去
    • IKAnalyzer.cfg.xml:ext_dict,custom/mydict.dic image.png
    • 补充自己的词语,然后需要重启es,才能生效 image.png
    • 验证自己的测试
     GET /waws_ik_index/_analyze
     {
       "text": "蓝瘦香菇",
       "analyzer": "ik_max_word"
     }
     ​
     {
       "tokens": [
         {
           "token": "蓝瘦香菇",
           "start_offset": 0,
           "end_offset": 4,
           "type": "CN_WORD",
           "position": 0
         },
         {
           "token": "蓝",
           "start_offset": 0,
           "end_offset": 1,
           "type": "CN_WORD",
           "position": 1
         },
         {
           "token": "瘦",
           "start_offset": 1,
           "end_offset": 2,
           "type": "CN_WORD",
           "position": 2
         },
         {
           "token": "香菇",
           "start_offset": 2,
           "end_offset": 4,
           "type": "CN_WORD",
           "position": 3
         },
         {
           "token": "香",
           "start_offset": 2,
           "end_offset": 3,
           "type": "CN_WORD",
           "position": 4
         },
         {
           "token": "菇",
           "start_offset": 3,
           "end_offset": 4,
           "type": "CN_WORD",
           "position": 5
         }
       ]
     }
    
  • 自己建立停用词库:比如了,的,啥,么,我们可能并不想去建立索引,让人家搜索

    • custom/ext_stopword.dic,已经有了常用的中文停用词,可以补充自己的停用词,然后重启es(和上面定义自定义词库是一样的)

Elasticsearch高手进阶篇(32)

彻底掌握IK中文分词_修改IK分词器源码来基于mysql热更新词库

这一讲并没有上手实战,好多的东西都是java的,以后在进行研究

热更新

  • 每次都是在es的扩展词典中,手动添加新词语,很坑

    • 每次添加完,都要重启es才能生效,非常麻烦
    • es是分布式的,可能有数百个节点,你不能每次都一个一个节点上面去修改
  • es不停机,直接我们在外部某个地方添加新的词语,es中立即热加载到这些新词语

热更新的方案
  • 修改ik分词器源码,然后手动支持从mysql中每隔一定时间,自动加载新的词库
  • 基于ik分词器原生支持的热更新方案,部署一个web服务器,提供一个http接口,通过modified和tag两个http响应头,来提供词语的热更新

用第一种方案,第二种,ik git社区官方都不建议采用,觉得不太稳定

下载源码

github.com/medcl/elast…

ik分词器,是个标准的java maven工程,直接导入eclipse就可以看到源码

修改源码

  • Dictionary类,169行:Dictionary单例类的初始化方法,在这里需要创建一个我们自定义的线程,并且启动它
  • HotDictReloadThread类:就是死循环,不断调用Dictionary.getSingleton().reLoadMainDict(),去重新加载词典
  • Dictionary类,389行:this.loadMySQLExtDict();
  • Dictionary类,683行:this.loadMySQLStopwordDict();

其他步骤

  • mvn package打包代码

    • target\releases\elasticsearch-analysis-ik-5.2.0.zip
  • 解压缩ik压缩包

    • 将mysql驱动jar,放入ik的目录下
  • 修改jdbc相关配置

  • 重启es

    • 观察日志,日志中就会显示我们打印的那些东西,比如加载了什么配置,加载了什么词语,什么停用词
  • 在mysql中添加词库与停用词

  • 分词实验,验证热更新生效