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

使用自定义的分词器可以将以逗号分隔的字段进行分词后建立索引,从而在搜索时也使用逗号分隔符进行匹配搜索。

原文地址:https://www.cnblogs.com/ooo0/p/15672838.html