月度归档:2019年02月

Elasticsearch基础介绍及索引原理分析

最近在参与一个基于Elasticsearch作为底层数据框架提供大数据量(亿级)的实时统计查询的方案设计工作,花了些时间学习Elasticsearch的基础理论知识,整理了一下,希望能对Elasticsearch感兴趣/想了解的同学有所帮助。 同时也希望有发现内容不正确或者有疑问的地方,望指明,一起探讨,学习,进步。

介绍

Elasticsearch 是一个分布式可扩展的实时搜索和分析引擎,一个建立在全文搜索引擎 Apache Lucene(TM) 基础上的搜索引擎.当然 Elasticsearch 并不仅仅是 Lucene 那么简单,它不仅包括了全文搜索功能,还可以进行以下工作:

  • 分布式实时文件存储,并将每一个字段都编入索引,使其可以被搜索。
  • 实时分析的分布式搜索引擎。
  • 可以扩展到上百台服务器,处理PB级别的结构化或非结构化数据。

基本概念

先说Elasticsearch的文件存储,Elasticsearch是面向文档型数据库,一条数据在这里就是一个文档,用JSON作为文档序列化的格式,比如下面这条用户数据:

{
    "name" :     "John",
    "sex" :      "Male",
    "age" :      25,
    "birthDate": "1990/05/01",
    "about" :    "I love to go rock climbing",
    "interests": [ "sports", "music" ]
}

用Mysql这样的数据库存储就会容易想到建立一张User表,有balabala的字段等,在Elasticsearch里这就是一个文档,当然这个文档会属于一个User的类型,各种各样的类型存在于一个索引当中。这里有一份简易的将Elasticsearch和关系型数据术语对照表:

关系数据库     ⇒ 数据库 ⇒ 表    ⇒ 行    ⇒ 列(Columns)

Elasticsearch  ⇒ 索引(Index)   ⇒ 类型(type)  ⇒ 文档(Docments)  ⇒ 字段(Fields)  

一个 Elasticsearch 集群可以包含多个索引(数据库),也就是说其中包含了很多类型(表)。这些类型中包含了很多的文档(行),然后每个文档中又包含了很多的字段(列)。Elasticsearch的交互,可以使用Java API,也可以直接使用HTTP的Restful API方式,比如我们打算插入一条记录,可以简单发送一个HTTP的请求:

PUT /megacorp/employee/1  
{
    "name" :     "John",
    "sex" :      "Male",
    "age" :      25,
    "about" :    "I love to go rock climbing",
    "interests": [ "sports", "music" ]
}

更新,查询也是类似这样的操作,具体操作手册可以参见Elasticsearch权威指南


索引

Elasticsearch最关键的就是提供强大的索引能力了,其实InfoQ的这篇时间序列数据库的秘密(2)——索引写的非常好,我这里也是围绕这篇结合自己的理解进一步梳理下,也希望可以帮助大家更好的理解这篇文章。

Elasticsearch索引的精髓:

一切设计都是为了提高搜索的性能

另一层意思:为了提高搜索的性能,难免会牺牲某些其他方面,比如插入/更新,否则其他数据库不用混了。前面看到往Elasticsearch里插入一条记录,其实就是直接PUT一个json的对象,这个对象有多个fields,比如上面例子中的name, sex, age, about, interests,那么在插入这些数据到Elasticsearch的同时,Elasticsearch还默默1的为这些字段建立索引--倒排索引,因为Elasticsearch最核心功能是搜索。

Elasticsearch是如何做到快速索引的

InfoQ那篇文章里说Elasticsearch使用的倒排索引比关系型数据库的B-Tree索引快,为什么呢?

什么是B-Tree索引?

上大学读书时老师教过我们,二叉树查找效率是logN,同时插入新的节点不必移动全部节点,所以用树型结构存储索引,能同时兼顾插入和查询的性能。因此在这个基础上,再结合磁盘的读取特性(顺序读/随机读),传统关系型数据库采用了B-Tree/B+Tree这样的数据结构:

Alt text

为了提高查询的效率,减少磁盘寻道次数,将多个值作为一个数组通过连续区间存放,一次寻道读取多个数据,同时也降低树的高度。

什么是倒排索引?

Alt text

继续上面的例子,假设有这么几条数据(为了简单,去掉about, interests这两个field):

| ID | Name | Age  |  Sex     |
| -- |:------------:| -----:| -----:| 
| 1  | Kate         | 24 | Female
| 2  | John         | 24 | Male
| 3  | Bill         | 29 | Male

ID是Elasticsearch自建的文档id,那么Elasticsearch建立的索引如下:

Name:

| Term | Posting List |
| -- |:----:|
| Kate | 1 |
| John | 2 |
| Bill | 3 |

Age:

| Term | Posting List |
| -- |:----:|
| 24 | [1,2] |
| 29 | 3 |

Sex:

| Term | Posting List |
| -- |:----:|
| Female | 1 |
| Male | [2,3] |
Posting List

Elasticsearch分别为每个field都建立了一个倒排索引,Kate, John, 24, Female这些叫term,而[1,2]就是Posting List。Posting list就是一个int的数组,存储了所有符合某个term的文档id。

看到这里,不要认为就结束了,精彩的部分才刚开始...

通过posting list这种索引方式似乎可以很快进行查找,比如要找age=24的同学,爱回答问题的小明马上就举手回答:我知道,id是1,2的同学。但是,如果这里有上千万的记录呢?如果是想通过name来查找呢?

Term Dictionary

Elasticsearch为了能快速找到某个term,将所有的term排个序,二分法查找term,logN的查找效率,就像通过字典查找一样,这就是Term Dictionary。现在再看起来,似乎和传统数据库通过B-Tree的方式类似啊,为什么说比B-Tree的查询快呢?

Term Index

B-Tree通过减少磁盘寻道次数来提高查询性能,Elasticsearch也是采用同样的思路,直接通过内存查找term,不读磁盘,但是如果term太多,term dictionary也会很大,放内存不现实,于是有了Term Index,就像字典里的索引页一样,A开头的有哪些term,分别在哪页,可以理解term index是一颗树:

Alt text

这棵树不会包含所有的term,它包含的是term的一些前缀。通过term index可以快速地定位到term dictionary的某个offset,然后从这个位置再往后顺序查找。

Alt text

所以term index不需要存下所有的term,而仅仅是他们的一些前缀与Term Dictionary的block之间的映射关系,再结合FST(Finite State Transducers)的压缩技术,可以使term index缓存到内存中。从term index查到对应的term dictionary的block位置之后,再去磁盘上找term,大大减少了磁盘随机读的次数。

这时候爱提问的小明又举手了:"那个FST是神马东东啊?"

一看就知道小明是一个上大学读书的时候跟我一样不认真听课的孩子,数据结构老师一定讲过什么是FST。但没办法,我也忘了,这里再补下课:

FSTs are finite-state machines that map a term (byte sequence) to an arbitrary output.

假设我们现在要将mop, moth, pop, star, stop and top(term index里的term前缀)映射到序号:0,1,2,3,4,5(term dictionary的block位置)。最简单的做法就是定义个Map<string, integer="">,大家找到自己的位置对应入座就好了,但从内存占用少的角度想想,有没有更优的办法呢?答案就是:FST(理论依据在此,但我相信99%的人不会认真看完的)

Alt text

⭕️表示一种状态

-->表示状态的变化过程,上面的字母/数字表示状态变化和权重

将单词分成单个字母通过⭕️和-->表示出来,0权重不显示。如果⭕️后面出现分支,就标记权重,最后整条路径上的权重加起来就是这个单词对应的序号。

FSTs are finite-state machines that map a term (byte sequence) to an arbitrary output.

