欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Elasticsearch 默认分词器和中分分词器之间的比较及使用方法

程序员文章站 2022-07-04 22:11:47
...

介绍:ElasticSearch 是一个基于 Lucene 的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于 RESTful web 接口。Elasticsearch 是用 Java 开发的,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。

Elasticsearch中,内置了很多分词器(analyzers)。下面来进行比较下系统默认分词器和常用的中文分词器之间的区别。
<!-- more -->

系统默认分词器:

1、standard 分词器

https://www.elastic.co/guide/...

如何使用:http://www.yiibai.com/lucene/...

英文的处理能力同于StopAnalyzer.支持中文采用的方法为单字切分。他会将词汇单元转换成小写形式,并去除停用词和标点符号。

/**StandardAnalyzer分析器*/
    public void standardAnalyzer(String msg){
        StandardAnalyzer analyzer = new StandardAnalyzer(Version.LUCENE_36);
        this.getTokens(analyzer, msg);
    }

2、simple 分词器

https://www.elastic.co/guide/...

如何使用: http://www.yiibai.com/lucene/...

功能强于WhitespaceAnalyzer, 首先会通过非字母字符来分割文本信息,然后将词汇单元统一为小写形式。该分析器会去掉数字类型的字符。

/**SimpleAnalyzer分析器*/
    public void simpleAnalyzer(String msg){
        SimpleAnalyzer analyzer = new SimpleAnalyzer(Version.LUCENE_36);
        this.getTokens(analyzer, msg);
    }

3、Whitespace 分词器

https://www.elastic.co/guide/...

如何使用:http://www.yiibai.com/lucene/...

仅仅是去除空格,对字符没有lowcase化,不支持中文;
并且不对生成的词汇单元进行其他的规范化处理。

/**WhitespaceAnalyzer分析器*/
    public void whitespaceAnalyzer(String msg){
        WhitespaceAnalyzer analyzer = new WhitespaceAnalyzer(Version.LUCENE_36);
        this.getTokens(analyzer, msg);
    }

4、Stop 分词器

https://www.elastic.co/guide/...

如何使用:http://www.yiibai.com/lucene/...

StopAnalyzer的功能超越了SimpleAnalyzer,在SimpleAnalyzer的基础上增加了去除英文中的常用单词(如the,a等),也可以更加自己的需要设置常用单词;不支持中文

/**StopAnalyzer分析器*/
   public void stopAnalyzer(String msg){
       StopAnalyzer analyzer = new StopAnalyzer(Version.LUCENE_36);
       this.getTokens(analyzer, msg);
   }

5、keyword 分词器

KeywordAnalyzer把整个输入作为一个单独词汇单元,方便特殊类型的文本进行索引和检索。针对邮政编码,地址等文本信息使用关键词分词器进行索引项建立非常方便。

6、pattern 分词器

https://www.elastic.co/guide/...

一个pattern类型的analyzer可以通过正则表达式将文本分成"terms"(经过token Filter 后得到的东西 )。接受如下设置:

一个 pattern analyzer 可以做如下的属性设置:

lowercase terms是否是小写. 默认为 true 小写.
pattern 正则表达式的pattern, 默认是 W+.
flags 正则表达式的flags
stopwords 一个用于初始化stop filter的需要stop 单词的列表.默认单词是空的列表

7、language 分词器

https://www.elastic.co/guide/...

一个用于解析特殊语言文本的analyzer集合。( arabic,armenian, basque, brazilian, bulgarian, catalan, cjk, czech, danish, dutch, english, finnish, french,galician, german, greek, hindi, hungarian, indonesian, irish, italian, latvian, lithuanian, norwegian,persian, portuguese, romanian, russian, sorani, spanish, swedish, turkish, thai.)可惜没有中文。不予考虑

8、snowball 分词器

一个snowball类型的analyzer是由standard tokenizer和standard filter、lowercase filter、stop filter、snowball filter这四个filter构成的。

snowball analyzer 在Lucene中通常是不推荐使用的。

9、Custom 分词器

是自定义的analyzer。允许多个零到多个tokenizer,零到多个 Char Filters. custom analyzer 的名字不能以 "_"开头.

The following are settings that can be set for a custom analyzer type:

Setting Description
tokenizer 通用的或者注册的tokenizer.
filter 通用的或者注册的token filters
char_filter 通用的或者注册的 character filters
position_increment_gap 距离查询时,最大允许查询的距离,默认是100

