ES快速入门(I)——分析分词器

  created  by  鱼鱼 {{tag}}
创建于 2020年08月30日 11:13:34 最后修改于 2020年09月01日 00:02:58

    本文旨在快速入门Elasticsearch的分词,包括分词分析器的创建和介绍对比等,请确保在阅读前已经搭建好完备的集群。文章基于es7.0+,与稍旧版本的主要区别是没有type。

分词过程

    在讨论分词前,我们先看一下es整体创建倒排的分词过程:

    我们常说的分词器指的其实是“分析器”analyzer,es将以上常用的逻辑封装起来成为analyzer,但是语义上的分词器是指上面的tokenizer。

    经过了三层处理后拿到了terms数组建立最终的倒排索引:

  1. character filter:一般不会用到这个filter,是在分词前对原有的文档字段内容做转换,例如去除html的标签提取出正文内容,按正则清除和替换某些内容,你可以指定及自定义0个到多个character filter,他们将共同存在,一个文本流在经过character filter处理后,依然是文本流;

  2. tokenizer:分词器,是Analyzer的核心,要求有且只有一个,它规定了语句的切分规则,利用tokenizer拆分后的文本可被称作token,只使用单一的tokenizer就可以构造最简单的analyzer了;

  3. token filter:在获取token集合后,再利用token filter进行过滤和转化从而得到最终的分词倒排集合(我们称结果集合中的元素为term),例如转换大小写,处理停用词(一些被忽略并当做分隔符的词汇)等。

  4. 特别地,对于不可分词的keyword,也有其专属的处理器,被称作normalizer

    一般说来,指定的既有分析器和一些开源的分析器(例如ik分析器)已经能够处理大部分搜索情况,在使用时直接创建相应的field即可。有时根据具体业务形态,可能也要对分词方式做出改变,此时才需要自己定制一套分词规则。

API——创建指定分词的字段、测试分词

    本段记录相关的API。

创建mapping和index

    在创建mapping/type时,我们可以手动的指定一个字段使用哪些分词方式,同个field如果使用多个分词方式其在使用上视为多个字段。接下来,让我们先创建一个名为test_index的index,因为是单机测试,所以此处只额外的备份数为0,使用5个分片,刷新间隔30s:(index这一层级其实省略也可)

curl -X PUT "localhost:9200/test_index" -H 'Content-Type: application/json' -d'
{
	"settings": {
		"index":{
			"refresh_interval": "30s",
			"number_of_shards": "5",
			"number_of_replicas": "0"
		}
	}
}
'

    接下来创建一个测试的mapping,其实可以在创建index时直接指定,我们指定了两个数据类型为text的field,此时并未定义它的分词方式,es会为他分配默认的standard解析器(url已经指定了type为_doc,这也是7.0后固定的type),因为已经创建完了index,所以只能在_doc端点执行修改的POST请求:

curl -X POST "localhost:9200/test_index/_mapping/_doc" -H 'Content-Type: application/json' -d'
{
	"properties": {
	    "name": { "type": "text" }, 
	    "email": { "type": "keyword" },
	    "content": { "type": "text" ,"analyzer":"simple"},
	    "tweeted_at": { "type": "date" }
	}
}
'

    其中content使用了simple的analyzer,而name字段使用了默认的standard的analyzer。

为index指定自定义analyzer或normalizer

    对于已经建立了索引的index,需要先将其关闭才能新增自定义analyzer,当然可以在创建index时直接指定:

curl -X POST "localhost:9200/test_index/_close"

    然后可以创建自定义分词器和过滤器的analyzer,这里创建了一个名为my_analyzer的分析器,并为其指定了tokenizer和filters,其中tokenizer为必选,其余均可为0到多个:

curl -X PUT "localhost:9200/test_index/_settings" -H 'Content-Type: application/json' -d'
{
	 "analysis": {
	    	"analyzer": {
	        	"my_analyzer":{
					"tokenizer":"standard",
					"filter":["standard", "lowercase", "stop"],
					"char_filter":  [ "html_strip" ]
	                }
	        }
	 }
}
'

    也可以指定一个normalizer:

curl -X PUT "localhost:9200/test_index/_settings" -H 'Content-Type: application/json' -d'
{
	  "analysis": {
	         "normalizer": {
		        "my_normalizer": {
		          "filter": ["lowercase", "asciifolding"]
		        }
		  }
	    	
	  }
}
'

其后记得再打开index:

curl -X POST "localhost:9200/test_index/_open"

新增field并指定分析器

    我们可以添加新的字段,也可以在原有字段映射新的分析器,但是已有的字段映射是不能修改的 包括分析器和数据类型,因为倒排索引是已经建好的,我们为content指定了一个新的whitespace的分析器映射,名也为whitespace(使用时为content.whitespace):