FST以字节的方式存储所有的term,这种压缩方式可以有效的缩减存储空间,使得term index足以放进内存,但这种方式也会导致查找时需要更多的CPU资源。

后面的更精彩,看累了的同学可以喝杯咖啡……


压缩技巧

Elasticsearch里除了上面说到用FST压缩term index外,对posting list也有压缩技巧。
小明喝完咖啡又举手了:"posting list不是已经只存储文档id了吗?还需要压缩?"

嗯,我们再看回最开始的例子,如果Elasticsearch需要对同学的性别进行索引(这时传统关系型数据库已经哭晕在厕所……),会怎样?如果有上千万个同学,而世界上只有男/女这样两个性别,每个posting list都会有至少百万个文档id。 Elasticsearch是如何有效的对这些文档id压缩的呢?

Frame Of Reference

增量编码压缩,将大数变小数,按字节存储

首先,Elasticsearch要求posting list是有序的(为了提高搜索的性能,再任性的要求也得满足),这样做的一个好处是方便压缩,看下面这个图例: Alt text

如果数学不是体育老师教的话,还是比较容易看出来这种压缩技巧的。

原理就是通过增量,将原来的大数变成小数仅存储增量值,再精打细算按bit排好队,最后通过字节存储,而不是大大咧咧的尽管是2也是用int(4个字节)来存储。

Roaring bitmaps

说到Roaring bitmaps,就必须先从bitmap说起。Bitmap是一种数据结构,假设有某个posting list:

[1,3,4,7,10]

对应的bitmap就是:

[1,0,1,1,0,0,1,0,0,1]

非常直观,用0/1表示某个值是否存在,比如10这个值就对应第10位,对应的bit值是1,这样用一个字节就可以代表8个文档id,旧版本(5.0之前)的Lucene就是用这样的方式来压缩的,但这样的压缩方式仍然不够高效,如果有1亿个文档,那么需要12.5MB的存储空间,这仅仅是对应一个索引字段(我们往往会有很多个索引字段)。于是有人想出了Roaring bitmaps这样更高效的数据结构。

Bitmap的缺点是存储空间随着文档个数线性增长,Roaring bitmaps需要打破这个魔咒就一定要用到某些指数特性:

将posting list按照65535为界限分块,比如第一块所包含的文档id范围在0~65535之间,第二块的id范围是65536~131071,以此类推。再用<商,余数>的组合表示每一组id,这样每组里的id范围都在0~65535内了,剩下的就好办了,既然每组id不会变得无限大,那么我们就可以通过最有效的方式对这里的id存储。

Alt text

细心的小明这时候又举手了:"为什么是以65535为界限?"

程序员的世界里除了1024外,65535也是一个经典值,因为它=2^16-1,正好是用2个字节能表示的最大数,一个short的存储单位,注意到上图里的最后一行“If a block has more than 4096 values, encode as a bit set, and otherwise as a simple array using 2 bytes per value”,如果是大块,用节省点用bitset存,小块就豪爽点,2个字节我也不计较了,用一个short[]存着方便。

那为什么用4096来区分大块还是小块呢?

个人理解:都说程序员的世界是二进制的,4096*2bytes = 8192bytes < 1KB, 磁盘一次寻道可以顺序把一个小块的内容都读出来,再大一位就超过1KB了,需要两次读。


联合索引

上面说了半天都是单field索引,如果多个field索引的联合查询,倒排索引如何满足快速查询的要求呢?

  • 利用跳表(Skip list)的数据结构快速做“与”运算,或者
  • 利用上面提到的bitset按位“与”

先看看跳表的数据结构:

Alt text

将一个有序链表level0,挑出其中几个元素到level1及level2,每个level越往上,选出来的指针元素越少,查找时依次从高level往低查找,比如55,先找到level2的31,再找到level1的47,最后找到55,一共3次查找,查找效率和2叉树的效率相当,但也是用了一定的空间冗余来换取的。

假设有下面三个posting list需要联合索引:

Alt text

如果使用跳表,对最短的posting list中的每个id,逐个在另外两个posting list中查找看是否存在,最后得到交集的结果。

如果使用bitset,就很直观了,直接按位与,得到的结果就是最后的交集。


总结和思考

Elasticsearch的索引思路:

将磁盘里的东西尽量搬进内存,减少磁盘随机读取次数(同时也利用磁盘顺序读特性),结合各种奇技淫巧的压缩算法,用及其苛刻的态度使用内存。

所以,对于使用Elasticsearch进行索引时需要注意:

  • 不需要索引的字段,一定要明确定义出来,因为默认是自动建索引的
  • 同样的道理,对于String类型的字段,不需要analysis的也需要明确定义出来,因为默认也是会analysis的
  • 选择有规律的ID很重要,随机性太大的ID(比如java的UUID)不利于查询

关于最后一点,个人认为有多个因素:

其中一个(也许不是最重要的)因素: 上面看到的压缩算法,都是对Posting list里的大量ID进行压缩的,那如果ID是顺序的,或者是有公共前缀等具有一定规律性的ID,压缩比会比较高;

另外一个因素: 可能是最影响查询性能的,应该是最后通过Posting list里的ID到磁盘中查找Document信息的那步,因为Elasticsearch是分Segment存储的,根据ID这个大范围的Term定位到Segment的效率直接影响了最后查询的性能,如果ID是有规律的,可以快速跳过不包含该ID的Segment,从而减少不必要的磁盘读次数,具体可以参考这篇如何选择一个高效的全局ID方案(评论也很精彩)

转:http://blog.pengqiuyuan.com/ji-chu-jie-shao-ji-suo-yin-yuan-li-fen-xi/

Elasticsearch数据搜索篇

ES即简单又复杂,你可以快速的实现全文检索,又需要了解复杂的REST API。本篇就通过一些简单的搜索命令,帮助你理解ES的相关应用。虽然不能让你理解ES的原理设计,但是可以帮助你理解ES,探寻更多的特性。

其他相关的内容参考:Elasticsearch官方文档翻译

样例数据

为了更好的使用和理解ES,没有点样例数据还是不好模拟的。这里提供了一份官网上的数据,accounts.json。如果需要的话,也可以去这个网址玩玩,它可以帮助你自定义写随机的JSON数据。

首先开启你的ES,然后执行下面的命令,windows下需要自己安装curl、也可以使用cygwin模拟curl命令:

curl -XPOST 'localhost:9200/bank/account/_bulk?pretty' --data-binary  @accounts.json

注意:

1 需要在accounts.json所在的目录运行curl命令。

2 localhost:9200是ES得访问地址和端口

3 bank是索引的名称

4 account是类型的名称

5 索引和类型的名称在文件中如果有定义,可以省略;如果没有则必须要指定

6 _bulk是rest得命令,可以批量执行多个操作(操作是在json文件中定义的,原理可以参考之前的翻译)

7 pretty是将返回的信息以可读的JSON形式返回。

执行完上述的命令后,可以通过下面的命令查询:

curl 'localhost:9200/_cat/indices?v'
health index pri rep docs.count docs.deleted store.size pri.store.size
yellow bank    5   1       1000            0    424.4kb        424.4kb

搜索API

ES提供了两种搜索的方式:请求参数方式 和 请求体方式

请求参数方式

curl 'localhost:9200/bank/_search?q=*&pretty'

其中bank是查询的索引名称,q后面跟着搜索的条件:q=*表示查询所有的内容

请求体方式(推荐这种方式)

curl -XPOST 'localhost:9200/bank/_search?pretty' -d '
{
  "query": { "match_all": {} }
}'

这种方式会把查询的内容放入body中,会造成一定的开销,但是易于理解。在平时的练习中,推荐这种方式。

 

返回的内容