自定义的模板:

index :
    analysis :
        analyzer :
            myAnalyzer2 :
                type : custom
                tokenizer : myTokenizer1
                filter : [myTokenFilter1, myTokenFilter2]
                char_filter : [my_html]
                position_increment_gap: 256
        tokenizer :
            myTokenizer1 :
                type : standard
                max_token_length : 900
        filter :
            myTokenFilter1 :
                type : stop
                stopwords : [stop1, stop2, stop3, stop4]
            myTokenFilter2 :
                type : length
                min : 0
                max : 2000
        char_filter :
              my_html :
                type : html_strip
                escaped_tags : [xxx, yyy]
                read_ahead : 1024

10、fingerprint 分词器

https://www.elastic.co/guide/...


中文分词器:

1、ik-analyzer

https://github.com/wks/ik-ana...

IKAnalyzer是一个开源的,基于java语言开发的轻量级的中文分词工具包。

采用了特有的“正向迭代最细粒度切分算法“,支持细粒度和最大词长两种切分模式;具有83万字/秒(1600KB/S)的高速处理能力。

采用了多子处理器分析模式,支持:英文字母、数字、中文词汇等分词处理,兼容韩文、日文字符

优化的词典存储,更小的内存占用。支持用户词典扩展定义

针对Lucene全文检索优化的查询分析器IKQueryParser(作者吐血推荐);引入简单搜索表达式,采用歧义分析算法优化查询关键字的搜索排列组合,能极大的提高Lucene检索的命中率。

Maven用法:

<dependency>
    <groupId>org.wltea.ik-analyzer</groupId>
    <artifactId>ik-analyzer</artifactId>
    <version>3.2.8</version>
</dependency>

在IK Analyzer加入Maven Central Repository之前,你需要手动安装,安装到本地的repository,或者上传到自己的Maven repository服务器上。

要安装到本地Maven repository,使用如下命令,将自动编译,打包并安装:
mvn install -Dmaven.test.skip=true

Elasticsearch添加中文分词

安装IK分词插件

https://github.com/medcl/elas...

进入elasticsearch-analysis-ik-master

更多安装请参考博客:

1、为elastic添加中文分词

2、如何在Elasticsearch中安装中文分词器(IK+pinyin)

3、Elasticsearch 中文分词器 IK 配置和使用

2、结巴中文分词

特点:

1、支持三种分词模式:

  • 精确模式,试图将句子最精确地切开,适合文本分析;

  • 全模式,把句子中所有的可以成词的词语都扫描出来, 速度非常快,但是不能解决歧义;

  • 搜索引擎模式,在精确模式的基础上,对长词再次切分,提高召回率,适合用于搜索引擎分词。

2、支持繁体分词

3、支持自定义词典

3、THULAC

THULAC(THU Lexical Analyzer for Chinese)由清华大学自然语言处理与社会人文计算实验室研制推出的一套中文词法分析工具包,具有中文分词和词性标注功能。THULAC具有如下几个特点:

能力强。利用我们集成的目前世界上规模最大的人工分词和词性标注中文语料库(约含5800万字)训练而成,模型标注能力强大。

准确率高。该工具包在标准数据集Chinese Treebank(CTB5)上分词的F1值可达97.3%,词性标注的F1值可达到92.9%,与该数据集上最好方法效果相当。

速度较快。同时进行分词和词性标注速度为300KB/s,每秒可处理约15万字。只进行分词速度可达到1.3MB/s。

中文分词工具thulac4j发布

1、规范化分词词典,并去掉一些无用词;

2、重写DAT(双数组Trie树)的构造算法,生成的DAT size减少了8%左右,从而节省了内存;

3、优化分词算法,提高了分词速率。

<dependency>
  <groupId>io.github.yizhiru</groupId>
  <artifactId>thulac4j</artifactId>
  <version>${thulac4j.version}</version>
</dependency>

http://www.cnblogs.com/en-hen...

thulac4j支持两种分词模式:

SegOnly模式,只分词没有词性标注;

SegPos模式,分词兼有词性标注。

// SegOnly mode
String sentence = "滔滔的流水,向着波士顿湾无声逝去";
SegOnly seg = new SegOnly("models/seg_only.bin");
System.out.println(seg.segment(sentence));
// [滔滔, 的, 流水, ,, 向着, 波士顿湾, 无声, 逝去]

