es 分析器
分析器一般用在下面两个场景中:
- ·创建或更新文档时(合称索引时),对相应的文本字段进行分词处理;
- ·查询文本字段时,对查询语句进行分词。
ES中的分析器有很多种,但是所有分析器的结构都遵循三段式原则,即字符过滤器、分词器和词语过滤器。
其中,字符过滤器可以有0个或多个,分词器必须只有一个,词语过滤器可以有0个或多个。从整体上来讲,三个部分的数据流方向为字符过滤器→分词器→分词过滤器。如图所示为一个分析器的构成示例。
图 分析器构成示例
对于不同的分析器,上述三部分的工作内容是不同的,为了正确匹配,如果在数据写入时指定了某个分析器,那么在匹配查询时也需要设定相同的分析器对查询语句进行分析。
字符过滤器
字符过滤器是分析器处理文本数据的第一道工序,它接收原始的字符流,对原始字符流中的字符进行添加、删除或者转换操作,进而改变原始的字符流。
表 ES内置的字符过滤器
分词器
分词器在分析器中负责非常重要的一环工作——按照规则来切分词语
分词器对文本进行切分后,需要保留词语与原始文本之间的对应关系,因此分词器还负责记录每个Token的位置,以及开始和结束的字符偏移量。
表 ES内置的分词器
分词过滤器
分词过滤器接收分词器的处理结果,并可以将切分好的词语进行加工和修改,进而对分词结果进行规范化、统一化和优化处理。
表 ES内置的分词过滤器
分析器的使用
ES提供了分析器的调用API,使用户可以方便地对比不同分析器的分析结果。另外,ES提供了一些开箱即用的内置分析器,这些分析器其实就是字符过滤器、分词器和分词过滤器的组合体,可以在索引建立时和搜索时指定使用这些分析器。当然,如果这些分析器不符合需求,用户还可以自定义分析器。
测试分析API
为了更好地理解分析器的运行结果,可以使用ES提供的分析API进行测试。在DSL中可以直接使用参数analyzer来指定分析器的名称进行测试,分析API的请求形式如下:
POST /_analyze
{
"analyzer": ${analyzer_name}, //指定分析器名称
"text":${analyzer_text} //待分析文本
}
以下示例使用standard分析器分析一段英文:
POST /_analyze
{
"analyzer": "standard", //指定分析器名称为standard
"text": "The letter tokenizer is not configurable." //待分析文本
}
上述文本的分析结果如下:
{
"tokens" : [ //分析器将文本切分后的分析结果
{
"token" : "the", //将文本切分后的第一个词语
"start_offset" : 0, //该词在文本中的起始偏移位置
"end_offset" : 3, //该词在文本中的结束偏移位置
"type" : "<ALPHANUM>", //词性
"position" : 0 //该词语在原文本中是第0个出现的词语
},
{
"token" : "letter",
"start_offset" : 4,
"end_offset" : 10,
"type" : "<ALPHANUM>",
"position" : 1
},
{
"token" : "tokenizer",
"start_offset" : 11,
"end_offset" : 20,
"type" : "<ALPHANUM>",
"position" : 2
},
…
]
}
根据以上结果可以看到,standard分析器对文本进行分析时,按照空格把上面的句子进行了分词。分析API返回信息的参数说明如下:
- ·token:文本被切分为词语后的某个词语;
- ·start_offset:该词在文本中的起始偏移位置;
- ·end_offset:该词在文本中的结束偏移位置;
- ·type:词性,各个分词器的值不一样;
- ·position:分词位置,指明该词语在原文本中是第几个出现的。
start_offset和end_offset组合起来就是该词在原文本中占据的起始位置和结束位置。
除了指定分析器进行请求分析外,还可以指定某个索引的字段,使用这个字段对应的分析器对目标文本进行分析。
POST /hotel/_analyze
{ //使用酒店索引的title字段对应的分析器分析文本
"field": "title",
"text": "金都嘉怡假日酒店"
}
还可以在API中自定义分析器对文本进行分析
POST /_analyze
{
"tokenizer": "standard", //使用standard分词器
"filter":["lowercase"], //使用Lower Case分词过滤器
"text": "JinDu JiaYi Holiday Hotel" //待分析文本
}
内置分析器
ES已经内置了一些分析器供用户使用,在默认情况下,一个索引的字段类型为text时,该字段在索引建立时和查询时的分析器是standard。standard分析器是由standard分词器、Lower Case分词过滤器和Stop Token分词过滤器构成的。注意,standard分析器没有字符过滤器。
除了standard分析器之外,ES还提供了simple分析器、language分析器、whitespace分析器及pattern分析器等,这些分析器的功能如表所示。
表 ES内置的分析器
索引时使用分析器
文本字段在索引时需要使用分析器进行分析,ES默认使用的是standard分析器。如果需要指定分析器,一种方式是在索引的settings参数中设置当前索引的所有文本字段的分析器,另一种方式是在索引的mappings参数中设置当前字段的分析器。
以下示例在settings参数中指定在酒店索引的所有文本字段中使用simple分析器进行索引构建。
PUT /hotel
{
"settings": {
"analysis": {
"analyzer": { //指定所有text字段索引时使用simple分析器
"default": {
"type": "simple"
}
}
}
},
"mappings": {
"properties": {
…
}
}
}
以下示例在mappings参数中指定在酒店索引的title字段中使用whitespace分析器进行索引构建。
PUT /hotel
{
"mappings": {
"properties": {
"title": {
"type": "text",
//指定索引中的title字段索引时使用whitespace分析器
"analyzer": "whitespace"
},
…
}
}
}
搜索时使用分析器
为了搜索时更加协调,在默认情况下,ES对文本进行搜索时使用的分析器和索引时使用的分析器保持一致。当然,用户也可以在mappings参数中指定字段在搜索时使用的分析器。如下示例展示了这种用法:
PUT /hotel
{
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "whitespace", //索引时使用whitespace分析器
"search_analyzer": "whitespace" //搜索时使用whitespace分析器
},
…
}
}
}
注意,这里指定的搜索分析器和索引时的分析器是一致的,但是在大多数情况下是没有必要指定的,因为在默认情况下二者就是一致的。如果指定的搜索分析器和索引时的分析器不一致,则ES在搜索时可能出现有不符合预期的匹配情况,因此该设置在使用时需要慎重选择。
自定义分析器
当系统内置的分析器不满足需求时,用户可以使用自定义分析器。
首先,需要在索引创建的DSL中定义分析器comma_analyzer,该分析器中只有一个分词组件,该分词组件使用逗号进行词语切分;然后在mappings中使用analyzer参数指定字段sup_env的分析器为定义好的comma_analyzer分析器。具体的DSL如下:
PUT /hotel
{
"settings": {
"analysis": {
"analyzer": {
"comma_analyzer": { //自定义分析器
"tokenizer": "comma_tokenizer" //使用comma_tokenizer分词器
}
},
"tokenizer": { //定义分词器
"comma_tokenizer": {
"type": "pattern",
"pattern": "," //指定切分时使用的分隔符
}
}
}
},
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "whitespace", //设定title字段索引时使用whitespace分析器
//设定title字段搜索时使用whitespace分析器
"search_analyzer": "whitespace"
},
"sup_env": {
"type": "text",
//设置sup_env字段使用comma_analyzer分析器
"analyzer": "comma_analyzer"
},
…
}
}
}
下面向酒店索引中插入几条数据:
POST /_bulk
{"index":{"_index":"hotel","_id":"001"}}
{"title": "金都嘉怡假日酒店","city": "北京","price": 337.00,"sup_env":"APP,H5"}
{"index":{"_index":"hotel","_id":"002"}}
{"title": "金都欣欣酒店","city": "天津","price": 200.00,"sup_env":"H5,WX"}
{"index":{"_index":"hotel","_id":"003"}}
{"title": "金都酒店","city": "北京","price": 500.00,"sup_env":"WX"}
当前用户的客户端为H5或App,当搜索“金都”关键词时应该构建的DSL如下:
GET /hotel/_search
{
"query": {
"bool": {
"must": [
{ //match查询,使用whitespace分析器
"match": {
"title": "金都"
}
},
{ //match查询,使用comma_analyzer分析器
"match": {
"sup_env": "H5,APP"
}
}
]
}
}
}
使用自定义的分词器可以将以逗号分隔的字段进行分词后建立索引,从而在搜索时也使用逗号分隔符进行匹配搜索。