{
  "took" : 26,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "failed" : 0
  },
  "hits" : {
    "total" : 1000,
    "max_score" : 1.0,
    "hits" : [ {
      "_index" : "bank",
      "_type" : "account",
      "_id" : "1",
      "_score" : 1.0, "_source" : {"account_number":1,"balance":39225,"firstname":"Amber","lastname":"Duke","age":32,"gender":"M","address":"880 Holmes Lane","employer":"Pyrami","email":"amberduke@pyrami.com","city":"Brogan","state":"IL"}
    }, {
      "_index" : "bank",
      "_type" : "account",
      "_id" : "6",
      "_score" : 1.0, "_source" : {"account_number":6,"balance":5686,"firstname":"Hattie","lastname":"Bond","age":36,"gender":"M","address":"671 Bristol Street","employer":"Netagy","email":"hattiebond@netagy.com","city":"Dante","state":"TN"}
    }, {
      "_index" : "bank",
      "_type" : "account",
      "_id" : "13",

返回的内容大致可以如下讲解:

took:是查询花费的时间,毫秒单位

time_out:标识查询是否超时

_shards:描述了查询分片的信息,查询了多少个分片、成功的分片数量、失败的分片数量等

hits:搜索的结果,total是全部的满足的文档数目,hits是返回的实际数目(默认是10)

_score是文档的分数信息,与排名相关度有关,参考各大搜索引擎的搜索结果,就容易理解。

由于ES是一次性返回所有的数据,因此理解返回的内容是很必要的。它不像传统的SQL是先返回数据的一个子集,再通过数据库端的游标不断的返回数据(由于对传统的数据库理解的不深,这里有错还望指正)。

查询语言DSL

ES支持一种JSON格式的查询,叫做DSL,domain specific language。这门语言刚开始比较难理解,因此通过几个简单的例子开始:

下面的命令,可以搜索全部的文档:

{
  "query": { "match_all": {} }
}

query定义了查询,match_all声明了查询的类型。还有其他的参数可以控制返回的结果:

curl -XPOST 'localhost:9200/bank/_search?pretty' -d '
{
  "query": { "match_all": {} },
  "size": 1
}'

上面的命令返回了所有文档数据中的第一条文档。如果size不指定,那么默认返回10条。

 

下面的命令请求了第10-20的文档。

curl -XPOST 'localhost:9200/bank/_search?pretty' -d '
{
  "query": { "match_all": {} },
  "from": 10,
  "size": 10
}'

下面的命令指定了文档返回的排序方式:

curl -XPOST 'localhost:9200/bank/_search?pretty' -d '
{
  "query": { "match_all": {} },
  "sort": { "balance": { "order": "desc" } }
}'

执行搜索

上面了解了基本的搜索语句,下面就开始深入一些常用的DSL了。

之前的返回数据都是返回文档的所有内容,这种对于网络的开销肯定是有影响的,下面的例子就指定了返回特定的字段:

curl -XPOST 'localhost:9200/bank/_search?pretty' -d '
{
  "query": { "match_all": {} },
  "_source": ["account_number", "balance"]
}'

再回到query,之前的查询都是查询所有的文档,并不能称之为搜索引擎。下面就通过match方式查询特定字段的特定内容,比如查询余额为20的账户信息:

curl -XPOST 'localhost:9200/bank/_search?pretty' -d '
{
  "query": { "match": { "account_number": 20 } }
}'

查询地址为mill的信息:

curl -XPOST 'localhost:9200/bank/_search?pretty' -d '
{
  "query": { "match": { "address": "mill" } }
}'

查询地址为mill或者lane的信息:

curl -XPOST 'localhost:9200/bank/_search?pretty' -d '
{
  "query": { "match": { "address": "mill lane" } }
}'

如果我们想要返回同时包含mill和lane的,可以通过match_phrase查询:

curl -XPOST 'localhost:9200/bank/_search?pretty' -d '
{
  "query": { "match_phrase": { "address": "mill lane" } }
}'

ES提供了bool查询,可以把很多小的查询组成一个更为复杂的查询,比如查询同时包含mill和lane的文档:

curl -XPOST 'localhost:9200/bank/_search?pretty' -d '
{
  "query": {
    "bool": {
      "must": [
        { "match": { "address": "mill" } },
        { "match": { "address": "lane" } }
      ]
    }
  }
}'

修改bool参数,可以改为查询包含mill或者lane的文档:

curl -XPOST 'localhost:9200/bank/_search?pretty' -d '
{
  "query": {
    "bool": {
      "should": [
        { "match": { "address": "mill" } },
        { "match": { "address": "lane" } }
      ]
    }
  }
}'
也可以改写为must_not,排除包含mill和lane的文档:
curl -XPOST 'localhost:9200/bank/_search?pretty' -d '
{
  "query": {
    "bool": {
      "must_not": [
        { "match": { "address": "mill" } },
        { "match": { "address": "lane" } }
      ]
    }
  }
}'

bool查询可以同时使用must, should, must_not组成一个复杂的查询:

curl -XPOST 'localhost:9200/bank/_search?pretty' -d '
{
  "query": {
    "bool": {
      "must": [
        { "match": { "age": "40" } }
      ],
      "must_not": [
        { "match": { "state": "ID" } }
      ]
    }
  }
}'

过滤查询

之前说过score字段指定了文档的分数,使用查询会计算文档的分数,最后通过分数确定哪些文档更相关,返回哪些文档。

有的时候我们可能对分数不感兴趣,就可以使用filter进行过滤,它不会去计算分值,因此效率也就更高一些。

filter过滤可以嵌套在bool查询内部使用,比如想要查询在2000-3000范围内的所有文档,可以执行下面的命令:

curl -XPOST 'localhost:9200/bank/_search?pretty' -d '
{
  "query": {
    "bool": {
      "must": { "match_all": {} },
      "filter": {
        "range": {
          "balance": {
            "gte": 20000,
            "lte": 30000
          }
        }
      }
    }
  }
}'

ES除了上面介绍过的范围查询range、match_all、match、bool、filter还有很多其他的查询方式,这里就先不一一说明了。

聚合

聚合提供了用户进行分组和数理统计的能力,可以把聚合理解成SQL中的GROUP BY和分组函数。在ES中,你可以在一次搜索查询的时间内,即完成搜索操作也完成聚合操作,这样就降低了多次使用REST API造成的网络开销。

下面就是通过terms聚合的简单样例:

curl -XPOST 'localhost:9200/bank/_search?pretty' -d '
{
  "size": 0,
  "aggs": {
    "group_by_state": {
      "terms": {
        "field": "state"
      }
    }
  }
}'
它类似于SQL中的下面的语句:
SELECT state, COUNT(*) FROM bank GROUP BY state ORDER BY COUNT(*) DESC

返回的数据:

"hits" : {
    "total" : 1000,
    "max_score" : 0.0,
    "hits" : [ ]
  },
  "aggregations" : {
    "group_by_state" : {
      "buckets" : [ {
        "key" : "al",
        "doc_count" : 21
      }, {
        "key" : "tx",
        "doc_count" : 17
      }, {
        "key" : "id",
        "doc_count" : 15
      }, {
        "key" : "ma",
        "doc_count" : 15
      }, {
        "key" : "md",
        "doc_count" : 15
      }, {
        "key" : "pa",
        "doc_count" : 15
      }, {
        "key" : "dc",
        "doc_count" : 14
      }, {
        "key" : "me",
        "doc_count" : 14
      }, {
        "key" : "mo",
        "doc_count" : 14
      }, {
        "key" : "nd",
        "doc_count" : 14
      } ]
    }
  }
}
由于size设置为0,它并没有返回文档的信息,只是返回了聚合的结果。

比如统计不同账户状态下的平均余额:

curl -XPOST 'localhost:9200/bank/_search?pretty' -d '
{
  "size": 0,
  "aggs": {
    "group_by_state": {
      "terms": {
        "field": "state"
      },
      "aggs": {
        "average_balance": {
          "avg": {
            "field": "balance"
          }
        }
      }
    }
  }
}'

聚合支持嵌套,举个例子,先按范围分组,在统计不同性别的账户余额:

curl -XPOST 'localhost:9200/bank/_search?pretty' -d '
{
  "size": 0,
  "aggs": {
    "group_by_age": {
      "range": {
        "field": "age",
        "ranges": [
          {
            "from": 20,
            "to": 30
          },
          {
            "from": 30,
            "to": 40
          },
          {
            "from": 40,
            "to": 50
          }
        ]
      },
      "aggs": {
        "group_by_gender": {
          "terms": {
            "field": "gender"
          },
          "aggs": {
            "average_balance": {
              "avg": {
                "field": "balance"
              }
            }
          }
        }
      }
    }
  }
}'
聚合可以实现很多复杂的功能,而且ES也提供了很多复杂的聚合,这里作为引导篇,也不过多介绍了。

对于基本的数据搜索大致就是上面讲述的样子,熟悉了一些常用的API,入门还是很简单的,倒是要熟练使用ES,还是需要掌握各种搜索查询的命令,以及ES内部的原理。

作者:xingoo
出处:http://www.cnblogs.com/xing901022
本文版权归作者和博客园共有。欢迎转载,但必须保留此段声明,且在文章页面明显位置给出原文连接!
分类: Elasticsearch

ES中的分词器

一、概念介绍

    全文搜索引擎会用某种算法对要建索引的文档进行分析, 从文档中提取出若干Token(词元), 这些算法称为Tokenizer(分词器), 这些Token会被进一步处理, 比如转成小写等, 这些处理算法被称为Token Filter(词元处理器), 被处理后的结果被称为Term(词), 文档中包含了几个这样的Term被称为Frequency(词频)。 引擎会建立Term和原文档的Inverted Index(倒排索引), 这样就能根据Term很快到找到源文档了。 文本被Tokenizer处理前可能要做一些预处理, 比如去掉里面的HTML标记, 这些处理的算法被称为Character Filter(字符过滤器), 这整个的分析算法被称为Analyzer(分析器)

整个分析过程,如下图所示:

二、ES中的分词器

从第一部分内容可以看出:Analyzer(分析器)由Tokenizer(分词器)和Filter(过滤器)组成。

1、ES内置分析器

analyzerlogical namedescription
standard analyzerstandardstandard tokenizer, standard filter, lower case filter, stop filter
simple analyzersimplelower case tokenizer
stop analyzerstoplower case tokenizer, stop filter
keyword analyzerkeyword不分词,内容整体作为一个token(not_analyzed)
pattern analyzerwhitespace正则表达式分词,默认匹配\W+
language analyzerslang各种语言
snowball analyzersnowballstandard tokenizer, standard filter, lower case filter, stop filter, snowball filter
custom analyzercustom一个Tokenizer, 零个或多个Token Filter, 零个或多个Char Filter

 

2、ES内置分词器

tokenizerlogical namedescription
standard tokenizerstandard
edge ngram tokenizeredgeNGram
keyword tokenizerkeyword不分词
letter analyzerletter按单词分
lowercase analyzerlowercaseletter tokenizer, lower case filter
ngram analyzersnGram
whitespace analyzerwhitespace以空格为分隔符拆分
pattern analyzerpattern定义分隔符的正则表达式
uax email url analyzeruax_url_email不拆分url和email
path hierarchy analyzerpath_hierarchy处理类似/path/to/somthing样式的字符串

 

3、ES内置过滤器

(1)ES内置的token filter

token filterlogical namedescription
standard filterstandard
ascii folding filterasciifolding
length filterlength去掉太长或者太短的
lowercase filterlowercase转成小写
ngram filternGram
edge ngram filteredgeNGram
porter stem filterporterStem波特词干算法
shingle filtershingle定义分隔符的正则表达式
stop filterstop移除 stop words
word delimiter filterword_delimiter将一个单词再拆成子分词
stemmer token filterstemmer
stemmer override filterstemmer_override
keyword marker filterkeyword_marker
keyword repeat filterkeyword_repeat
kstem filterkstem
snowball filtersnowball
phonetic filterphonetic插件
synonym filtersynonyms处理同义词
compound word filterdictionary_decompounder, hyphenation_decompounder分解复合词
reverse filterreverse反转字符串
elision filterelision去掉缩略语
truncate filtertruncate截断字符串
unique filterunique
pattern capture filterpattern_capture
pattern replace filtepattern_replace用正则表达式替换
trim filtertrim去掉空格
limit token count filterlimit限制token数量
hunspell filterhunspell拼写检查
common grams filtercommon_grams
normalization filterarabic_normalization, persian_normalization

(2)ES内置的character filter

character filterlogical namedescription
mapping char filtermapping根据配置的映射关系替换字符
html strip char filterhtml_strip去掉HTML元素
pattern replace char filterpattern_replace用正则表达式处理字符串

 

4、自定义分析器

ES允许用户通过配置文件elasticsearch.yml自定义分析器Analyzer,如下:

index:

analysis:

analyzer:

myAnalyzer:

tokenizer: standard

filter: [standard, lowercase, stop]

上面配置信息注册了一个分析器myAnalyzer,在次注册了之后可以在索引或者查询的时候直接使用。该分析器的功能和标准分析器差不多,tokenizer: standard,使用了标准分词器 ;filter: [standard, lowercase, stop],使用了标准过滤器、转小写过滤器和停用词过滤器。

也可以使用第三方分析器,比如IKAnalyzer,详情请参考ElasticSearch安装ik分词插件

基于海量公司分词ES中文分词插件

介绍

本次想和大家分享一款Elasticsearch分词插件,该插件是基于天津海量信息股份有限公司的中文分词核心开发的。海量分词针对大数据检索场景专门做了定制和优化,更贴近搜索需求,整体分词的性能也是非常高效。

本文章有广告成分。但希望将公司研究成果分享出来,给大家实际工作中多一种选择...

海量分词检索优化点

  • 地名方面海量分词5.0可以识别并检索出关于地名后缀的结果

    可以通过搜索“河南”得到“河南省”的结果,搜索“天津”得到“天津市”的搜索结果,而不是简单河南、天津的识别。

  • 著名人物的人名识别更精准,如刘翔、傅莹等

    部分分词器处理中文分词只有两种方式:一种是单字(unigrams)形式,即简单粗暴的将中文的每一个汉字作为一个词(token)分开;另一种是两字(bigrams)的,也就是任意相邻的两个汉字作为一个词分开。这种简单粗暴的切分方式无法实现时效性较新的人名识别,如刘翔、傅莹等会被识别为单字切开。

  • 外国人名识别方面海量可以将人名识别智能识别

    “玛利亚 凯利”、“乔治·史密斯”、“玛丽·戴维斯”将完整的外国人名识别出姓氏和名,如“乔治·史密斯”可以被识别为“乔治”和 “史密斯”。

  • 常见词的品牌名称识别方面,海量分词5.0识别的结果中包含实际意义的品牌名称

    如“乐高”,“吉米作为简单的词,可以被识别,但是词放在文档语境中有其品牌的属性,海量分词识别的结果中可以准确搜索出品牌的结果。

  • 机构名识别方面

    海量分词5.0可以识别完整的机构名称,如“天津海量信息技术股份有限公司”,可以完整的识别出全称。

海量分词性能评测

评测用例

本次评测选取的语料一共三个。一个是2MB的海量测试语料,一个是4MB的北大语料(新版旧版各2MB),一个是9.4GB海量的线上实际数据

评测指标

本次评测是在开源评测程序上修改而来,评测指标有分词速度、行数完美率、字数完美率(该指标仅供参考)、内存消耗

评测结果

2MB海量测试语料

分词器分词模式分词速度(字符/毫秒)行数完美率字数完美率占用内存(MB)
海量/1049.021274.11%65.97%85
ltp/33.74883355.68%45.23%201
IctClass普通分词208.6961248.77%37.10%51
IctClass细粒度分词691.595138.33%27.95%51
JiebaSEARCH分词592.69747.64%36.25%236
FudanNLP/121.753742.99%31.59%99
HanLP标准分词212.7412145.30%34.00%63
HanLPNLP分词378.2367644.09%32.55%71
HanLPN-最短路径分词189.2995944.19%32.22%60
HanLP最短路径分词415.6360543.19%31.28%59
HanLP极速词典分词6735.193436.78%25.10%18
THULAC/0.2085734854.49%43.79%110
StanfordCTB0.1352046444.43%33.25%1101
StanfordPKU0.1250862345.15%34.01%1065

可以看到海量分词的行数完美率是最高的,而且速度十分优异;仅有的一个比海量分词速度快的算法是一个追求极限性能舍弃准确率的算法

4MB北大语料

词器分词模式分词速度(字符/毫秒)行数完美率字数完美率占用内存(MB)
海量/1121.726985.94%48.28%85
ltp/35.8132987.37%49.37%201
IctClass普通分词226.1155478.55%42.04%51
IctClass细粒度分词756.513559.06%30.61%51
JiebaSEARCH分词957.5282647.07%20.01%236
FudanNLP/126.0987958.54%27.78%99
HanLP标准分词369.6665.46%35.04%63
HanLPNLP分词439.7563261.93%31.37%71
HanLPN-最短路径分词223.3048269.20%35.07%60
HanLP最短路径分词440.7224467.74%33.83%59
HanLP极速词典分词7522.58158.09%27.82%18

(注:THULAC和stanford由于速度问题,不纳入评测)

可以看到海量的速度和行数完美率都很优异而且达到了兼顾,行数完美率只落后更高的ltp算法1.4个百分点,速度却是它的三十多倍

9.4GB线上数据

分词器分词模式分词速度(字符/毫秒)
ltp/33.592
海量/960.611
IctClass普通分词198.094
HanLPN-最短路径分词201.735
HanLP最短路径分词425.482
HanLP标准分词473.400
HanLPNLP分词361.842
IctClass细粒度分词689.183
FudanNLP/120.860
HanLP极速词典分词6238.916
JiebaSEARCH分词568.262

(注:THULAC和stanford由于速度问题,不纳入评测)

本表格中分词顺序按(4MB北大语料的)行数完美率进行排序,越靠前的(4MB北大语料的)行数完美率越高

可以看出海量的分词速度十分优秀,分词速度拉开了大多数分词数倍,相比于行数完美率小幅领先的ltp要快几十倍

海量分词插件使用方法

安装使用

  • 下载安装 - 地址: https://github.com/HylandaOpen/elasticsearch-analysis-hlseg/releases
    unzip plugin to folder `your-es-root/plugins/`
  • 使用 elasticsearch-plugin 安装
    ./bin/elasticsearch-plugin install https://github.com/HylandaOpen/elasticsearch-analysis-hlseg/releases/download/v6.4.2/elasticsearch-analysis-hlseg-6.4.2.zip
  • 重启es集群

实例(借用github-ik分词插件的实例)

1.创建index

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

2.配置mapping

curl -XPOST http://localhost:9200/hylanda_seg/data/_mapping -H 'Content-Type:application/json' -d'
{
  "properties": {
    "msg": {
      "type": "text",
      "analyzer": "hlseg_search"
    }
  }
}'

3.插入测试数据

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

4.查询

curl -XPOST http://localhost:9200/hylanda_seg/data/_search  -H 'Content-Type:application/json' -d'
{
  "query": {
    "match": {
      "content": "中国"
    }
  },
  "highlight": {
    "fields": {
      "content": {}
    }
  }
}
'

返回结果

{
  "took" : 11,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 2,
    "max_score" : 0.5754429,
    "hits" : [
      {
        "_index" : "hylanda_seg",
        "_type" : "data",
        "_id" : "4",
        "_score" : 0.5754429,
        "_source" : {
          "content" : "中韩渔警冲突调查:韩警平均每天扣1艘中国渔船"
        },
        "highlight" : {
          "content" : [
            "中韩渔警冲突调查:韩警平均每天扣1艘<em>中国</em>渔船"
          ]
        }
      },
      {
        "_index" : "hylanda_seg",
        "_type" : "data",
        "_id" : "5",
        "_score" : 0.2876821,
        "_source" : {
          "content" : "中国驻洛杉矶领事馆遭亚裔男子枪击 嫌犯已自首"
        },
        "highlight" : {
          "content" : [
            "<em>中国</em>驻洛杉矶领事馆遭亚裔男子枪击 嫌犯已自首"
          ]
        }
      }
    ]
  }
}

字典配置

海量分词分为基础词词典CoreDict.dat和自定义词典userDict_utf8.txt。基础词词典在dictionary目录下,需要将CoreDict.zip解压后放在config目录下,可以通过修改config下的userDict_utf8.txt来更新自定义词典

自定义词典格式如下


1.用户自定义词典采用文本格式,utf-8编码,每行一个词

2.每个词包含三列属性,分别是词串、词的属性以及idf值的加权等级,并以Tab作为分隔,其中除了词串必填外,其他列可以不填,不填写则系统采用默认值

3.“#”表示注释,会在加载时被忽略

4.词的属性以西文逗号分隔,可以是词性、停止词标志或者自定义属性

5.词性标记参考北大标准,用于词性标注时参考,该项不填则默认为名词

6.停止词标志为:stopword,由SegOption.outputStopWord来控制是否输出停止词

7.自定义属性不参与分词过程,分词结果中若Token.userTag不为空,则可以获取到该词的自定义属性。

8.idf值的加权分5级,从低到高的定义是idf-lv1 — idf-lv5,等级越高则该词在关键词计算时的权重会越大,若不填写该值则系统默认是idf-lv3(中等权重)

[尊重社区原创,转载请保留或注明出处]
本文地址:http://elasticsearch.cn/article/6199

Elasticsearch之中文分词器插件es-ik

elasticsearch官方默认的分词插件

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

比如,我现在,拿个具体实例来展现下,验证为什么,es官网提供的分词插件对中文分词而言,效果差

[hadoop@HadoopMaster elasticsearch-2.4.3]$ jps
2044 Jps
1979 Elasticsearch
[hadoop@HadoopMaster elasticsearch-2.4.3]$ pwd
/home/hadoop/app/elasticsearch-2.4.3
[hadoop@HadoopMaster elasticsearch-2.4.3]$ curl 'http://192.168.80.10:9200/zhouls/_analyze?pretty=true' -d '{"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
}, {
"token" : "记",

 

"start_offset" : 4,
"end_offset" : 5,
"type" : "<IDEOGRAPHIC>",
"position" : 4
}, {
"token" : "性",
"start_offset" : 5,
"end_offset" : 6,
"type" : "<IDEOGRAPHIC>",
"position" : 5
}, {
"token" : "不",
"start_offset" : 6,
"end_offset" : 7,
"type" : "<IDEOGRAPHIC>",
"position" : 6
}, {
"token" : "如",
"start_offset" : 7,
"end_offset" : 8,
"type" : "<IDEOGRAPHIC>",
"position" : 7
}, {
"token" : "烂",
"start_offset" : 8,
"end_offset" : 9,
"type" : "<IDEOGRAPHIC>",
"position" : 8
}, {
"token" : "笔",

"start_offset" : 9,
"end_offset" : 10,
"type" : "<IDEOGRAPHIC>",
"position" : 9
}, {
"token" : "头",
"start_offset" : 10,
"end_offset" : 11,
"type" : "<IDEOGRAPHIC>",
"position" : 10
}, {
"token" : "感",
"start_offset" : 11,
"end_offset" : 12,
"type" : "<IDEOGRAPHIC>",
"position" : 11
}, {
"token" : "叹",
"start_offset" : 12,
"end_offset" : 13,
"type" : "<IDEOGRAPHIC>",
"position" : 12
}, {
"token" : "号",
"start_offset" : 13,
"end_offset" : 14,
"type" : "<IDEOGRAPHIC>",
"position" : 13
}, {
"token" : "的",

"start_offset" : 14,
"end_offset" : 15,
"type" : "<IDEOGRAPHIC>",
"position" : 14
}, {
"token" : "博",
"start_offset" : 15,
"end_offset" : 16,
"type" : "<IDEOGRAPHIC>",
"position" : 15
}, {
"token" : "客",
"start_offset" : 16,
"end_offset" : 17,
"type" : "<IDEOGRAPHIC>",
"position" : 16
}, {
"token" : "园",
"start_offset" : 17,
"end_offset" : 18,
"type" : "<IDEOGRAPHIC>",
"position" : 17
} ]
}
[hadoop@HadoopMaster elasticsearch-2.4.3]$

 

 

 