// SegPos mode
SegPos pos = new SegPos("models/seg_pos.bin");
System.out.println(pos.segment(sentence));
//[滔滔/a, 的/u, 流水/n, ,/w, 向着/p, 波士顿湾/ns, 无声/v, 逝去/v]

4、NLPIR

中科院计算所 NLPIR:http://ictclas.nlpir.org/nlpir/ (可直接在线分析中文)

下载地址:https://github.com/NLPIR-team...

中科院分词系统(NLPIR)JAVA简易教程: http://www.cnblogs.com/wukong...

5、ansj分词器

https://github.com/NLPchina/a...

这是一个基于n-Gram+CRF+HMM的中文分词的java实现.

分词速度达到每秒钟大约200万字左右(mac air下测试),准确率能达到96%以上

目前实现了.中文分词. 中文姓名识别 .

用户自定义词典,关键字提取,自动摘要,关键字标记等功能
可以应用到自然语言处理等方面,适用于对分词效果要求高的各种项目.

maven 引入:

<dependency>
            <groupId>org.ansj</groupId>
            <artifactId>ansj_seg</artifactId>
            <version>5.1.1</version>
</dependency>

调用demo

String str = "欢迎使用ansj_seg,(ansj中文分词)在这里如果你遇到什么问题都可以联系我.我一定尽我所能.帮助大家.ansj_seg更快,更准,更*!" ;
 System.out.println(ToAnalysis.parse(str));

 欢迎/v,使用/v,ansj/en,_,seg/en,,,(,ansj/en,中文/nz,分词/n,),在/p,这里/r,如果/c,你/r,遇到/v,什么/r,问题/n,都/d,可以/v,联系/v,我/r,./m,我/r,一定/d,尽我所能/l,./m,帮助/v,大家/r,./m,ansj/en,_,seg/en,更快/d,,,更/d,准/a,,,更/d,*/a,!

6、哈工大的LTP

https://link.zhihu.com/?targe...

LTP制定了基于XML的语言处理结果表示,并在此基础上提供了一整套自底向上的丰富而且高效的中文语言处理模块(包括词法、句法、语义等6项中文处理核心技术),以及基于动态链接库(Dynamic Link Library, DLL)的应用程序接口、可视化工具,并且能够以网络服务(Web Service)的形式进行使用。

关于LTP的使用,请参考: http://ltp.readthedocs.io/zh_...

7、庖丁解牛

下载地址:http://pan.baidu.com/s/1eQ88SZS

使用分为如下几步:

  1. 配置dic文件:
    修改paoding-analysis.jar中的paoding-dic-home.properties文件,将“#paoding.dic.home=dic”的注释去掉,并配置成自己dic文件的本地存放路径。eg:/home/hadoop/work/paoding-analysis-2.0.4-beta/dic

  2. 把Jar包导入到项目中:
    将paoding-analysis.jar、commons-logging.jar、lucene-analyzers-2.2.0.jar和lucene-core-2.2.0.jar四个包导入到项目中,这时就可以在代码片段中使用庖丁解牛工具提供的中文分词技术,例如:

Analyzer analyzer = new PaodingAnalyzer(); //定义一个解析器
String text = "庖丁系统是个完全基于lucene的中文分词系统,它就是重新建了一个analyzer,叫做PaodingAnalyzer,这个analyer的核心任务就是生成一个可以切词TokenStream。"; <span style="font-family: Arial, Helvetica, sans-serif;">//待分词的内容</span>
TokenStream tokenStream = analyzer.tokenStream(text, new StringReader(text)); //得到token序列的输出流
try {
    Token t;
    while ((t = tokenStream.next()) != null)
    {
           System.out.println(t); //输出每个token
    }
} catch (IOException e) {
    e.printStackTrace();
}

8、sogo在线分词

sogo在线分词采用了基于汉字标注的分词方法,主要使用了线性链链CRF(Linear-chain CRF)模型。词性标注模块主要基于结构化线性模型(Structured Linear Model)

在线使用地址为:
http://www.sogou.com/labs/web...

9、word分词

地址: https://github.com/ysc/word

word分词是一个Java实现的分布式的中文分词组件,提供了多种基于词典的分词算法,并利用ngram模型来消除歧义。能准确识别英文、数字,以及日期、时间等数量词,能识别人名、地名、组织机构名等未登录词。能通过自定义配置文件来改变组件行为,能自定义用户词库、自动检测词库变化、支持大规模分布式环境,能灵活指定多种分词算法,能使用refine功能灵活控制分词结果,还能使用词频统计、词性标注、同义标注、反义标注、拼音标注等功能。提供了10种分词算法,还提供了10种文本相似度算法,同时还无缝和Lucene、Solr、ElasticSearch、Luke集成。注意:word1.3需要JDK1.8

