elasticsearch中文分词


由于elasticsearch基于lucene,所以天然地就多了许多lucene上的中文分词的支持,比如 IK, Paoding, MMSEG4J等lucene中文分词原理上都能在elasticsearch上使用。当然前提是有elasticsearch的插件。 至于插件怎么开发,这里有一片文章介绍:
http://log.medcl.net/item/2011/07/diving-into-elasticsearch-3-custom-analysis-plugin/
暂时还没时间看,留在以后仔细研究, 这里只记录本人使用medcl提供的IK分词插件的集成步骤。

一、插件准备
网上有介绍说可以直接用plugin -install medcl/elasticsearch-analysis-ik的办法,但是我执行下来的效果只是将插件的源码下载下来,elasticsearch只是将其作为一个_site插件看待。
所以只有执行maven并将打包后的jar文件拷贝到上级目录。(否则在定义mapping的analyzer的时候会提示找不到类的错误)。
由于IK是基于字典的分词,所以还要下载IK的字典文件,在medcl的elasticsearch-RTF中有,可以通过这个地址下载:
http://github.com/downloads/medcl/elasticsearch-analysis-ik/ik.zip
下载之后解压缩到config目录下。到这里,你可能需要重新启动下elasticsearch,好让下一部定义的分词器能立即生效。

二、分词定义
分词插件准备好之后就可以在elasticsearch里定义(声明)这个分词类型了(自带的几个类型,比如standred则不需要特别定义)。跟其他设置一样,分词的定义也可以在系统级(elasticsearch全局范围),也可以在索引级(只在当前index内部可见)。系统级的定义当然是指在conf目录下的
elasticsearch.yml文件里定义,内容大致如下:
index:  
  analysis:                     
    analyzer:        
      ikAnalyzer:  
          alias: [ik]  
          type: org.elasticsearch.index.analysis.IkAnalyzerProvider 
或者 index.analysis.analyzer.ik.type : "ik"

因为个人喜好,我并没有这么做, 而是定义在了需要使用中文分词的index中,这样定义更灵活,也不会影响其他index。
在定义analyze之前,先关闭index。其实并不需要关闭也可以生效,但是为了数据一致性考虑,还是先执行关闭。(如果是线上的系统需要三思)

curl -XPOST http://localhost:9400/application/_close
(很显然,这里的application是我的一个index)

然后执行:
curl -XPUT localhost:9400/application/_settings -d '
{
   "analysis": {
      "analyzer":{
             "ikAnalyzer":{
                 "type":"org.elasticsearch.index.analysis.IkAnalyzerProvider",
                    "alias":"ik"
                }
            }
     }
}
'
打开index:

curl -XPOST http://localhost:9400/application/_open

到此为止一个新的类型的分词器就定义好了,接下来就是要如何使用了

或者按如下配置
curl -XPUT localhost:9200/indexname -d '{
    "settings" : {
        "analysis" : {
            "analyzer" : {
                "ik" : {
                    "tokenizer" : "ik"
                }
            }
        }
    },
    "mappings" : {
        "article" : {
            "dynamic" : true,
            "properties" : {
                "title" : {
                    "type" : "string",
                    "analyzer" : "ik"
                }
            }
        }
    }
}'
如果我们想返回最细粒度的分词结果,需要在elasticsearch.yml中配置如下:

index:
  analysis:
    analyzer:
      ik:
          alias: [ik_analyzer]
          type: org.elasticsearch.index.analysis.IkAnalyzerProvider
      ik_smart:
          type: ik
          use_smart: true
      ik_max_word:
          type: ik
          use_smart: false

