elasticsearch安装ik中文分词器

发布时间:2021-04-22 13:15:31编辑:admin阅读(3455)

    一、概述

    elasticsearch官方默认的分词插件,对中文分词效果不理想。

    中文的分词器现在大家比较推荐的就是 IK分词器,当然也有些其它的比如 smartCN、HanLP。

    这里只讲如何使用IK做为中文分词。

     

    二、安装elasticsearch

    环境说明

    操作系统:centos 7.6

    docker版本:19.03.12

    ip地址:192.168.31.165

     

    安装

    这里安装7.10.1版本

    下载镜像

    docker pull elasticsearch:7.5.1

     

    修改系统参数

    vi /etc/sysctl.conf

    调整参数

    vm.max_map_count=262144

    刷新参数

    sysctl -p

     

    注意,系统参数一定要修改,否则参数过低,会造成elasticsearch启动失败。

     

    配置文件

    mkdir -p /data/elk7/elasticsearch/{data,logs,config,plugins}
    vi /data/elk7/elasticsearch/config/elasticsearch.yml

    内容如下:

    cluster.name: "docker-cluster"
    network.host: 0.0.0.0

     

    启动elasticsearch

    以单例模式启动

    docker run -d --name=elasticsearch \
    -p 9200:9200 -p 9300:9300 \
    -e "discovery.type=single-node" elasticsearch:7.10.1

    等待30秒左右,查看docker日志,是否有错误日志

     

    访问elasticsearch页面

    http://192.168.31.165:9200/

    效果如下:

    1.png

     

    拷贝数据到持久化目录,并重新启动elasticsearch

    docker cp elasticsearch:/usr/share/elasticsearch/data /data/elk7/elasticsearch/
    docker cp elasticsearch:/usr/share/elasticsearch/logs /data/elk7/elasticsearch/
    chmod 777 -R /data/elk7/elasticsearch/
    
    docker rm -f elasticsearch
    docker run -d --name=elasticsearch \
      --restart=always \
      -p 9200:9200 -p 9300:9300 \
      -e "discovery.type=single-node" \
      -v /data/elk7/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \
      -v /data/elk7/elasticsearch/data:/usr/share/elasticsearch/data \
      -v /data/elk7/elasticsearch/logs:/usr/share/elasticsearch/logs \
      elasticsearch:7.10.1

     

    再次刷新页面,效果同上。

     

    三、安装ik中文分词器

    打开github地址:https://github.com/medcl/elasticsearch-analysis-ik

    打开releases页面,下载7.10.1版本

    1.png

     

    注意:这个版本,必须和elasticsearch对应。

     

    下载完成后,将文件elasticsearch-analysis-ik-7.10.1.zip上传到/opt目录

    解压到指定目录

    mkdir /data/elk7/elasticsearch/plugins/elasticsearch-analysis-ik
    unzip /opt/elasticsearch-analysis-ik-7.10.1.zip -d /data/elk7/elasticsearch/plugins/elasticsearch-analysis-ik

    设置文件权限

    chmod 777 -R /data/elk7/elasticsearch/

     

    重新启动elasticsearch

    docker rm -f elasticsearch
    docker run -d --name=elasticsearch \
      --restart=always \
      -p 9200:9200 -p 9300:9300 \
      -e "discovery.type=single-node" \
      -v /data/elk7/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \
      -v /data/elk7/elasticsearch/data:/usr/share/elasticsearch/data \
      -v /data/elk7/elasticsearch/logs:/usr/share/elasticsearch/logs \
      -v /data/elk7/elasticsearch/plugins:/usr/share/elasticsearch/plugins \
      elasticsearch:7.10.1

    注意:这里是新挂载了plugins目录,用来存放插件的。

     

    查看插件接口

    http://192.168.31.165:9200/_cat/plugins

    输出:

    e30bb0e85e63 analysis-ik 7.10.1

    说明插件安装成功了。

     

    四、ik分词器的使用

    简单示例

    请求url:

    http://192.168.31.165:9200/_analyze

     

    首先我们通过Postman发送GET请求查询分词效果

    先指定Headers,Content-Type=application/json

    1.png

     

    再指定请求参数

    {
        "text":"农业银行"
    }

    效果如下:

    1.png

     

    得到如下结果,可以发现es的默认分词器无法识别中文中农业银行这样的词汇,而是简单的将每个字拆完分为一个词,这显然不符合我们的使用要求。

    {
        "tokens": [
            {
                "token": "农",
                "start_offset": 0,
                "end_offset": 1,
                "type": "<IDEOGRAPHIC>",
                "position": 0
            },
            {
                "token": "业",
                "start_offset": 1,
                "end_offset": 2,
                "type": "<IDEOGRAPHIC>",
                "position": 1
            },
            {
                "token": "银",
                "start_offset": 2,
                "end_offset": 3,
                "type": "<IDEOGRAPHIC>",
                "position": 2
            },
            {
                "token": "行",
                "start_offset": 3,
                "end_offset": 4,
                "type": "<IDEOGRAPHIC>",
                "position": 3
            }
        ]
    }

     

    上面已经安装ik中文分词器,接下来使用它。

    我们这次加入新的参数"analyzer":"ik_max_word"

    • k_max_word:会将文本做最细粒度的拆分,例如「中华人民共和国国歌」会被拆分为「中华人民共和国、中华人民、中华、华人、人民共和国、人民、人、民、共和国、共和、和、国国、国歌」,会穷尽各种可能的组合

    • ik_smart:会将文本做最粗粒度的拆分,例如「中华人民共和国国歌」会被拆分为「中华人民共和国、国歌」

     

    修改postman请求参数为:

    {
        "analyzer":"ik_max_word",
        "text":"农业银行"
    }

    得到如下结果

    {
        "tokens": [
            {
                "token": "农业银行",
                "start_offset": 0,
                "end_offset": 4,
                "type": "CN_WORD",
                "position": 0
            },
            {
                "token": "农业",
                "start_offset": 0,
                "end_offset": 2,
                "type": "CN_WORD",
                "position": 1
            },
            {
                "token": "银行",
                "start_offset": 2,
                "end_offset": 4,
                "type": "CN_WORD",
                "position": 2
            }
        ]
    }

     

    百度搜索中每天都会收录新的词汇,es中也可以进行扩展词汇。

    我们首先查询弗雷尔卓德字段

    修改postman请求参数为:

    {
        "analyzer":"ik_max_word",
        "text":"弗雷尔卓德"
    }

     

    仅仅可以得到每个字的分词结果,我们需要做的就是使分词器识别到弗雷尔卓德也是一个词语。

    {
        "tokens": [
            {
                "token": "弗",
                "start_offset": 0,
                "end_offset": 1,
                "type": "CN_CHAR",
                "position": 0
            },
            {
                "token": "雷",
                "start_offset": 1,
                "end_offset": 2,
                "type": "CN_CHAR",
                "position": 1
            },
            {
                "token": "尔",
                "start_offset": 2,
                "end_offset": 3,
                "type": "CN_CHAR",
                "position": 2
            },
            {
                "token": "卓",
                "start_offset": 3,
                "end_offset": 4,
                "type": "CN_CHAR",
                "position": 3
            },
            {
                "token": "德",
                "start_offset": 4,
                "end_offset": 5,
                "type": "CN_CHAR",
                "position": 4
            }
        ]
    }

     

    首先进入es根目录中的plugins文件夹下的ik文件夹,进入config目录,创建custom.dic文件

    cd /data/elk7/elasticsearch/plugins/elasticsearch-analysis-ik/config
    vi custom.dic

    写入以下内容

    弗雷尔卓德
    弗雷尔
    卓
    德

     

    打开IKAnalyzer.cfg.xml文件,将新建的custom.dic配置其中

    <?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">custom.dic</entry>
         <!--用户可以在这里配置自己的扩展停止词字典-->
        <entry key="ext_stopwords"></entry>
        <!--用户可以在这里配置远程扩展字典 -->
        <!-- <entry key="remote_ext_dict">words_location</entry> -->
        <!--用户可以在这里配置远程扩展停止词字典-->
        <!-- <entry key="remote_ext_stopwords">words_location</entry> -->
    </properties>

    注意:仅仅修改<entry key="ext_dict"></entry> 这一行内容即可

     

    重启es

    docker restart elasticsearch

     

    再次查询发现es的分词器可以识别到弗雷尔卓德词汇

    {
        "tokens": [
            {
                "token": "弗雷尔卓德",
                "start_offset": 0,
                "end_offset": 5,
                "type": "CN_WORD",
                "position": 0
            },
            {
                "token": "弗雷尔",
                "start_offset": 0,
                "end_offset": 3,
                "type": "CN_WORD",
                "position": 1
            },
            {
                "token": "卓",
                "start_offset": 3,
                "end_offset": 4,
                "type": "CN_WORD",
                "position": 2
            },
            {
                "token": "德",
                "start_offset": 4,
                "end_offset": 5,
                "type": "CN_WORD",
                "position": 3
            }
        ]
    }


     

    官方示例

    1. 创建索引

    进入linux系统,手动执行。

    curl -XPUT http://localhost:9200/index

     

     2.创建一个映射

    curl -XPOST http://localhost:9200/index/_mapping -H 'Content-Type:application/json' -d'
    {
            "properties": {
                "content": {
                    "type": "text",
                    "analyzer": "ik_max_word",
                    "search_analyzer": "ik_smart"
                }
            }
    
    }'

     

    3. 索引加入一些文档

    curl -XPOST http://localhost:9200/index/_create/1 -H 'Content-Type:application/json' -d'
    {"content":"美国留给伊拉克的是个烂摊子吗"}
    '
    curl -XPOST http://localhost:9200/index/_create/2 -H 'Content-Type:application/json' -d'
    {"content":"公安部:各地校车将享最高路权"}
    '
    curl -XPOST http://localhost:9200/index/_create/3 -H 'Content-Type:application/json' -d'
    {"content":"中韩渔警冲突调查:韩警平均每天扣1艘中国渔船"}
    '
    curl -XPOST http://localhost:9200/index/_create/4 -H 'Content-Type:application/json' -d'
    {"content":"中国驻洛杉矶领事馆遭亚裔男子枪击 嫌犯已自首"}
    '

     

    4. 带高亮显示的查询

    curl -XPOST http://localhost:9200/index/_search  -H 'Content-Type:application/json' -d'
    {
        "query" : { "match" : { "content" : "中国" }},
        "highlight" : {
            "pre_tags" : ["<tag1>", "<tag2>"],
            "post_tags" : ["</tag1>", "</tag2>"],
            "fields" : {
                "content" : {}
            }
        }
    }
    '

    注意:

    highlight表示高亮显示。

    pre_tags,post_tags表示,匹配关键字后,增加标记。

    fields 表示

     

    输出:

    {
        "took": 174,
        "timed_out": false,
        "_shards": {
            "total": 1,
            "successful": 1,
            "skipped": 0,
            "failed": 0
        },
        "hits": {
            "total": {
                "value": 3,
                "relation": "eq"
            },
            "max_score": 1.2257079,
            "hits": [
                {
                    "_index": "index",
                    "_type": "_doc",
                    "_id": "3",
                    "_score": 1.2257079,
                    "_source": {
                        "content": "中韩渔警冲突调查:韩警平均每天扣1艘中国渔船"
                    },
                    "highlight": {
                        "content": [
                            "<tag1>中</tag1>韩渔警冲突调查:韩警平均每天扣1艘<tag1>中</tag1><tag1>国</tag1>渔船"
                        ]
                    }
                },
                {
                    "_index": "index",
                    "_type": "_doc",
                    "_id": "4",
                    "_score": 0.9640833,
                    "_source": {
                        "content": "中国驻洛杉矶领事馆遭亚裔男子枪击 嫌犯已自首"
                    },
                    "highlight": {
                        "content": [
                            "<tag1>中</tag1><tag1>国</tag1>驻洛杉矶领事馆遭亚裔男子枪击 嫌犯已自首"
                        ]
                    }
                },
                {
                    "_index": "index",
                    "_type": "_doc",
                    "_id": "1",
                    "_score": 0.3864615,
                    "_source": {
                        "content": "美国留给伊拉克的是个烂摊子吗"
                    },
                    "highlight": {
                        "content": [
                            "美<tag1>国</tag1>留给伊拉克的是个烂摊子吗"
                        ]
                    }
                }
            ]
        }
    }

     

    字典配置

    上午已经提到了如何自定义字典文件,比如:custom.dic。这里不做重复介绍,请查看上文操作。

     

    热更新 IK 分词使用方法

    目前该插件支持热更新 IK 分词,通过上文在 IK 配置文件中提到的如下配置

    <!--用户可以在这里配置远程扩展字典 -->
    <entry key="remote_ext_dict">location</entry>
    <!--用户可以在这里配置远程扩展停止词字典-->
    <entry key="remote_ext_stopwords">location</entry>

    其中 location 是指一个 url,比如 http://yoursite.com/getCustomDict,该请求只需满足以下两点即可完成分词热更新。

    1. 该 http 请求需要返回两个头部(header),一个是 Last-Modified,一个是 ETag,这两者都是字符串类型,只要有一个发生变化,该插件就会去抓取新的分词进而更新词库。

    2. 该 http 请求返回的内容格式是一行一个分词,换行符用 \n 即可。

    满足上面两点要求就可以实现热更新分词了,不需要重启 ES 实例。

    可以将需自动更新的热词放在一个 UTF-8 编码的 .txt 文件里,放在 nginx 或其他简易 http server 下,当 .txt 文件修改时,http server 会在客户端请求该文件时自动返回相应的 Last-Modified 和 ETag。可以另外做一个工具来从业务系统提取相关词汇,并更新这个 .txt 文件。

     

    注意:远程扩展字典,需要自己写api,根据实际业务情况而定。我目前还未找到公开的远程扩展字典api,支持任何用户访问的那种。

     

    本文参考链接:

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

    https://www.cnblogs.com/haixiang/p/11810799.html


关键字