maven 中引入依赖:

<dependencies>
    <dependency>
        <groupId>org.apdplat</groupId>
        <artifactId>word</artifactId>
        <version>1.3</version>
    </dependency>
</dependencies>

ElasticSearch插件:

1、打开命令行并切换到elasticsearch的bin目录
cd elasticsearch-2.1.1/bin

2、运行plugin脚本安装word分词插件:
./plugin install http://apdplat.org/word/archive/v1.4.zip

安装的时候注意:
    如果提示:
        ERROR: failed to download
    或者
        Failed to install word, reason: failed to download
    或者
        ERROR: incorrect hash (SHA1)
    则重新再次运行命令,如果还是不行,多试两次

如果是elasticsearch1.x系列版本,则使用如下命令:
./plugin -u http://apdplat.org/word/archive/v1.3.1.zip -i word

3、修改文件elasticsearch-2.1.1/config/elasticsearch.yml,新增如下配置:
index.analysis.analyzer.default.type : "word"
index.analysis.tokenizer.default.type : "word"

4、启动ElasticSearch测试效果,在Chrome浏览器中访问:
http://localhost:9200/_analyze?analyzer=word&text=杨尚川是APDPlat应用级产品开发平台的作者

5、自定义配置
修改配置文件elasticsearch-2.1.1/plugins/word/word.local.conf

6、指定分词算法
修改文件elasticsearch-2.1.1/config/elasticsearch.yml,新增如下配置:
index.analysis.analyzer.default.segAlgorithm : "ReverseMinimumMatching"
index.analysis.tokenizer.default.segAlgorithm : "ReverseMinimumMatching"

这里segAlgorithm可指定的值有:
正向最大匹配算法:MaximumMatching
逆向最大匹配算法:ReverseMaximumMatching
正向最小匹配算法:MinimumMatching
逆向最小匹配算法:ReverseMinimumMatching
双向最大匹配算法:BidirectionalMaximumMatching
双向最小匹配算法:BidirectionalMinimumMatching
双向最大最小匹配算法:BidirectionalMaximumMinimumMatching
全切分算法:FullSegmentation
最少词数算法:MinimalWordCount
最大Ngram分值算法:MaxNgramScore
如不指定,默认使用双向最大匹配算法:BidirectionalMaximumMatching

10、jcseg分词器

https://code.google.com/archi...

11、stanford分词器

Stanford大学的一个开源分词工具,目前已支持汉语。

首先,去【1】下载Download Stanford Word Segmenter version 3.5.2,取得里面的 data 文件夹,放在maven project的 src/main/resources 里。

然后,maven依赖添加:

<properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <corenlp.version>3.6.0</corenlp.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>edu.stanford.nlp</groupId>
            <artifactId>stanford-corenlp</artifactId>
            <version>${corenlp.version}</version>
        </dependency>
        <dependency>
            <groupId>edu.stanford.nlp</groupId>
            <artifactId>stanford-corenlp</artifactId>
            <version>${corenlp.version}</version>
            <classifier>models</classifier>
        </dependency>
        <dependency>
            <groupId>edu.stanford.nlp</groupId>
            <artifactId>stanford-corenlp</artifactId>
            <version>${corenlp.version}</version>
            <classifier>models-chinese</classifier>
        </dependency>
    </dependencies>

测试:

import java.util.Properties;

import edu.stanford.nlp.ie.crf.CRFClassifier;

public class CoreNLPSegment {

    private static CoreNLPSegment instance;
    private CRFClassifier         classifier;

    private CoreNLPSegment(){
        Properties props = new Properties();
        props.setProperty("sighanCorporaDict", "data");
        props.setProperty("serDictionary", "data/dict-chris6.ser.gz");
        props.setProperty("inputEncoding", "UTF-8");
        props.setProperty("sighanPostProcessing", "true");
        classifier = new CRFClassifier(props);
        classifier.loadClassifierNoExceptions("data/ctb.gz", props);
        classifier.flags.setProperties(props);
    }

    public static CoreNLPSegment getInstance() {
        if (instance == null) {
            instance = new CoreNLPSegment();
        }

        return instance;
    }