三、使用分词器
在将分词器使用到实际数据之前,可以先测验下分词效果:
http://localhost:9400/application/_analyze?analyzer=ik&text=中文分词
分词结果是:
{
  "tokens" : [ {
    "token" : "中文",
    "start_offset" : 0,
    "end_offset" : 2,
    "type" : "CN_WORD",
    "position" : 1
  }, {
    "token" : "分词",
    "start_offset" : 2,
    "end_offset" : 4,
    "type" : "CN_WORD",
    "position" : 2
  } ]
}
与使用standard分词器的效果更合理了:
{
  "tokens" : [ {
    "token" : "中",
    "start_offset" : 0,
    "end_offset" : 1,
    "type" : "<IDEOGRAPHIC>",
    "position" : 1
  }, {
    "token" : "文",
    "start_offset" : 1,
    "end_offset" : 2,
    "type" : "<IDEOGRAPHIC>",
    "position" : 2
  }, {
    "token" : "分",
    "start_offset" : 2,
    "end_offset" : 3,
    "type" : "<IDEOGRAPHIC>",
    "position" : 3
  }, {
    "token" : "词",
    "start_offset" : 3,
    "end_offset" : 4,
    "type" : "<IDEOGRAPHIC>",
    "position" : 4
  } ]
}
新的分词器定义完成,工作正常后就可以在mapping的定义中引用了,比如我定义这样的type:
curl localhost:9400/application/article/_mapping -d '
{
    "article": {
        "properties": {            
            "description": {
                "type": "string",
                "indexAnalyzer":"ikAnalyzer",
                "searchAnalyzer":"ikAnalyzer"
            },
            "title": {
                "type": "string",
                "indexAnalyzer":"ik",
                "searchAnalyzer":"ik"
            }
        }
    }
}
'
很遗憾,对于已经存在的index来说,要将一个string类型的field从standard的分词器改成别的分词器通常都是失败的:
{
    "error": "MergeMappingException[Merge failed with failures {[mapper [description] has different index_analyzer, mapper [description] has
different search_analyzer]}]",
    "status": 400
}
而且没有办法解决冲突,唯一的办法是新建一个索引,并制定mapping使用新的分词器(注意要在数据插入之前,否则会使用elasticsearch默认的分词器)
curl -XPUT localhost:9400/application/article/_mapping -d '
{
  "article" : {
    "properties" : {
 "description": {
                "type": "string",
                "indexAnalyzer":"ikAnalyzer",
                "searchAnalyzer":"ikAnalyzer"
            },
            "title": {
                "type": "string",
                "indexAnalyzer":"ik",
                "searchAnalyzer":"ik"
            }
    }
  }
}
至此,一个带中文分词的elasticsearch就算搭建完成。 想偷懒的可以下载medcl的elasticsearch-RTF直接使用,里面需要的插件和配置基本都已经设置好。
------------
标准分词(standard)配置如下:

curl -XPUT localhost:9200/local -d '{
    "settings" : {
        "analysis" : {
            "analyzer" : {
                "stem" : {
                    "tokenizer" : "standard",
                    "filter" : ["standard", "lowercase", "stop", "porter_stem"]
                }
            }
        }
    },
    "mappings" : {
        "article" : {
            "dynamic" : true,
            "properties" : {
                "title" : {
                    "type" : "string",
                    "analyzer" : "stem"
                }
            }
        }
    }
}'

index:local
type:article
default analyzer:stem (filter:小写、停用词等)
field:title  
测试:


# Sample Analysis
curl -XGET localhost:9200/local/_analyze?analyzer=stem -d '{Fight for your life}'
curl -XGET localhost:9200/local/_analyze?analyzer=stem -d '{Bruno fights Tyson tomorrow}'
 
# Index Data
curl -XPUT localhost:9200/local/article/1 -d'{"title": "Fight for your life"}'
curl -XPUT localhost:9200/local/article/2 -d'{"title": "Fighting for your life"}'
curl -XPUT localhost:9200/local/article/3 -d'{"title": "My dad fought a dog"}'
curl -XPUT localhost:9200/local/article/4 -d'{"title": "Bruno fights Tyson tomorrow"}'
 
# search on the title field, which is stemmed on index and search
curl -XGET localhost:9200/local/_search?q=title:fight
 
# searching on _all will not do anystemming, unless also configured on the mapping to be stemmed...
curl -XGET localhost:9200/local/_search?q=fight

例如:

Fight for your life

分词如下:

{"tokens":[
{"token":"fight","start_offset":1,"end_offset":6,"type":"<ALPHANUM>","position":1},<br>
{"token":"your","start_offset":11,"end_offset":15,"type":"<ALPHANUM>","position":3},<br>
{"token":"life","start_offset":16,"end_offset":20,"type":"<ALPHANUM>","position":4}
]}

 -------------------另一篇--------------------
ElasticSearch安装ik分词插件

一、IK简介
    IK Analyzer是一个开源的,基于java语言开发的轻量级的中文分词工具包。从2006年12月推出1.0版开始, IKAnalyzer已经推出了4个大版本。最初,它是以开源项目Luence为应用主体的,结合词典分词和文法分析算法的中文分词组件。从3.0版本开 始,IK发展为面向Java的公用分词组件,独立于Lucene项目,同时提供了对Lucene的默认优化实现。在2012版本中,IK实现了简单的分词 歧义排除算法,标志着IK分词器从单纯的词典分词向模拟语义分词衍化。 
    IK Analyzer 2012特性:
    1.采用了特有的“正向迭代最细粒度切分算法“,支持细粒度和智能分词两种切分模式;
    2.在系统环境:Core2 i7 3.4G双核,4G内存,window 7 64位, Sun JDK 1.6_29 64位 普通pc环境测试,IK2012具有160万字/秒(3000KB/S)的高速处理能力。
    3.2012版本的智能分词模式支持简单的分词排歧义处理和数量词合并输出。
    4.采用了多子处理器分析模式,支持:英文字母、数字、中文词汇等分词处理,兼容韩文、日文字符
    5.优化的词典存储,更小的内存占用。支持用户词典扩展定义。特别的,在2012版本,词典支持中文,英文,数字混合词语。