总结

如果直接使用Elasticsearch的朋友在处理中文内容的搜索时,肯定会遇到很尴尬的问题——中文词语被分成了一个一个的汉字,当用Kibana作图的时候,按照term来分组,结果一个汉字被分成了一组。

这是因为使用了Elasticsearch中默认的标准分词器,这个分词器在处理中文的时候会把中文单词切分成一个一个的汉字,因此引入es之中文的分词器插件es-ik就能解决这个问题

 

 

 

 

 

 

 

 

 

如何集成IK分词工具

 总的流程如下:

第一步:下载es的IK插件https://github.com/medcl/elasticsearch-analysis-ik/tree/2.x

第二步:使用maven对下载的es-ik源码进行编译(mvn clean package -DskipTests)

第三步:把编译后的target/releases下的elasticsearch-analysis-ik-1.10.3.zip文件拷贝到ES_HOME/plugins/ik目录下面,然后使用unzip命令解压

如果unzip命令不存在,则安装:yum install -y unzip

第四步:重启es服务

第五步:测试分词效果: curl 'http://your ip:9200/zhouls/_analyze?analyzer=ik_max_word&pretty=true' -d '{"text":"这里是好记性不如烂笔头感叹号的博客们"}'

   注意:若你是单节点的es集群的话,则只需在一台部署es-ik。若比如像我这里的话,是3台,则需在三台都部署es-ik,且配置要一样。

 

 

 

 