    public String[] doSegment(String data) {
        return (String[]) classifier.segmentString(data).toArray();
    }

    public static void main(String[] args) {

        String sentence = "他和我在学校里常打桌球。";
        String ret[] = CoreNLPSegment.getInstance().doSegment(sentence);
        for (String str : ret) {
            System.out.println(str);
        }

    }

}

博客

https://blog.sectong.com/blog...

http://blog.csdn.net/lightty/...

12、Smartcn

Smartcn为Apache2.0协议的开源中文分词系统,Java语言编写,修改的中科院计算所ICTCLAS分词系统。很早以前看到Lucene上多了一个中文分词的contribution,当时只是简单的扫了一下.class文件的文件名,通过文件名可以看得出又是一个改的ICTCLAS的分词系统。

http://lucene.apache.org/core...


自定义分词器

虽然Elasticsearch带有一些现成的分析器,然而在分析器上Elasticsearch真正的强大之处在于,你可以通过在一个适合你的特定数据的设置之中组合字符过滤器、分词器、词汇单元过滤器来创建自定义的分析器。

字符过滤器

字符过滤器 用来 整理 一个尚未被分词的字符串。例如,如果我们的文本是HTML格式的,它会包含像 <p> 或者 <div> 这样的HTML标签,这些标签是我们不想索引的。我们可以使用 html清除 字符过滤器 来移除掉所有的HTML标签,并且像把 &Aacute; 转换为相对应的Unicode字符 Á 这样,转换HTML实体。

一个分析器可能有0个或者多个字符过滤器。

分词器:

一个分析器 必须 有一个唯一的分词器。 分词器把字符串分解成单个词条或者词汇单元。 标准 分析器里使用的 标准 分词器 把一个字符串根据单词边界分解成单个词条,并且移除掉大部分的标点符号,然而还有其他不同行为的分词器存在。

词单元过滤器:

经过分词,作为结果的 词单元流 会按照指定的顺序通过指定的词单元过滤器 。

词单元过滤器可以修改、添加或者移除词单元。我们已经提到过 lowercase 和 stop 词过滤器 ,但是在 Elasticsearch 里面还有很多可供选择的词单元过滤器。 词干过滤器 把单词 遏制 为 词干。 ascii_folding 过滤器移除变音符,把一个像 "très" 这样的词转换为 "tres" 。 ngram 和 edge_ngram 词单元过滤器 可以产生 适合用于部分匹配或者自动补全的词单元。

创建一个自定义分析器

我们可以在 analysis 下的相应位置设置字符过滤器、分词器和词单元过滤器:

PUT /my_index
{
    "settings": {
        "analysis": {
            "char_filter": { ... custom character filters ... },
            "tokenizer":   { ...    custom tokenizers     ... },
            "filter":      { ...   custom token filters   ... },
            "analyzer":    { ...    custom analyzers      ... }
        }
    }
}

这个分析器可以做到下面的这些事:

1、使用 html清除 字符过滤器移除HTML部分。

2、使用一个自定义的 映射 字符过滤器把 & 替换为 "和" :

"char_filter": {
    "&_to_and": {
        "type":       "mapping",
        "mappings": [ "&=> and "]
    }
}

3、使用 标准 分词器分词。

4、小写词条,使用 小写 词过滤器处理。

5、使用自定义 停止 词过滤器移除自定义的停止词列表中包含的词:

"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" ]
    }
}

汇总起来,完整的 创建索引 请求 看起来应该像这样:


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" ]
            }}
}}}

索引被创建以后,使用 analyze API 来 测试这个新的分析器:

GET /my_index/_analyze?analyzer=my_analyzer
The quick & brown fox

下面的缩略结果展示出我们的分析器正在正确地运行:

{
  "tokens" : [
      { "token" :   "quick",    "position" : 2 },
      { "token" :   "and",      "position" : 3 },
      { "token" :   "brown",    "position" : 4 },
      { "token" :   "fox",      "position" : 5 }
    ]
}

这个分析器现在是没有多大用处的,除非我们告诉 Elasticsearch在哪里用上它。我们可以像下面这样把这个分析器应用在一个 string 字段上:

PUT /my_index/_mapping/my_type
{
    "properties": {
        "title": {
            "type":      "string",
            "analyzer":  "my_analyzer"
        }
    }
}

来源:https://segmentfault.com/a/1190000011065897#articleHeader12