美文网首页
elasticsearch之八分词器

elasticsearch之八分词器

作者: Java及SpringBoot | 来源:发表于2020-03-06 15:46 被阅读0次

    个人专题目录


    1. 中文分词器 IK分词器

    1.1 分词器 analyzer

    什么是分词器 analyzer

    分词器是一个字符串解析拆分工具。其作用是分析写入的Document中的文本数据field,并将field数据拆分成一个个有完整含义的、不可拆分的单词。

    作用:切分词语,normalization(提升recall召回率)

    给你一段句子,然后将这段句子拆分成一个一个的单个的单词,同时对每个单词进行normalization(时态转换,单复数转换)

    recall,召回率:搜索的时候,增加能够搜索到的结果的数量

    analyzer 组成部分:

    1. character filter:在一段文本进行分词之前,先进行预处理,比如说最常见的就是,过滤html标签(<span>hello<span> --> hello),& --> and(I&you --> I and you)

    2. tokenizer:分词,hello you and me --> hello, you, and, me

    3. token filter:lowercase,stop word,synonymom,dogs --> dog,liked --> like,Tom --> tom,a/the/an --> 干掉,mother --> mom,small --> little

    一个分词器,很重要,将一段文本进行各种处理,最后处理好的结果才会拿去建立倒排索引。

    内置分词器的介绍

    要切分的语句:Set the shape to semi-transparent by calling set_trans(5)

    standard analyzer - 是Elasticsearch中的默认分词器。标准分词器,处理英语语法的分词器。切分后的key_words:set, the, shape, to, semi, transparent, by, calling, set_trans, 5。这种分词器也是Elasticsearch中默认的分词器。切分过程中不会忽略停止词(如:the、a、an等)。会进行单词的大小写转换、过滤连接符(-)或括号等常见符号。

    GET _analyze
    {
     "text": "Set the shape to semi-transparent by calling set_trans(5)",
     "analyzer": "standard"
    }
    

    simple analyzer - 简单分词器。切分后的key_words:set, the, shape, to, semi, transparent, by, calling, set, trans。就是将数据切分成一个个的单词。使用较少,经常会破坏英语语法。

    GET _analyze
    {
     "text": "Set the shape to semi-transparent by calling set_trans(5)",
     "analyzer": "simple"
    }
    

    whitespace analyzer - 空白符分词器。切分后的key_words:Set, the, shape, to, semi-transparent, by, calling, set_trans(5)。就是根据空白符号切分数据。如:空格、制表符等。使用较少,经常会破坏英语语法。

    GET _analyze
    {
     "text": "Set the shape to semi-transparent by calling set_trans(5)",
     "analyzer": "whitespace"
    }
    

    language analyzer - 语言分词器,如英语分词器(english)等。切分后的key_words:set, shape, semi, transpar, call, set_tran, 5。根据英语语法分词,会忽略停止词、转换大小写、单复数转换、时态转换等,应用分词器分词功能类似standard analyzer。

    GET _analyze
    {
     "text": "Set the shape to semi-transparent by calling set_trans(5)",
     "analyzer": "english"
    }
    

    注意:Elasticsearch中提供的常用分词器都是英语相关的分词器,对中文的分词都是一字一词。

    测试分词器

    GET /_analyze
    {
      "analyzer": "standard",
      "text": "Text to analyze 80"
    }
    

    返回值:

    {
      "tokens" : [
        {
          "token" : "text",
          "start_offset" : 0,
          "end_offset" : 4,
          "type" : "<ALPHANUM>",
          "position" : 0
        },
        {
          "token" : "to",
          "start_offset" : 5,
          "end_offset" : 7,
          "type" : "<ALPHANUM>",
          "position" : 1
        },
        {
          "token" : "analyze",
          "start_offset" : 8,
          "end_offset" : 15,
          "type" : "<ALPHANUM>",
          "position" : 2
        },
        {
          "token" : "80",
          "start_offset" : 16,
          "end_offset" : 18,
          "type" : "<NUM>",
          "position" : 3
        }
      ]
    }
    

    token 实际存储的term 关键字

    position 在此词条在原文本中的位置

    start_offset/end_offset字符在原始字符串中的位置

    修改分词器的设置

    启用english停用词token filter

    PUT /my_index
    {
      "settings": {
        "analysis": {
          "analyzer": {
            "es_std": {
              "type": "standard",
              "stopwords": "_english_"
            }
          }
        }
      }
    }
    

    测试分词

    GET /my_index/_analyze
    {
      "analyzer": "standard", 
      "text": "a dog is in the house"
    }
    
    GET /my_index/_analyze
    {
      "analyzer": "es_std",
      "text":"a dog is in the house"
    }
    

    定制化自己的分词器

    PUT /my_index
    {
      "settings": {
        "analysis": {
          "char_filter": {
            "&_to_and": {
              "type": "mapping",
              "mappings": ["&=> and"]
            }
          },
          "filter": {
            "my_stopwords": {
              "type": "stop",
              "stopwords": ["the", "a"]
            }
          },
          "analyzer": {
            "my_analyzer": {
              "type": "custom",
              "char_filter": ["html_strip", "&_to_and"],
              "tokenizer": "standard",
              "filter": ["lowercase", "my_stopwords"]
            }
          }
        }
      }
    }
    

    测试

    GET /my_index/_analyze
    {
      "analyzer": "my_analyzer",
      "text": "tom&jerry are a friend in the house, <a>, HAHA!!"
    }
    

    设置字段使用自定义分词器

    PUT /my_index/_mapping/
    {
      "properties": {
        "content": {
          "type": "text",
          "analyzer": "my_analyzer"
        }
      }
    }
    

    2. 中文分词器 IK分词器

    • IKAnalyzer 是一个开源的,基于 java 语言开发的轻量级的中文分词工具包
    • 是一个基于 Maven 构建的项目
    • 具有 60 万字 秒的高速处理能力
    • 支持用户词典扩展定义

    2.1 Ik分词器安装使用

    中文分词器

    standard 分词器,仅适用于英文。

    GET /_analyze
    {
      "analyzer": "standard",
      "text": "中华人民共和国人民大会堂"
    }
    

    我们想要的效果是什么:中华人民共和国,人民大会堂

    IK分词器就是目前最流行的es中文分词器

    3. IK分词器安装

    3.1 环境准备

    Elasticsearch 要使用 ik,就要先构建 ik 的 jar包,这里要用到 maven 包管理工具,而 maven 需要java 环境,而 Elasticsearch 内置了jdk, 所以可以将JAVA_HOME设置为Elasticsearch 内置的jdk

    1)设置JAVA_HOME

    vim /etc/profile
    # 在profile文件末尾添加
    #java environment
    export JAVA_HOME=/opt/elasticsearch-7.4.0/jdk
    export PATH=$PATH:${JAVA_HOME}/bin
    
    # 保存退出后,重新加载profile
    source /etc/profile
    
    

    2)下载maven安装包

    wget http://mirror.cc.columbia.edu/pub/software/apache/maven/maven-3/3.1.1/binaries/apache-maven-3.1.1-bin.tar.gz  
    

    3)解压maven安装包

    tar xzf apache-maven-3.1.1-bin.tar.gz 
    

    4)设置软连接

    ln -s apache-maven-3.1.1 maven 
    

    5)设置path

    打开文件

     vim  /etc/profile.d/maven.sh
    

    将下面的内容复制到文件,保存

    export MAVEN_HOME=/opt/maven  
    export PATH=${MAVEN_HOME}/bin:${PATH} 
    

    设置好Maven的路径之后,需要运行下面的命令使其生效

    source /etc/profile.d/maven.sh
    

    6)验证maven是否安装成功

    mvn -v
    

    3.2 安装IK分词器

    1)下载IK

    wget https://github.com/medcl/elasticsearch-analysis-ik/archive/v7.4.0.zip
    

    执行如下图:

    2)解压IK

    由于这里是zip包不是gz包,所以我们需要使用unzip命令进行解压,如果本机环境没有安装unzip,请执行:

    yum install zip 
    yum install unzip
    

    解压IK

    unzip v7.4.0.zip
    

    3)编译jar包

    # 切换到 elasticsearch-analysis-ik-7.4.0目录
    cd elasticsearch-analysis-ik-7.4.0/
    #打包
    mvn package
    

    4) jar包移动

    package执行完毕后会在当前目录下生成target/releases目录,将其中的elasticsearch-analysis-ik-7.4.0.zip。拷贝到elasticsearch目录下的新建的目录plugins/analysis-ik,并解压

    #切换目录
    cd /opt/elasticsearch-7.4.0/plugins/
    #新建目录
    mkdir analysis-ik
    cd analysis-ik
    #执行拷贝
    cp -R /opt/elasticsearch-analysis-ik-7.4.0/target/releases/elasticsearch-analysis-ik-7.4.0.zip      /opt/elasticsearch-7.4.0/plugins/analysis-ik
    #执行解压
    unzip  /opt/elasticsearch-7.4.0/plugins/analysis-ik/elasticsearch-analysis-ik-7.4.0.zip
    

    5)拷贝辞典

    将elasticsearch-analysis-ik-7.4.0目录下的config目录中的所有文件 拷贝到elasticsearch的config目录

    cp -R /opt/elasticsearch-analysis-ik-7.4.0/config/*   /opt/elasticsearch-7.4.0/config
    

    记得一定要重启Elasticsearch!!!

    3.3 使用IK分词器

    IK分词器有两种分词模式:ik_max_word和ik_smart模式。

    1、ik_max_word

    会将文本做最细粒度的拆分,比如会将“乒乓球明年总冠军”拆分为“乒乓球、乒乓、球、明年、总冠军、冠军。

    #方式一ik_max_word
    GET /_analyze
    {
      "analyzer": "ik_max_word",
      "text": "乒乓球明年总冠军"
    }
    

    ik_max_word分词器执行如下:

    {
      "tokens" : [
        {
          "token" : "乒乓球",
          "start_offset" : 0,
          "end_offset" : 3,
          "type" : "CN_WORD",
          "position" : 0
        },
        {
          "token" : "乒乓",
          "start_offset" : 0,
          "end_offset" : 2,
          "type" : "CN_WORD",
          "position" : 1
        },
        {
          "token" : "球",
          "start_offset" : 2,
          "end_offset" : 3,
          "type" : "CN_CHAR",
          "position" : 2
        },
        {
          "token" : "明年",
          "start_offset" : 3,
          "end_offset" : 5,
          "type" : "CN_WORD",
          "position" : 3
        },
        {
          "token" : "总冠军",
          "start_offset" : 5,
          "end_offset" : 8,
          "type" : "CN_WORD",
          "position" : 4
        },
        {
          "token" : "冠军",
          "start_offset" : 6,
          "end_offset" : 8,
          "type" : "CN_WORD",
          "position" : 5
        }
      ]
    }
    
    

    2、ik_smart
    会做最粗粒度的拆分,比如会将“乒乓球明年总冠军”拆分为乒乓球、明年、总冠军。

    #方式二ik_smart
    GET /_analyze
    {
      "analyzer": "ik_smart",
      "text": "乒乓球明年总冠军"
    }
    

    ik_smart分词器执行如下:

    {
      "tokens" : [
        {
          "token" : "乒乓球",
          "start_offset" : 0,
          "end_offset" : 3,
          "type" : "CN_WORD",
          "position" : 0
        },
        {
          "token" : "明年",
          "start_offset" : 3,
          "end_offset" : 5,
          "type" : "CN_WORD",
          "position" : 1
        },
        {
          "token" : "总冠军",
          "start_offset" : 5,
          "end_offset" : 8,
          "type" : "CN_WORD",
          "position" : 2
        }
      ]
    }
    
    

    由此可见 使用ik_smart可以将文本"text": "乒乓球明年总冠军"分成了【乒乓球】【明年】【总冠军】

    这样看的话,这样的分词效果达到了我们的要求。

    ik分词器基础知识

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

    ik_smart: 会做最粗粒度的拆分,比如会将“中华人民共和国人民大会堂”拆分为“中华人民共和国,人民大会堂”。

    ik分词器的使用

    存储时,使用ik_max_word,搜索时,使用ik_smart

    PUT /my_index 
    {
      "mappings": {
          "properties": {
            "text": {
              "type": "text",
              "analyzer": "ik_max_word",
              "search_analyzer": "ik_smart"
            }
          }
      }
    }
    

    搜索

    GET /my_index/_search?q=中华人民共和国人民大会堂
    

    3.4 ik配置文件

    ik配置文件

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

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

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

    preposition.dic: 介词

    quantifier.dic:放了一些单位相关的词,量词

    suffix.dic:放了一些后缀

    surname.dic:中国的姓氏

    stopword.dic:英文停用词

    ik原生最重要的两个配置文件

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

    stopword.dic:包含了英文的停用词

    停用词,stopword

    a the and at but

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

    自定义词库

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

    自己补充自己的最新的词语,到ik的词库里面

    IKAnalyzer.cfg.xml:ext_dict,创建mydict.dic。

    补充自己的词语,然后需要重启es,才能生效

    (2)自己建立停用词库:比如了,的,啥,么,我们可能并不想去建立索引,让人家搜索

    custom/ext_stopword.dic,已经有了常用的中文停用词,可以补充自己的停用词,然后重启es

    3.5 使用mysql热更新 词库

    热更新

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

    (1)每次添加完,都要重启es才能生效,非常麻烦

    (2)es是分布式的,可能有数百个节点,你不能每次都一个一个节点上面去修改

    es不停机,直接我们在外部某个地方添加新的词语,es中立即热加载到这些新词语

    热更新的方案

    (1)基于ik分词器原生支持的热更新方案,部署一个web服务器,提供一个http接口,通过modified和tag两个http响应头,来提供词语的热更新

    (2)修改ik分词器源码,然后手动支持从mysql中每隔一定时间,自动加载新的词库

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

    步骤

    1、下载源码

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

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

    2、修改源

    org.wltea.analyzer.dic.Dictionary类,160行Dictionary单例类的初始化方法,在这里需要创建一个我们自定义的线程,并且启动它

    org.wltea.analyzer.dic.HotDictReloadThread类:就是死循环,不断调用Dictionary.getSingleton().reLoadMainDict(),去重新加载词典

    Dictionary类,399行:this.loadMySQLExtDict(); 加载mymsql字典。

    Dictionary类,609行:this.loadMySQLStopwordDict();加载mysql停用词

    config下jdbc-reload.properties。mysql配置文件

    3、mvn package打包代码

    target\releases\elasticsearch-analysis-ik-7.3.0.zip

    4、解压缩ik压缩包

    将mysql驱动jar,放入ik的目录下

    5、修改jdbc相关配置

    6、重启es

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

    7、在mysql中添加词库与停用词

    8、分词实验,验证热更新生效

    GET /_analyze
    {
      "analyzer": "ik_smart",
      "text": "播客"
    }
    

    相关文章

      网友评论

          本文标题:elasticsearch之八分词器

          本文链接:https://www.haomeiwen.com/subject/bznirhtx.html