Elasticsearch分析器使用

分析器主要是对输入的文本类内容进行分析(通常是分词),将分析结果以 term 的形式进行存储。

分析器一般用在下面两个场景中:

  • 创建或更新文档时(合称索引时),对相应的文本字段进行分词处理;·

  • 查询文本字段时,对查询语句进行分词

ES中的分析器有很多种,但是所有分析器的结构都遵循三段式原则:Character Filters(字符过滤器)、Tokenizer(分词器)、Token Filters(分词过滤器)。其中,字符过滤器可以0个或多个,分词器必须只有一个,词语过滤器可以有0个或多个。从整体上来讲,三个部分的数据流方向为字符过滤器->分词器->分词过滤器。

分析器工作流程:文本先以字符流的形式流经字符过滤器,字符过滤器处理完字符后将结果传递给分词器,分词器对文本进行分词处理后将结果又传递给分词过滤器。

一、分析器构成

1.1、字符过滤器

字符过滤器就是对原始文本做一些粗加工的工作,为后续的分词做准备。例如,原始数据中可能包含来自爬虫的结果,字符过滤器可以去除文本中的HTML标签,也可以将原始文本中的一些特殊字符进行转义,如把“&”转换为and。ES内置的字符过滤器如下:

名称 功能
映射关系字符过滤器 根据配置的映射关系替换字符
HTML擦除过滤器 去掉HTML元素
正则表达式替换过滤器 用正则表达式处理字符串

1.2、分词器

分词器按照规则来切分词语。简单的分词器通常是根据空格及标点符号进行切分,但中文分词字符之间往往没有空格,因此采用英文的切分规则是不可取的。分词器对文本进行切分后,需要保留词语与原始文本之间的对应关系,因此分词器还负责记录每个token的位置,以及开始和结束的字符偏移量。ES内置分词器如下:

名称 功能
标准分词器 对英文分词时,基于语法分词; 对于中文分词时,切分成单字
字母分词器 使用非字母的字符作为分词标记
小写分词器 功能上等同于字母分词器,并且把所有分词结果转换为小写形式
空格分词器 使用空格作为分词标记

1.3、分词过滤器

分词过滤器接收分词器的处理结果,并可以将切分好的词语进行加工和修改,进而对分词结果进行规范化、统一化和优化处理。例如,它可以将文本中的字母全部转换为小写形式,还可以删除停用词(如的、这、那等),还可以为某个分词增加同义词。ES内置分词过滤器如下:

名称 功能
Lower Case过滤器 将所有字母转换为小写形式
Stop Token过滤器 将停用词从分词结果中移除
同义词分词过滤器 为分词结果添加同义词

二、分析器使用

ES提供了分析器的调用API,使用户可以方便地对比不同分析器的分析结果。另外,ES提供了一些开箱即用的内置分析器,这些分析器其实就是字符过滤器、分词器和分词过滤器的组合体,可以在索引建立时和搜索时指定使用这些分析器

2.1、测试分析API

使用ES提供的分析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
  },
  {
     "token": "letter",
     "start_offset": 4,
     "end_offset": 10,
     "type": "<ALPHANUM>",
     "position": 1
  },
  {
     "token": "tokenizer",
     "start_offset": 11,
     "end_offset": 20,
     "type": "<ALPHANUM>",
     "position": 2
  },
  {
     "token": "is",
     "start_offset": 21,
     "end_offset": 23,
     "type": "<ALPHANUM>",
     "position": 3
  },
  {
     "token": "not",
     "start_offset": 24,
     "end_offset": 27,
     "type": "<ALPHANUM>",
     "position": 4
  },
  {
     "token": "configurable",
     "start_offset": 28,
     "end_offset": 40,
     "type": "<ALPHANUM>",
     "position": 5
  }
]
}

standard分析器对文本是按照空格进行分词的,分析API返回结果的参数说明如下:

  • token:文本被切分词语后的某个词语

  • start_offset:该词在文本中的起始偏移位置

  • end_offset:该词在文本中的结束偏移位置

  • type:词性,各个分词器的值不一样

  • position:分词位置,指明该词语在原文本中是第几个出现的

start_offset和end_offset组合起来就是该词在原文本中占据的起始位置和结束位置。下面使用standard分析器分析一段中文文本:

POST _analyze
{
 "analyzer":"standard",
 "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
  }
]
}