curl -X PUT "localhost:9200/test_index/_mapping/_doc" -H 'Content-Type: application/json' -d'
{
	"properties": {
	    "content": { 
	    	"type": "text",
	    	"analyzer":"simple",
	    	"fields":{
	    		"whitespace":{
	    			"type":"text",
	    			"analyzer":"whitespace"
	    		}
	    	}
	    } 
	    
	}
}

测试分析、分词器

    可以测试各种分词、分析器的效果:

curl -X GET "localhost:9200/{index}/_analyze" -H 'Content-Type: application/json' -d'
{
  "analyzer" : "standard",
  "text" : "Quick Brown Foxes!"
}
'

    上面指定了一个analyzer,其中的index是可选的,如果选了index,就可以使用对应index具体字段的分词器。也指定了要分词的content(text),除去text外,其余参数都为选填:

  • text:待分词的语句,必填;

  • analyzer:指定使用的分析器,优先级高于tokenizer,如果没有任何除去text的额外参数,则有一个隐性的analyzer:standard;

  • char_filter:像定义分析器那样指定charfilter;

  • filter:指定token filter;

  • field:在指定了index的前提下,可以指定一个字段使用该字段的分词器;

  • tokenizer:指定分词器;

  • normalizer:指定规范器,与tokenizer和analyzer相悖。

    会返回相应的分词结果,例如:

curl -X GET "localhost:9200/{index}/_analyze" -H 'Content-Type: application/json' -d'
{
  "analyzer" : "english",
  "text" : "Brown Foxes jump into the hole!"
}
'

    返回:

{
    "tokens": [
        {
            "token": "brown",
            "start_offset": 0,
            "end_offset": 5,
            "type": "<ALPHANUM>",
            "position": 0
        },
        {
            "token": "fox",
            "start_offset": 6,
            "end_offset": 11,
            "type": "<ALPHANUM>",
            "position": 1
        },
        {
            "token": "jump",
            "start_offset": 12,
            "end_offset": 16,
            "type": "<ALPHANUM>",
            "position": 2
        },
        {
            "token": "hole",
            "start_offset": 26,
            "end_offset": 30,
            "type": "<ALPHANUM>",
            "position": 5
        }
    ]
}

    也可以看一下上文中自定义的normalizer的效果:

curl -X GET "localhost:9200/test_index/_analyze" -H 'Content-Type: application/json' -d'
{
    "normalizer" : "my_normalizer",
  "text" : "Brown Foxes jump into the hole!"
}
'
{
    "tokens": [
        {
            "token": "brown foxes jump into the hole!",
            "start_offset": 0,
            "end_offset": 31,
            "type": "word",
            "position": 0
        }
    ]
}

    会发现除去过滤效果,其整体是一个token。

评论区
评论
{{comment.creator}}
{{comment.createTime}} {{comment.index}}楼
评论

ES快速入门(I)——分析分词器

ES快速入门(I)——分析分词器

    本文旨在快速入门Elasticsearch的分词,包括分词分析器的创建和介绍对比等,请确保在阅读前已经搭建好完备的集群。文章基于es7.0+,与稍旧版本的主要区别是没有type。

分词过程

    在讨论分词前,我们先看一下es整体创建倒排的分词过程:

    我们常说的分词器指的其实是“分析器”analyzer,es将以上常用的逻辑封装起来成为analyzer,但是语义上的分词器是指上面的tokenizer。

    经过了三层处理后拿到了terms数组建立最终的倒排索引:

  1. character filter:一般不会用到这个filter,是在分词前对原有的文档字段内容做转换,例如去除html的标签提取出正文内容,按正则清除和替换某些内容,你可以指定及自定义0个到多个character filter,他们将共同存在,一个文本流在经过character filter处理后,依然是文本流;

  2. tokenizer:分词器,是Analyzer的核心,要求有且只有一个,它规定了语句的切分规则,利用tokenizer拆分后的文本可被称作token,只使用单一的tokenizer就可以构造最简单的analyzer了;

  3. token filter:在获取token集合后,再利用token filter进行过滤和转化从而得到最终的分词倒排集合(我们称结果集合中的元素为term),例如转换大小写,处理停用词(一些被忽略并当做分隔符的词汇)等。

  4. 特别地,对于不可分词的keyword,也有其专属的处理器,被称作normalizer

    一般说来,指定的既有分析器和一些开源的分析器(例如ik分析器)已经能够处理大部分搜索情况,在使用时直接创建相应的field即可。有时根据具体业务形态,可能也要对分词方式做出改变,此时才需要自己定制一套分词规则。

API——创建指定分词的字段、测试分词

    本段记录相关的API。

创建mapping和index

    在创建mapping/type时,我们可以手动的指定一个字段使用哪些分词方式,同个field如果使用多个分词方式其在使用上视为多个字段。接下来,让我们先创建一个名为test_index的index,因为是单机测试,所以此处只额外的备份数为0,使用5个分片,刷新间隔30s:(index这一层级其实省略也可)

