Elasticsearch中文分词器IK

引言

问什么要使用分词器?
这个问题可能就要牵扯到倒排索引这个概念,那什么是倒排索引呢?

倒排索引(英语:Inverted index),也常被称为反向索引、置入档案或反向档案,是一种索引方法,被用来存储在全文搜索下某个单词在一个文档或者一组文档中的存储位置的映射。它是文档检索系统中最常用的数据结构。
有两种不同的反向索引形式:

  • 一条记录的水平反向索引(或者反向档案索引)包含每个引用单词的文档的列表。
  • 一个单词的水平反向索引(或者完全反向索引)又包含每个单词在一个文档中的位置。

后者的形式提供了更多的兼容性(比如短语搜索),但是需要更多的时间和空间来创建。
以上是维基百科给出的较为官方的解释。

通俗的使用关系型数据库可解释为:将某个字段的部分内容设置为关键词,而这个关键词就是逻辑上的索引(记录所在字段、所在字段位置),通过这个索引可以找到这个字段以及所在字段的具体位置,当然获取到字段完全匹配就可以获取到这条数据。 (此解释存在对倒排索引的扭曲,不可当作官方或准确的定义使用,只为了侧面的解释其含义)

说到这里也许大家已经知道分词器的作用了。为什么要说中文分词器呢?因为 elasticsearch 不是中国创造的,人家默认不支持中文分词(此处中文分词是分为有意义的词语为非单个文字)

正文

安装方式

github确认版本对应关系 elasticsearch-analysis-ik 确认版本之后在 releases 下载或复制路径。

ik分词存在两种安装方式

  • 通过 elasticsearch 的 elasticsearch-plugin 命令安装
    复制所要安装的 ik 分词器的链接,使用以下方式安装即可。此方式安装生成的 ik 分词器的配置文件在 elasticsearch 的 config 目录下
./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.4.3/elasticsearch-analysis-ik-6.4.3.zip

  • 解压包方式
    通过上面所说的地址下载解压在 elasticsearch 的 plgins 目录下即可,此方式 ik 分词器的配置文件就在解压包的下级目录

重启 elasticsearch 验证是否安装完成

curl 192.168.82.92:9200/_cat/plugins
node-1 analysis-ik 6.4.3
读时分词

读时分词:发生在用户查询时,ES 会即时地对用户输入的关键词进行分词,分词结果只存在内存中,当查询结束时,分词结果也会随即消失。
以下将演示读时分词操作,我将在kibana(elastic 旗下的一个组件)操作。

#添加索引
PUT /word-segmenter?pretty=true
#返回值
{
  "acknowledged": true,
  "shards_acknowledged": true,
  "index": "word-segmenter"
}

#查看索引
GET /_cat/indices?v
#返回值
health status index          uuid                   pri rep docs.count docs.deleted store.size pri.store.size
yellow open   word-segmenter 3YonvPYpSKyk4TOX74Ql9A   5   1          0            0      1.1kb          1.1kb

#存储数据
POST /word-segmenter/article
{
  "subject" : "王者荣耀"
}
#返回值
{
  "_index": "word-segmenter",
  "_type": "article",
  "_id": "hyL9GGwBQsOoFTCidV78",
  "_version": 1,
  "result": "created",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  },
  "_seq_no": 0,
  "_primary_term": 1
}

#验证分词器
GET /word-segmenter/_analyze?pretty=true
{
  "analyzer" : "ik_max_word",
  "text" : "王者荣耀"
}
#返回值
{
  "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
    }
  ]
}

#查询测试
POST /word-segmenter/_search?pretty=true
{
  "query" : {
    "match": {
      "subject": {
        "query": "王者荣耀",
        "analyzer": "ik_max_word"
      }
    }
  }
}
#返回值
{
  "took": 3,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 0,
    "max_score": null,
    "hits": []
  }
}

你会发现查询不到结果,明明存入了数据,并且也是也使用了分词,分词的结果“王者”、“荣耀”在数据中也存在,那问题到底出现在哪里?

#查看 word-segmenter 索引的结构
GET /word-segmenter?pretty=true
#返回值
{
  "word-segmenter": {
    "aliases": {},
    "mappings": {
      "article": {
        "properties": {
          "subject": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          }
        }
      }
    },
    "settings": {
      "index": {
        "creation_date": "1563787157307",
        "number_of_shards": "5",
        "number_of_replicas": "1",
        "uuid": "3YonvPYpSKyk4TOX74Ql9A",
        "version": {
          "created": "6040399"
        },
        "provided_name": "word-segmenter"
      }
    }
  }
}