elasticsearch-analysis-ik-1.10.0.zip  对应于  elasticsearch-2.4.0

elasticsearch-analysis-ik-1.10.3.zip  对应于  elasticsearch-2.4.3

 

 

 

我这里,已经给大家准备好了,以下是我的CSDN账号。下载好了,大家可以去下载。

 

http://download.csdn.net/detail/u010106732/9890897

http://download.csdn.net/detail/u010106732/9890918

 

 

 

 

 

 

 

https://github.com/medcl/elasticsearch-analysis-ik/tree/v1.10.0

 

 

 

 

 

 

 

 

 

 

 

第一步: 在浏览器里,输入https://github.com/

 

 

 

 

第二步https://github.com/search?utf8=%E2%9C%93&q=elasticsearch-ik

 

 

 

第三步https://github.com/medcl/elasticsearch-analysis-ik  ,点击2.x 。当然也有一些人在用2.4.0版本,都适用。若你是使用5.X,则自己对号入座即可,这个很简单。

 

 

 

 

第四步https://github.com/medcl/elasticsearch-analysis-ik/tree/2.x 得到

 

 

 

第五步:找到之后,点击,下载,这里选择离线安装

 

 

 

第六步:将Elasticsearch之中文分词器插件es-ik的压缩包解压下,初步认识下其目录结构,比如我这里放到D盘下来认识下。并为后续的maven编译做基础。

 

 

 