curl -X PUT "localhost:9200/test_index" -H 'Content-Type: application/json' -d'
{
	"settings": {
		"index":{
			"refresh_interval": "30s",
			"number_of_shards": "5",
			"number_of_replicas": "0"
		}
	}
}
'

    接下来创建一个测试的mapping,其实可以在创建index时直接指定,我们指定了两个数据类型为text的field,此时并未定义它的分词方式,es会为他分配默认的standard解析器(url已经指定了type为_doc,这也是7.0后固定的type),因为已经创建完了index,所以只能在_doc端点执行修改的POST请求:

curl -X POST "localhost:9200/test_index/_mapping/_doc" -H 'Content-Type: application/json' -d'
{
	"properties": {
	    "name": { "type": "text" }, 
	    "email": { "type": "keyword" },
	    "content": { "type": "text" ,"analyzer":"simple"},
	    "tweeted_at": { "type": "date" }
	}
}
'

    其中content使用了simple的analyzer,而name字段使用了默认的standard的analyzer。

为index指定自定义analyzer或normalizer

    对于已经建立了索引的index,需要先将其关闭才能新增自定义analyzer,当然可以在创建index时直接指定:

curl -X POST "localhost:9200/test_index/_close"

    然后可以创建自定义分词器和过滤器的analyzer,这里创建了一个名为my_analyzer的分析器,并为其指定了tokenizer和filters,其中tokenizer为必选,其余均可为0到多个:

curl -X PUT "localhost:9200/test_index/_settings" -H 'Content-Type: application/json' -d'
{
	 "analysis": {
	    	"analyzer": {
	        	"my_analyzer":{
					"tokenizer":"standard",
					"filter":["standard", "lowercase", "stop"],
					"char_filter":  [ "html_strip" ]
	                }
	        }
	 }
}
'

    也可以指定一个normalizer:

curl -X PUT "localhost:9200/test_index/_settings" -H 'Content-Type: application/json' -d'
{
	  "analysis": {
	         "normalizer": {
		        "my_normalizer": {
		          "filter": ["lowercase", "asciifolding"]
		        }
		  }
	    	
	  }
}
'

其后记得再打开index:

curl -X POST "localhost:9200/test_index/_open"

新增field并指定分析器

    我们可以添加新的字段,也可以在原有字段映射新的分析器,但是已有的字段映射是不能修改的 包括分析器和数据类型,因为倒排索引是已经建好的,我们为content指定了一个新的whitespace的分析器映射,名也为whitespace(使用时为content.whitespace):

curl -X PUT "localhost:9200/test_index/_mapping/_doc" -H 'Content-Type: application/json' -d'
{
	"properties": {
	    "content": { 
	    	"type": "text",
	    	"analyzer":"simple",
	    	"fields":{
	    		"whitespace":{
	    			"type":"text",
	    			"analyzer":"whitespace"
	    		}
	    	}
	    } 
	    
	}
}

测试分析、分词器

    可以测试各种分词、分析器的效果:

curl -X GET "localhost:9200/{index}/_analyze" -H 'Content-Type: application/json' -d'
{
  "analyzer" : "standard",
  "text" : "Quick Brown Foxes!"
}
'

    上面指定了一个analyzer,其中的index是可选的,如果选了index,就可以使用对应index具体字段的分词器。也指定了要分词的content(text),除去text外,其余参数都为选填:

    会返回相应的分词结果,例如:

curl -X GET "localhost:9200/{index}/_analyze" -H 'Content-Type: application/json' -d'
{
  "analyzer" : "english",
  "text" : "Brown Foxes jump into the hole!"
}
'

    返回:

{
    "tokens": [
        {
            "token": "brown",
            "start_offset": 0,
            "end_offset": 5,
            "type": "<ALPHANUM>",
            "position": 0
        },
        {
            "token": "fox",
            "start_offset": 6,
            "end_offset": 11,
            "type": "<ALPHANUM>",
            "position": 1
        },
        {
            "token": "jump",
            "start_offset": 12,
            "end_offset": 16,
            "type": "<ALPHANUM>",
            "position": 2
        },
        {
            "token": "hole",
            "start_offset": 26,
            "end_offset": 30,
            "type": "<ALPHANUM>",
            "position": 5
        }
    ]
}

    也可以看一下上文中自定义的normalizer的效果:

curl -X GET "localhost:9200/test_index/_analyze" -H 'Content-Type: application/json' -d'
{
    "normalizer" : "my_normalizer",
  "text" : "Brown Foxes jump into the hole!"
}
'
{
    "tokens": [
        {
            "token": "brown foxes jump into the hole!",
            "start_offset": 0,
            "end_offset": 31,
            "type": "word",
            "position": 0
        }
    ]
}

    会发现除去过滤效果,其整体是一个token。


ES快速入门(I)——分析分词器2020-09-01鱼鱼

{{commentTitle}}

评论   ctrl+Enter 发送评论