ElasticSearch 分词器、自定义分词器以及倒排索引

倒排索引

索引(正排索引)

索引或者叫做正排索引的概念,想必都不陌生,有个非常经典的例子,就是书本的目录,索引就类似目录,你可以根据目录的页码很方便的找到你所要找到的内容地址。
在这里插入图片描述
如上这张图片,我们可以很方便的根据目录(索引)来找到这一章节的位置,这就是正排索引,关系型数据库用的就是正排索引,mysql 的 b数构建主键索引树时,其实就是主键ID指向地址。

倒排索引

倒排索引的出现,是为了解决海量数据搜索的问题出现的。一个搜索引擎,如果有几十亿的数据,你想从这几十亿的数据中捞出你想要的数据,如果按照索引的概念来搜索,是个非常巨大的工作量,首先你需要一次次的翻找目录找到页码才可以定位到内容地址,但是如果有一种索引,可以直接根据某个单词找到页码在找到内容地址,这样无疑会省事很多。
倒排索引就是一种这样的索引结构。(其实就是正排索引倒着来,正排索引是由页码到内容,倒排索引是由内容单词到页码再到内容地址。)
在这里插入图片描述

索引 与 倒排索引 的例子

这里举了一个例子,有三个文档,分别是 Mastering ElasticSearch 、 ElasticSearch Server、ElasticSearch Essentials,正排索引的话,其实就是左边的结构,文档id 直接映射到文档内容上,但是如果是倒排索引的话,则会先将这三个文档进行分词,分成 ElasticSearch 、Mastering 、Server、Essentials 这四个词项(Term),然后还会对这四个词项的出现次数做一个统计,并且还会为每一个词项出现在的文档id以及出现的位置做一个统计 (DocumentId:Position),比如 ElasticSearch 出现在了第一个文档的第二个位置,那么对应的就是 1:1 文档ID:出现的位置(从0开始)。
在这里插入图片描述
统计词项的时候,会穷举统计词项出现在所有文档的位置,这样搜索的时候,就可以直接通过 ElasticSearch 找到文档id并且还能找到出现位置高亮显示。

ElasticSearch 倒排索引的组成

  • 单词词典(Iterm),记录所有文档的单词,记录单词到倒排列表的关系
    单词词典一般通过 b+ 树实现
  • 倒排列表(Posting List) 记录了单词对应文档id的集合,集合中的对象称为倒排索引项,一个索引项包含以下几个内容
    - 文档Id (Doc ID)
    - 词频 (TF) (单词出现的次数, ElastticSearch 相关性得分就是根据这个算的)
    - 位置(Position),单词在文档中出现的位置,用于语句搜索
    - 偏移量 (Offset),记录单词的开始结束位置,用于高亮显示
    在这里插入图片描述
    以上就是 ElasticSearch 的一个简单的文档倒排索引,这个例子统计的是 ElasticSearch 词项,可以看到ElasticSearch 这个词项的倒排列表有文档ID、TF、Position、Offset等信息。
    比如:ElasticSearch 这个单词在第一个文档中出现了一次,位置是第二个单词,起始位置是从第10个字母开始到23个字母结束。

分词器

Analysis 分析 与 Analyzer 分词器

  • ElasticSearch中的 Analysis 分析这个概念更像是一个过程,是指把全文本转化成一系列单词的过程,也叫分词。
  • Analyzer 分词器是一种功能工具,分词就是通过分词器来实现的,分词器就是将具体的文本分解成一个个单词,比如 ElasticSearch Engilist,会被分词器分解成 ElasticSearch 与 English 两个单词
  • ElasticSearch 在查询的时候,也是需要进行分词器将查询文本进行分词的。

Analyzer 分词器的组成

  • Character Filters, 主要是对原始文本做一些处理过滤,比如将 html 标签给去除掉不参与分词,例如:]< text >ElasticSearch Server</ text >,经过Character Filters会变成 ElasticSearch Server
  • Tokenizer 按照一定的规则切分单词,比如按照空格去切分,ElasticSearch Server 会被切分成 ElasticSearch 与 Server 两个单词
  • Token Filter 对切分出来的单词进行进一步处理(小写、过滤掉停用词、同义词处理、复数单词处理),比如将将大写变成小写,ElasticSearch 与 Server 经过这一步后会变成 elasticsearch 与 server

测试分词效果 _analyzer API