第七步:用本地安装好的maven来编译

Microsoft Windows [版本 6.1.7601]
版权所有 (c) 2009 Microsoft Corporation。保留所有权利。

C:\Users\Administrator>cd D:\elasticsearch-analysis-ik-2.x

C:\Users\Administrator>d:

D:\elasticsearch-analysis-ik-2.x>mvn

 

 

得到,

 

 

 

D:\elasticsearch-analysis-ik-2.x>mvn clean package -DskipTests
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building elasticsearch-analysis-ik 1.10.4
[INFO] ------------------------------------------------------------------------
Downloading: http://maven.aliyun.com/nexus/content/repositories/central/org/apac
he/maven/plugins/maven-enforcer-plugin/1.0/maven-enforcer-plugin-1.0.pom
Downloaded: http://maven.aliyun.com/nexus/content/repositories/central/org/apach
e/maven/plugins/maven-enforcer-plugin/1.0/maven-enforcer-plugin-1.0.pom (7 KB at
2.5 KB/sec)
Downloading: http://maven.aliyun.com/nexus/content/repositories/central/org/apac
he/maven/enforcer/enforcer/1.0/enforcer-1.0.pom
Downloaded: http://maven.aliyun.com/nexus/content/repositories/central/org/apach
e/maven/enforcer/enforcer/1.0/enforcer-1.0.pom (12 KB at 19.5 KB/sec)
Downloading: http://maven.aliyun.com/nexus/content/repositories/central/org/apac
he/maven/maven-parent/17/maven-parent-17.pom
Downloaded: http://maven.aliyun.com/nexus/content/repositories/central/org/apach
e/maven/maven-parent/17/maven-parent-17.pom (25 KB at 41.9 KB/sec)
Downloading: http://maven.aliyun.com/nexus/content/repositories/central/org/apac
he/maven/plugins/maven-enforcer-plugin/1.0/maven-enforcer-plugin-1.0.jar
Downloaded: http://maven.aliyun.com/nexus/content/repositories/central/org/apach
e/maven/plugins/maven-enforcer-plugin/1.0/maven-enforcer-plugin-1.0.jar (22 KB a
t 44.2 KB/sec)
Downloading: http://maven.aliyun.com/nexus/content/repositories/central/org/apac
he/maven/plugins/maven-compiler-plugin/3.5.1/maven-compiler-plugin-3.5.1.pom
Downloaded: http://maven.aliyun.com/nexus/content/repositories/central/org/apach
e/maven/plugins/maven-compiler-plugin/3.5.1/maven-compiler-plugin-3.5.1.pom (10
KB at 35.3 KB/sec)
Downloading: http://maven.aliyun.com/nexus/content/repositories/central/org/apac
he/maven/plugins/maven-plugins/28/maven-plugins-28.pom
Downloaded: http://maven.aliyun.com/nexus/content/repositories/central/org/apach
e/maven/plugins/maven-plugins/28/maven-plugins-28.pom (12 KB at 42.1 KB/sec)
Downloading: http://maven.aliyun.com/nexus/content/repositories/central/org/apac
he/maven/maven-parent/27/maven-parent-27.pom
Downloaded: http://maven.aliyun.com/nexus/content/repositories/central/org/apach
e/maven/maven-parent/27/maven-parent-27.pom (40 KB at 94.0 KB/sec)
Downloading: http://maven.aliyun.com/nexus/content/repositories/central/org/apac
he/apache/17/apache-17.pom
Downloaded: http://maven.aliyun.com/nexus/content/repositories/central/org/apach

 

 

 