在查询索引结构的返回值中可以发现 subject 并没有看到使用分词器(实际上使用了 elasticsearch 的默认分词器)。问题来了,难道使用不同的分词器就不能查找到结果么?下面我们证实以下,修改查询词。

#
POST /word-segmenter/_search?pretty=true
{
  "query" : {
    "match": {
      "subject": {
        "query": "王",
        "analyzer": "ik_max_word"
      }
    }
  }
}
#返回值
{
  "took": 11,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 1,
    "max_score": 0.2876821,
    "hits": [
      {
        "_index": "word-segmenter",
        "_type": "article",
        "_id": "hyL9GGwBQsOoFTCidV78",
        "_score": 0.2876821,
        "_source": {
          "subject": "王者荣耀"
        }
      }
    ]
  }
}

可以查询到数据,首先可以排除上面的猜想。那么只能是分词的问题了,查看默认分词,分的到底是什么?

#默认分词器
GET /word-segmenter/_analyze?pretty=true
{
  "text" : "王者荣耀"
}
#返回值
{
  "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
    }
  ]
}

通过上面我们可以确认两个分词器分词的结果,相互不存在,所以就造成了我们无法搜索到结果。这里我们就将引入写时分词

写时分词

写时分词:发生在文档写入时,ES 会对文档进行分词后,将结果存入倒排索引,该部分最终会以文件的形式存储于磁盘上,不会因查询结束或者 ES 重启而丢失。

#删除原有索引 word-segmenter
DELETE /word-segmenter?pretty=true
#返回值
{
  "acknowledged": true
}

#新建索引,指定默认分词器为 ik 分词器
PUT /word-segmenter?pretty=true
{
  "settings": {
    "analysis": {
      "analyzer": {
        "ik" : {
          "tokenizer" : "ik_max_word"
        }
      }
    }
  },
  "mappings": {
    "article" : {
      "properties": {
      "subject" : {
        "type": "text",
        "analyzer": "ik_max_word"
        }
      }
    }
  }
}

然后执行读时分词的数据插入及查询会发现可以查到。就算查询时不手动制定使用的分词器也可以查询数据。

自定义分词器

在上面我们测试了将“王者荣耀”分词为“王者”、“荣耀”两个词,但是我就是想将“王者荣耀”也作为一个词如何操作呢?ik 分词器给我们提供了扩展字典的方式。

#进入 ik 分词器的配置文件夹(路径取决于安装方式与安装路径)
cd /home/software/elasticsearch-6.4.3/config/analysis-ik/

#查创建自己的词库
vim /my_extra_word.dic 

#添加数据,每行代表一个词
王者荣耀

#修改 ik 分词器的配置
vim IKAnalyzer.cfg.xml 

#将 <entry key="ext_dict"></entry> 指向新建的词典,多个词典用 “;” 分号隔开
<?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">my_extra_word.dic</entry>
         <!--用户可以在这里配置自己的扩展停止词字典-->
        <entry key="ext_stopwords"></entry>
        <!--用户可以在这里配置远程扩展字典 -->
        <!-- <entry key="remote_ext_dict">words_location</entry> -->
        <!--用户可以在这里配置远程扩展停止词字典-->
        <!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>

#重启 elasticsearch
kill -9 9200
cd /home/software/elasticsearch-6.4.3/
./bin/elasticsearch -d

#测试查看
GET /word-segmenter/_analyze?&pretty=true
{
  "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
    }
  ]
}
引用

倒排索引-维基百科
掌握 analyze API,一举搞定 Elasticsearch 分词难题
ES创建索引映射指定分词策略
elasticsearch5.5.2手动创建索引并配置ik中文分词器
ES中文分词器+自定义分词
centos7安装elasticsearch7并集成IK中文分词器添加系统服务开机启动
Elasticsearch之中文分词器插件es-ik

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,752评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,100评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,244评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,099评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,210评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,307评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,346评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,133评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,546评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,849评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,019评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,702评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,331评论 3 319
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,030评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,260评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,871评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,898评论 2 351