_analyzer API 是ElasticSearch 开放出来的一款可以针对指定的分词器测试分词效果

  • _analyzer API 可以直接指定 Analyzer 进行测试,不需要指定索引
  • _analyzer API 可以指定索引的字段进行分词测试
  • _analyzer API 还可以自定义分词器进行测试
直接指定 Analyzer 进行测试

请求格式:GET + _analyze + 请求体(指定分词器 + 要分词的文本)

#standard
GET _analyze
{
  "analyzer": "standard", # 分词器
  "text": "2 running Quick brown-foxes leap over lazy dogs in the summer evening." # 要分词的文本
}
指定索引字段进行分词

请求格式:POST + 索引+ _analyze + 请求体(指定字段 + 要分词的文本)

POST movies/_analyze 
{
  "field": "genre",
  "text": "Master ElasticSearch"
}
自定义分词器测试
POST _analyze
{
  "tokenizer": "standard", 
  "filter": ["lowercase"],
  "text": "Master ElasticSearch"
}

内置分词器

ElasticSearch 内置的几个分词器
  • Standard Analyzer - 默认分词器,按词切分,小写处理

  • Simple Analyzer - 按照非字母切分(符号被过滤), 小写处理

  • Stop Analyzer - 小写处理,停用词过滤(the,a,is)

  • Whitespace Analyzer - 按照空格切分,不转小写

  • Keyword Analyzer - 不分词,直接将输入当作输出

  • Patter Analyzer - 正则表达式,默认\W+(非字符分割)

  • Language - 提供了30多种常见语言的分词器

  • Customer Analyzer 自定义分词器

Standard Analyzer
  • 默认分词器
  • 按词切分
  • 小写处理
#standard
GET _analyze
{
  "analyzer": "standard",
  "text": "2 running Quick brown-foxes leap over lazy dogs in the summer evening."
}

在这里插入图片描述
可以看到 2 running Quick 被按照空格分成了三个词,并且 Quick 小写,至于每个词项的内容,还有我们前边分析过的 偏移量以及位置

Simple Analyzer
  • 按照单词与非字母切分,非字母的都去掉
  • 小写处理
#simpe
GET _analyze
{
  "analyzer": "simple",
  "text": "2 running Quick brown-foxes leap over lazy dogs in the summer evening."
}

在这里插入图片描述

我们可以明显看到,2 这个字符被去掉了,并且 Quick 被小写了,最关键的 brown-foxes 被切分成了两个词项,因为 - 不是字母

Stop Analyzer
  • 按照单词与非字母切分,非字母的都去掉
  • 小写处理
  • 会吧 is the 等修饰性词语去掉
# stop
GET _analyze
{
  "analyzer": "stop",
  "text": "2 running Quick brown-foxes leap over lazy dogs in the summer evening."
}

在这里插入图片描述
stop 相比 Simple Analyzer ,可以看到除了非字母过滤外,又多了 修饰词过滤, in the 两个修饰词都没有出现在词项中。

Whitespace Analyze
  • 按照空格切分
# whitespace
GET _analyze
{
  "analyzer": "whitespace",
  "text": "2 running Quick brown-foxes leap over lazy dogs in the summer evening."
}

在这里插入图片描述
可以看到并没有进行数字以及大小写的过滤,单纯只是根据空格切分了一下词项

Patter Analyzer
  • 正则表达式
  • 默认\W+(非字符分割)

Patter 的结果还是与 Simple Analyzer 相似的,因为这里是默认的选择。
Patter Analyzer 的一些设置参数,我们可以通过自定义参数来设置 Patter 的分词功能,因为他支持正则表达式。

项目Value
pattern一个Java的正则表达式,则默认为\W+。
flagsJava正则表达式标志。标志应用管道分隔,例如"CASE_INSENSITIVE
lowercase是否将分词转成小写。默认为true。
stopwords预定义的停用词列表,例如_english_或包含停用词列表的数组。默认为_none_。
stopwords_path包含停用词的文件的路径。

我们先自定义一个分词器 my_email_analyzer,并且设置分词器的类型为 pattern 并且 支持小写

#自定义一个分词器,使用 pattern并给自定义正则表达式,lowercase 设为 true
PUT my-index-000001
{
  "settings": {
    "analysis": {
      "analyzer": {
        "my_email_analyzer": {
          "type":      "pattern",
          "pattern":   "\\W|_", 
          "lowercase": true
        }
      }
    }
  }
}

#查看分词效果
POST my-index-000001/_analyze
{
  "analyzer": "my_email_analyzer",
  "text": "John_Smith@foo-bar.com"
}