需要等待一会儿,这个根据自己的网速快慢。

Downloaded: http://maven.aliyun.com/nexus/content/repositories/central/org/apach
e/maven/maven-archiver/2.4/maven-archiver-2.4.jar (20 KB at 19.8 KB/sec)
Downloading: http://maven.aliyun.com/nexus/content/repositories/central/org/apac
he/maven/shared/maven-repository-builder/1.0-alpha-2/maven-repository-builder-1.
0-alpha-2.jar
Downloaded: http://maven.aliyun.com/nexus/content/repositories/central/org/apach
e/maven/maven-project/2.0.4/maven-project-2.0.4.jar (107 KB at 84.7 KB/sec)
Downloaded: http://maven.aliyun.com/nexus/content/repositories/central/org/codeh
aus/plexus/plexus-utils/2.0.1/plexus-utils-2.0.1.jar (217 KB at 158.7 KB/sec)
Downloaded: http://maven.aliyun.com/nexus/content/repositories/central/org/apach
e/maven/shared/maven-repository-builder/1.0-alpha-2/maven-repository-builder-1.0
-alpha-2.jar (23 KB at 16.4 KB/sec)
Downloaded: http://maven.aliyun.com/nexus/content/repositories/central/org/apach
e/maven/maven-model/2.0.4/maven-model-2.0.4.jar (79 KB at 54.3 KB/sec)
Downloaded: http://maven.aliyun.com/nexus/content/repositories/central/org/apach
e/maven/maven-artifact/2.0.4/maven-artifact-2.0.4.jar (79 KB at 52.9 KB/sec)
[INFO] Reading assembly descriptor: D:\elasticsearch-analysis-ik-2.x/src/main/as
semblies/plugin.xml
[INFO] Building zip: D:\elasticsearch-analysis-ik-2.x\target\releases\elasticsea
rch-analysis-ik-1.10.4.zip
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 01:22 min
[INFO] Finished at: 2017-02-25T14:48:40+08:00
[INFO] Final Memory: 35M/609M
[INFO] ------------------------------------------------------------------------

D:\elasticsearch-analysis-ik-2.x>

 

 

 

成功,得到。

 

这里,需要本地(即windows系统)里,提前安装好maven,需要来编译。若没安装的博友,请移步,见

Eclipse下Maven新建项目、自动打依赖jar包(包含普通项目和Web项目)

 

 

 

最后得到是,

 

 

第八步将最后编译好的,分别上传到3台机器里。$ES_HOME/plugins/ik 目录下,注意需要新建ik目录。

[hadoop@HadoopSlave1 elasticsearch-2.4.3]$ pwd
/home/hadoop/app/elasticsearch-2.4.3
[hadoop@HadoopSlave1 elasticsearch-2.4.3]$ ll
total 56
drwxrwxr-x. 2 hadoop hadoop 4096 Feb 22 01:37 bin
drwxrwxr-x. 3 hadoop hadoop 4096 Feb 22 22:43 config
drwxrwxr-x. 3 hadoop hadoop 4096 Feb 22 07:07 data
drwxrwxr-x. 2 hadoop hadoop 4096 Feb 22 01:37 lib
-rw-rw-r--. 1 hadoop hadoop 11358 Aug 24 2016 LICENSE.txt
drwxrwxr-x. 2 hadoop hadoop 4096 Feb 25 05:15 logs
drwxrwxr-x. 5 hadoop hadoop 4096 Dec 8 00:41 modules
-rw-rw-r--. 1 hadoop hadoop 150 Aug 24 2016 NOTICE.txt
drwxrwxr-x. 4 hadoop hadoop 4096 Feb 22 06:02 plugins
-rw-rw-r--. 1 hadoop hadoop 8700 Aug 24 2016 README.textile
[hadoop@HadoopSlave1 elasticsearch-2.4.3]$ cd plugins/
[hadoop@HadoopSlave1 plugins]$ ll
total 8
drwxrwxr-x. 5 hadoop hadoop 4096 Feb 22 06:02 head
drwxrwxr-x. 8 hadoop hadoop 4096 Feb 22 06:02 kopf
[hadoop@HadoopSlave1 plugins]$ mkdir ik
[hadoop@HadoopSlave1 plugins]$ pwd
/home/hadoop/app/elasticsearch-2.4.3/plugins
[hadoop@HadoopSlave1 plugins]$ ll
total 12
drwxrwxr-x. 5 hadoop hadoop 4096 Feb 22 06:02 head
drwxrwxr-x. 2 hadoop hadoop 4096 Feb 25 06:18 ik
drwxrwxr-x. 8 hadoop hadoop 4096 Feb 22 06:02 kopf

[hadoop@HadoopSlave1 plugins]$ cd ik/
[hadoop@HadoopSlave1 ik]$ pwd
/home/hadoop/app/elasticsearch-2.4.3/plugins/ik
[hadoop@HadoopSlave1 ik]$ rz

[hadoop@HadoopSlave1 ik]$ ll
total 4400
-rw-r--r--. 1 hadoop hadoop 4505518 Jan 15 08:59 elasticsearch-analysis-ik-1.10.3.zip
[hadoop@HadoopSlave1 ik]$

 

 

 

第九步:关闭es服务进程

[hadoop@HadoopSlave1 ik]$ jps
1874 Elasticsearch
2078 Jps
[hadoop@HadoopSlave1 ik]$ kill -9 1874
[hadoop@HadoopSlave1 ik]$ jps
2089 Jps
[hadoop@HadoopSlave1 ik]$

 

 

第十步:使用unzip命令解压,如果unzip命令不存在,则安装:yum install -y unzip。

[hadoop@HadoopSlave1 ik]$ unzip elasticsearch-analysis-ik-1.10.3.zip
Archive: elasticsearch-analysis-ik-1.10.3.zip
inflating: elasticsearch-analysis-ik-1.10.3.jar
inflating: httpclient-4.5.2.jar
inflating: httpcore-4.4.4.jar
inflating: commons-logging-1.2.jar
inflating: commons-codec-1.9.jar
inflating: plugin-descriptor.properties
creating: config/
creating: config/custom/
inflating: config/custom/ext_stopword.dic
inflating: config/custom/mydict.dic
inflating: config/custom/single_word.dic
inflating: config/custom/single_word_full.dic
inflating: config/custom/single_word_low_freq.dic
inflating: config/custom/sougou.dic
inflating: config/IKAnalyzer.cfg.xml
inflating: config/main.dic
inflating: config/preposition.dic
inflating: config/quantifier.dic
inflating: config/stopword.dic
inflating: config/suffix.dic
inflating: config/surname.dic
[hadoop@HadoopSlave1 ik]$ ll
total 5828
-rw-r--r--. 1 hadoop hadoop 263965 Dec 1 2015 commons-codec-1.9.jar
-rw-r--r--. 1 hadoop hadoop 61829 Dec 1 2015 commons-logging-1.2.jar
drwxr-xr-x. 3 hadoop hadoop 4096 Jan 1 12:46 config
-rw-r--r--. 1 hadoop hadoop 55998 Jan 1 13:27 elasticsearch-analysis-ik-1.10.3.jar
-rw-r--r--. 1 hadoop hadoop 4505518 Jan 15 08:59 elasticsearch-analysis-ik-1.10.3.zip
-rw-r--r--. 1 hadoop hadoop 736658 Jan 1 13:26 httpclient-4.5.2.jar
-rw-r--r--. 1 hadoop hadoop 326724 Jan 1 13:07 httpcore-4.4.4.jar
-rw-r--r--. 1 hadoop hadoop 2667 Jan 1 13:27 plugin-descriptor.properties