二、安装IK分词插件
    假设读者已经安装好ES,如果没有的话,请参考ElasticSearch入门 —— 集群搭建。安装IK分词需要的资源可以从这里下载,整个安装过程需要三个步骤:
    1、获取分词的依赖包
    通过git clone https://github.com/medcl/elasticsearch-analysis-ik,下载分词器源码,然后进入下载目录,执行命令:mvn clean package,打包生成elasticsearch-analysis-ik-1.2.5.jar。将这个jar拷贝到ES_HOME/plugins/analysis-ik目录下面,如果没有该目录,则先创建该目录。
    2、ik目录拷贝
    将下载目录中的ik目录拷贝到ES_HOME/config目录下面。
    3、分词器配置
    打开ES_HOME/config/elasticsearch.yml文件,在文件最后加入如下内容:

index:  
  analysis:                     
    analyzer:        
      ik:  
          alias: [ik_analyzer]  
          type: org.elasticsearch.index.analysis.IkAnalyzerProvider  
      ik_max_word:  
          type: ik  
          use_smart: false  
      ik_smart:  
          type: ik  
          use_smart: true  

index.analysis.analyzer.default.type: ik 

    ok!插件安装已经完成,请重新启动ES,接下来测试ik分词效果啦!
三、ik分词测试
    1、创建一个索引,名为index。  

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

    2、为索引index创建mapping。

curl -XPOST http://localhost:9200/index/fulltext/_mapping -d'  
{  
    "fulltext": {  
             "_all": {  
            "analyzer": "ik"  
        },  
        "properties": {  
            "content": {  
                "type" : "string",  
                "boost" : 8.0,  
                "term_vector" : "with_positions_offsets",  
                "analyzer" : "ik",  
                "include_in_all" : true  
            }  
        }  
    }  
}' 

    3、测试

curl 'http://localhost:9200/index/_analyze?analyzer=ik&pretty=true' -d '  
{  
"text":"世界如此之大"  
}' 

    显示结果如下:
{  
  "tokens" : [ {  
    "token" : "text",  
    "start_offset" : 4,  
    "end_offset" : 8,  
    "type" : "ENGLISH",  
    "position" : 1  
  }, {  
    "token" : "世界",  
    "start_offset" : 11,  
    "end_offset" : 13,  
    "type" : "CN_WORD",  
    "position" : 2  
  }, {  
    "token" : "如此",  
    "start_offset" : 13,  
    "end_offset" : 15,  
    "type" : "CN_WORD",  
    "position" : 3  
  }, {  
    "token" : "之大",  
    "start_offset" : 15,  
    "end_offset" : 17,  
    "type" : "CN_WORD",  
    "position" : 4  
  } ]  

----一下摘自官方----
Dict Configuration (es-root/config/ik/IKAnalyzer.cfg.xml)
-—————

https://github.com/medcl/elasticsearch-analysis-ik/blob/master/config/ik/IKAnalyzer.cfg.xml

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

Analysis Configuration (elasticsearch.yml)
-—————

index:
  analysis:                   
    analyzer:      
      ik:
          alias: [ik_analyzer]
          type: org.elasticsearch.index.analysis.IkAnalyzerProvider
      ik_max_word:
          type: ik
          use_smart: false
      ik_smart:
          type: ik
          use_smart: true

Or

index.analysis.analyzer.ik.type : “ik”

you can set your prefer segment mode,default `use_smart` is false.

Mapping Configuration
-—————

Here is a quick example:
1.create a index

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

2.create a mapping

curl -XPOST http://localhost:9200/index/fulltext/_mapping -d'
{
    "fulltext": {
             "_all": {
            "indexAnalyzer": "ik",
            "searchAnalyzer": "ik",
            "term_vector": "no",
            "store": "false"
        },
        "properties": {
            "content": {
                "type": "string",
                "store": "no",
                "term_vector": "with_positions_offsets",
                "indexAnalyzer": "ik",
                "searchAnalyzer": "ik",
                "include_in_all": "true",
                "boost": 8
            }
        }
    }
}'
3.index some docs

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

curl -XPOST http://localhost:9200/index/fulltext/_search  -d'
{
    "query" : { "term" : { "content" : "中国" }},
    "highlight" : {
        "pre_tags" : ["<tag1>", "<tag2>"],
        "post_tags" : ["</tag1>", "</tag2>"],
        "fields" : {
            "content" : {}
        }
    }
}
'
here is the query result

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

没有更多推荐了,返回首页