从结果中可以看出ES内置的standard不适合分析中文。用户还可以指定某个索引的字段,使用这个字段对应的分析器对目标文本进行分析。下面使用酒店索引的title字段对应的分析器分析文本:

POST /hotel/_analyze
{
 "field":"title",
 "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
  }
]
}

另外,用户还可以在API中自定义分析器对文本进行分析。在下面的示例中自定义了一个分析器,该分析器的分析器使用standard,分词过滤器使用Lower Case,其将分词后的结果转换为小写形式:

GET _analyze
{
 "tokenizer":"standard",
//使用standard分词器
 "filter":["lowercase"],
//使用lower case分词过滤器
 "text":"JinDu JiaYi Holiday Hotel"
//待分析文本
}

返回分析结果如下:

{
 "tokens": [
  {
     "token": "jindu",
     "start_offset": 0,
     "end_offset": 5,
     "type": "<ALPHANUM>",
     "position": 0
  },
  {
     "token": "jiayi",
     "start_offset": 6,
     "end_offset": 11,
     "type": "<ALPHANUM>",
     "position": 1
  },
  {
     "token": "holiday",
     "start_offset": 12,
     "end_offset": 19,
     "type": "<ALPHANUM>",
     "position": 2
  },
  {
     "token": "hotel",
     "start_offset": 20,
     "end_offset": 25,
     "type": "<ALPHANUM>",
     "position": 3
  }
]
}

2.2、内置分析器

ES除了standard分析器,还提供了simple分析器、language分析器、whitespace分析器及pattern分析器等。ES内置的分析器:

名称 功能
simple分析器 按非字母字符进行词语拆分,并将所有词语转换为小写
language分析器 语言分析器
whitespace分析器 按照空白字符拆分词语
pattern分析器 使用正则表达式将文本拆分为词语

2.3、索引时使用分析器

文本字段在索引时需要使用分析器进行分析,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"  
    },
    …
  }
}
}

2.4、搜索时使用分析器

为了搜索时更加协调,在默认情况下,ES对文本进行搜索时使用的分析器和索引时使用的分析器保持一致。当然,用户也可以在mappings参数中指定字段在搜索时使用的分析器。如下示例展示了这种用法:

PUT /hotel 
{
 "mappings": {
   "properties": {
     "title": {
       "type": "text",
       "analyzer": "whitespace",           //索引时使用whitespace分析器
       "search_analyzer": "whitespace"     //搜索时使用whitespace分析器
    },
    …
  }
}
}  

注意,这里指定的搜索分析器和索引时的分析器是一致的,但是在大多数情况下是没有必要指定的,因为在默认情况下二者就是一致的。如果指定的搜索分析器和索引时的分析器不一致,则ES在搜索时可能出现有不符合预期的匹配情况,因此该设置在使用时需要慎重选择。

2.5、自定义分析器

用户可以使用自定义分析器,在有些场景中,某个文本字段不是自然语言而是在某种规则下的编码。例如,在酒店索引中有个sup_env字段,其值为“APP,H5,WX”,表示当前酒店可以在App、Web端和微信小程序端上显示。假设当前搜索用户使用的是H5或App客户端,则需要过滤掉不支持在这两个客户端上显示的酒店。首先,需要在索引创建的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"
        }
      }
    ]
  }
}
}  

运行上面的DSL后,ES返回的结果如下:

{ 

 "hits" : {
  …
   "hits" : [                   //命中的文档集合
    {
       "_index" : "hotel",
       "_type" : "_doc",
       "_id" : "001",
       "_score" : 1.5761212,
       "_source" : {
         "title" : "金都嘉怡假日酒店",
        …
         "sup_env" : "App,H5"   //切分成App和H5,两部分都与查询词匹配
      }
    },
    {
       "_index" : "hotel",
       "_type" : "_doc",
       "_id" : "002",
       "_score" : 0.7015199,
       "_source" : {
         "title" : "金都欣欣酒店",
          …
         "sup_env" : "H5,WX" //切分成H5和WX,其中H5与查询词匹配
      }
    }
  ]
}
}

由上面的结果可以看到,索引中有3个文档,只有文档001和文档002对应的酒店标题中包含“金都”且可以在H5或App客户端显示。使用自定义的分词器可以将以逗号分隔的字段进行分词后建立索引,从而在搜索时也使用逗号分隔符进行匹配搜索。

原文始发于微信公众号(面试技术):Elasticsearch分析器使用

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/186865.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!