结果:[ john, smith, foo, bar, com ],可以看到 将分词根据非字母进行拆分并且将词语进行了小写

Language

ElasticSearch 为不同国家的语言都做了一个分词器,比如英语用的是 english,中文分词一般推荐使用icu_analyzer 这个分词器。

支持语言:arabic, armenian, basque, bengali, bulgarian, catalan, czech, dutch, english, finnish, french, galician, german, hindi, hungarian, indonesian, irish, italian, latvian, lithuanian, norwegian, portuguese, romanian, russian, sorani, spanish, swedish, turkish.

  • IK 中文分词器,支持自定义词典
  • icu_analyze 支持大多数的中文分词
  • THULAC 清华大学自然语言处理的一款中文分词器

中文分词的难点,是在于中文的博大精深,每次子在不同的场景下,所表示的语义是不同的,尤其是成语,中文分词要讲一句话分解成为一个个的词,而不是一个个的字,所以一款好的中文分词是比较难搞的。
在这里插入图片描述
可以看到,icu_analyze 会将 确实 这种词语分成一个词而不是一个个的字。

自定义分词器

当ElasticSearch 提供的一些分词器不满足我们的特定场景时,可以自定义一个分词器。之前介绍过一个分词器的三个核心,自定义分词器其实就是对这三个部分分别设置组合功能。

Character Filters

Character Filters会过滤掉一些词,ElasticSearch 提供了一些自带的过滤组件

  • html_strip - 去除 html 标签
  • mapping- 字符串替换
  • pattern_replace - 正则表达式替换
#使用 html_strip 过滤器
POST _analyze
{
  "tokenizer":"keyword",
  "char_filter":["html_strip"],
  "text": "<b>hello world</b>"
}

会得到 hello world 结果,将 < b > 标签替换掉了

#char filter 替换表情符号
POST _analyze
{
  "tokenizer": "standard",
  "char_filter": [
      {
        "type" : "mapping",
        "mappings" : [ ":) => happy", ":( => sad"]
      }
    ],
    "text": ["I am felling :)", "Feeling :( today"]
}

结果:happy sad,符号已经被替换掉了。
mappings 的用法是,指定type 为 mapping,并且在 mappings 中配置你要转义的词 比如要将 : ) 笑脸符号转化成 happy单词 ,那么可以在mappings 中写 “: ) => happy”, “: ( => sad”,ElasticSearch 就会知道你要干什么。

Tokenizer

Tokenizer 是按照分词规则将一个文本切分成不同的词项,ElastciSearch 内置了一些 Tokenizer

  • whitespace - 以空格的方式分词
  • standard - 按照字母分词
  • path_hierarchy - 按照文件的输入路径分词
  • keyword - 不分词
  • pattern - 按照正则表达式分词
  • uax_url_email - 按照邮箱的规则分词
# 按照路径去分词
POST _analyze
{
  "tokenizer":"path_hierarchy",
  "text":"/user/ymruan/a/b/c/d/e"
}

结果是 “/user” /user/ymruan“ “/user/ymruan/a” /user/ymruan/a/b ,可以看到 path_hierarchy 会将目录一级一级的切分出来。

Token Filter

是对 Tokenizer 处理出来的单词进行进一步的加工,ElasticSearch 也提供了几个默认的 Token Filter

  • lowercase - 大小写
  • stop - 停用词过滤
  • synonym - 同义词转换
    配置 tokenfileter 是在分词器的 “filter” 属性中配置
#whitespace与stop
GET _analyze
{
  "tokenizer": "whitespace",
  "filter": ["stop","snowball"],
  "text": ["The rain in Spain falls mainly on the plain."]
}

结果: rain Spain fall main
可以看到 in 等停用词已经被过滤掉了并且 falls mainly 的复词也被替换成了简单的同义词。

自定义分词器API

分词器其实是设置在 索引的 settings 部分的,可以在创建索引的时候自定义一个分词器。

PUT my_index
{
  "settings":{
    "analysis":{
      "analyzer":{
        "my_tokenizer": {
          "type":"englist",
          "char_filter": ["html_strip"],
          "tokenizer":"keyword",
          "filter": ["lowercase","stop","snowball"]
        }
      }
    }
  }
}

这样我们在 analysis 下的 analyzer 定义了一个自己的分词器名字是 my_tokenizer,使用了 char_filter、tokenizer、filter等功能。
格式最好如果这个一样。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值