[hadoop@HadoopSlave1 ik]$

同理,其他两台也是。

 

 

 

第十一步:重启三台机器的es服务进程

 

 

 

其实,若想更具体地,看得,es安装中文分词器es-ik之后,的变化情况,直接,在$ES_HOME下,执行bin/elasticsearch。当然,我这里只是给你展示下而已,还是用bin/elasticsearch -d在后台启动吧!

 

 

 

 

 

 

 

第十二步:测试,安装了es中文分词插件es-ik之后的对中文分词效果

  ik_max_word方式来分词测试

[hadoop@HadoopMaster elasticsearch-2.4.3]$ pwd
/home/hadoop/app/elasticsearch-2.4.3
[hadoop@HadoopMaster elasticsearch-2.4.3]$ curl 'http://192.168.80.10:9200/zhouls/_analyze?analyzer=ik_max_word&pretty=true' -d '{"text":"这里是好记性不如烂笔头感叹号的博客园"}'
{
"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" : 1,
"end_offset" : 2,
"type" : "CN_WORD",
"position" : 2
}, {
"token" : "好记",
"start_offset" : 3,
"end_offset" : 5,
"type" : "CN_WORD",
"position" : 3
}, {
"token" : "记性",
"start_offset" : 4,
"end_offset" : 6,
"type" : "CN_WORD",

"position" : 4
}, {
"token" : "不如",
"start_offset" : 6,
"end_offset" : 8,
"type" : "CN_WORD",
"position" : 5
}, {
"token" : "烂",
"start_offset" : 8,
"end_offset" : 9,
"type" : "CN_CHAR",
"position" : 6
}, {
"token" : "笔头",
"start_offset" : 9,
"end_offset" : 11,
"type" : "CN_WORD",
"position" : 7
}, {
"token" : "笔",
"start_offset" : 9,
"end_offset" : 10,
"type" : "CN_WORD",
"position" : 8
}, {
"token" : "头",
"start_offset" : 10,
"end_offset" : 11,
"type" : "CN_CHAR",

"position" : 9
}, {
"token" : "感叹号",
"start_offset" : 11,
"end_offset" : 14,
"type" : "CN_WORD",
"position" : 10
}, {
"token" : "感叹",
"start_offset" : 11,
"end_offset" : 13,
"type" : "CN_WORD",
"position" : 11
}, {
"token" : "叹号",
"start_offset" : 12,
"end_offset" : 14,
"type" : "CN_WORD",
"position" : 12
}, {
"token" : "叹",
"start_offset" : 12,
"end_offset" : 13,
"type" : "CN_WORD",
"position" : 13
}, {
"token" : "号",
"start_offset" : 13,
"end_offset" : 14,
"type" : "CN_CHAR",

"position" : 14
}, {
"token" : "博客园",
"start_offset" : 15,
"end_offset" : 18,
"type" : "CN_WORD",
"position" : 15
}, {
"token" : "博客",
"start_offset" : 15,
"end_offset" : 17,
"type" : "CN_WORD",
"position" : 16
}, {
"token" : "园",
"start_offset" : 17,
"end_offset" : 18,
"type" : "CN_CHAR",
"position" : 17
} ]
}
[hadoop@HadoopMaster elasticsearch-2.4.3]$

 

 

 

 

[hadoop@HadoopMaster elasticsearch-2.4.3]$ curl 'http://192.168.80.10:9200/zhouls/_analyze?analyzer=ik_max_word&pretty=true' -d '{"text":"我们是大数据开发技术人员"}'
{
"tokens" : [ {
"token" : "我们",
"start_offset" : 0,
"end_offset" : 2,
"type" : "CN_WORD",
"position" : 0
}, {
"token" : "大数",
"start_offset" : 3,
"end_offset" : 5,
"type" : "CN_WORD",
"position" : 1
}, {
"token" : "数据",
"start_offset" : 4,
"end_offset" : 6,
"type" : "CN_WORD",
"position" : 2
}, {
"token" : "开发",
"start_offset" : 6,
"end_offset" : 8,
"type" : "CN_WORD",
"position" : 3
}, {
"token" : "发",
"start_offset" : 7,
"end_offset" : 8,
"type" : "CN_WORD",
"position" : 4
}, {

"token" : "技术人员",
"start_offset" : 8,
"end_offset" : 12,
"type" : "CN_WORD",
"position" : 5
}, {
"token" : "技术",
"start_offset" : 8,
"end_offset" : 10,
"type" : "CN_WORD",
"position" : 6
}, {
"token" : "人员",
"start_offset" : 10,
"end_offset" : 12,
"type" : "CN_WORD",
"position" : 7
} ]
}
[hadoop@HadoopMaster elasticsearch-2.4.3]$

 

可以看出,成功分词了且效果更好!

 

 

 

其实,啊,为什么“是”没有了呢?是因为es的中文分词器插件es-ik的过滤停止词的贡献!请移步,如下

Elasticsearch之IKAnalyzer的过滤停止词

 

 

 

 

 

es官方文档提供的ik_max_word和ik_smart解释

https://github.com/medcl/elasticsearch-analysis-ik/tree/2.x

 

 

 

 

 

ik_smart方式来分词测试

[hadoop@HadoopMaster elasticsearch-2.4.3]$ curl 'http://192.168.80.10:9200/zhouls/_analyze?analyzer=ik_smart&pretty=true' -d '{"text":"这里是好记性不如烂笔头感叹号的博客园"}'
{
"tokens" : [ {
"token" : "这里是",
"start_offset" : 0,
"end_offset" : 3,
"type" : "CN_WORD",
"position" : 0
}, {
"token" : "好",
"start_offset" : 3,
"end_offset" : 4,
"type" : "CN_CHAR",
"position" : 1
}, {
"token" : "记性",
"start_offset" : 4,
"end_offset" : 6,
"type" : "CN_WORD",
"position" : 2
}, {
"token" : "不如",
"start_offset" : 6,
"end_offset" : 8,
"type" : "CN_WORD",
"position" : 3
}, {
"token" : "烂",
"start_offset" : 8,
"end_offset" : 9,
"type" : "CN_CHAR",
"position" : 4
}, {

 

"token" : "笔头",
"start_offset" : 9,
"end_offset" : 11,
"type" : "CN_WORD",
"position" : 5
}, {
"token" : "感叹号",
"start_offset" : 11,
"end_offset" : 14,
"type" : "CN_WORD",
"position" : 6
}, {
"token" : "博客园",
"start_offset" : 15,
"end_offset" : 18,
"type" : "CN_WORD",
"position" : 7
} ]
}
[hadoop@HadoopMaster elasticsearch-2.4.3]$

 

 

 

 

 

 

 

[hadoop@HadoopMaster elasticsearch-2.4.3]$ curl 'http://192.168.80.10:9200/zhouls/_analyze?analyzer=ik_smart&pretty=true' -d '{"text":"我们是大数据开发技术人员"}'
{
"tokens" : [ {
"token" : "我们",
"start_offset" : 0,
"end_offset" : 2,
"type" : "CN_WORD",
"position" : 0
}, {
"token" : "大",
"start_offset" : 3,
"end_offset" : 4,
"type" : "CN_CHAR",
"position" : 1
}, {
"token" : "数据",
"start_offset" : 4,
"end_offset" : 6,
"type" : "CN_WORD",
"position" : 2
}, {
"token" : "开发",
"start_offset" : 6,
"end_offset" : 8,
"type" : "CN_WORD",
"position" : 3
}, {
"token" : "技术人员",
"start_offset" : 8,
"end_offset" : 12,
"type" : "CN_WORD",
"position" : 4
} ]

}

来源: http://www.cnblogs.com/zlslch/p/6440373.html