elasticsearch篇之正/倒排索引与分词

版权声明:文章内容来自于网络和博主自身学习体会,转载请注明出处,欢迎留言大家一起讨论学习~~ https://blog.csdn.net/sinat_35930259/article/details/80282710

正/倒排索引


类似于书的目录,目录能够方便的定位哪一章节或哪一小节的页码,但是无法定位某一关键字的位置。有一些书的最后有索引页,它的功能就是帮助定位某些关键字出现的位置。

目录页对应正排索引
索引页对应倒排索引

正排索引和倒排索引


对于搜索引擎来讲:

正排索引是文档 Id 到文档内容、单词的关联关系。也就是说可以通过 Id获取到文档的内容。

倒排索引是单词到文档 Id 的关联关系。也就是说了一通过单词搜索到文档 Id。

倒排索引的查询流程是:首先根据关键字搜索到对应的文档 Id,然后根据正排索引查询文档 Id 的完整内容,最后返回给用户想要的结果。

倒排索引的组成

倒排索引是搜索引擎的核心,主要包含两个部分:

  • 单词词典(Trem Dictionary):记录的是所有的文档分词后的结果
  • 倒排列表(Posting List):记录了单词对应文档的集合,由倒排索引项(Posting)组成。

单词字典的实现一般采用B+Tree的方式,来保证高效

倒排索引项(Posting)主要包含如下的信息:
1、文档ID,用于获取原始文档的信息
2、单词频率(TF,Term Frequency),记录该单词在该文档中出现的次数,用于后续相关性算分。
3、位置(Position),记录单词在文档中的分词位置(多个),用于做词语搜索。
4、偏移(Offset),记录单词在文档的开始和结束位置,用于高亮显示。

es存储的是一个json的内容,其中包含很多字段,每个字段都会有自己的倒排索引。

分词


分词和分词器

分词是指将文本转换成一系列的单词的过程,也可以叫做文本分析,在es中称为Analysis。

例如文本“elasticsearch是最流行的搜索引擎”,经过分词后变成“elasticsearch”,“流行”,“搜索引擎”

分词器(Analyzer)是es中专门用于分词的组件,它的组成如下:

组成 功能
Character Filter 针对原始文本进行处理,比如去除html标记符。
Tokenuzer 将原始文本按照一定规则切分为单词。
Token Filters 针对tokenizer处理的单词进行再加工,比如转为小写、删除或新增等。

分词器组成的调用是有顺序的:
这里写图片描述

Analyze API

es提供了一个测试分词的api接口,方便验证分词效果,endpoint是_analyze

这个api具有以下特点:

  • 可以直接指定analyzer进行测试
  • 可以直接指定索引中的字段进行测试
  • 可以自定义分词器进行测试

直接指定analyzer进行测试

请求举例:

POST _analyze
{
    "analyzer": "standard",
    "text": "hello world"
}

analyzer表示指定的分词器,这里使用es自带的分词器standard,text用来指定待分词的文本

这里写图片描述

从结果中可以看到,分词器将文本分成了hello 和 world两个单词

指定索引中的字段进行测试

应用场景:当创建好索引后发现某一字段的查询和预期不一样,就可以对这个字段进行分词测试。

请求举例:

POST text_index/_analyze
{
  "field": "username",
  "text": "hello world"
}

这里写图片描述

当没有指定分词器的时候默认使用standard

自定义分词器进行测试

请求举例l:

POST _analyze
{
  "tokenizer": "standard",
  "filter": [ "lowercase" ],
  "text": "Hello World"
}

根据分词的流程,首先通过tokenizer指定的分词方法standard进行分词,然后会经过filter将大写转化为小写。

这里写图片描述

预定义的分词器

es自带有以下的预定义分词器,可以直接使用:

standard

默认分词器,具有按词切分、支持多语言、小写处理的特点。
这里写图片描述

可以看到,standerd将stop word默认关闭了,也就是这些词还是会在分词后保留。stop word就是例如and、the、or这种词,可以通过配置将它打开。其实搜索引擎应该将这些stop word过滤掉,这样可以减少压力的同时保证搜索的准确性。

simple

具有特性是:按照非字母切分、小写处理。
这里写图片描述

可以看到它将非字母的字符切掉了,例如横线、标点、数字都被干掉了。

whitespace

具有的特性是:按照空格切分。
这里写图片描述

可以看到它按照空格切分,并且没有进行小写转化。

stop

具有的特性是:将stop word切掉
这里写图片描述

keyword

具有的特性是:不分词,直接将输入作为一个单词输出
这里写图片描述

pattern

具有的特性是:通过正则表达式自定义分隔符,默认是\W+,即非字词的符号作为分隔符,小写转化
这里写图片描述

language

具有的特性是:提供了30+常见语言的分词器。

中文分词

中文分词是指讲一个汉字序列切分成一个一个独立的词。在英文中,单词间以空格作为自然分界符,韩语中词没有一个形式上的分界符。

而且根据上下文的不同,分析结果迥异。

中文分词常见的分词器

  • IK
    可以实现中英文单词的分词,支持ik_smart、ik_maxword等模式;可以自定义词库,支持热更新分词词典。

  • jieba
    python中最流行的分词系统,支持分词和词性标注;支持繁体分词、自定义词典、并行分词。

基于自然语言的分词系统:
这种分词系统可以通过创建一个模型,然后该模型经过训练可以通过根据上下文进行合理的分词,常见的有:

  • Hanlp:有一系列模型预算法组成的Java工具包,目标是普及自然语言处理在生产环境中的应用
  • THULAC:清华大学推出,具有中文分词和词性标注的功能。

自定义分词

当自带的分词无法满足需求的时候,就需要自定义分词。

自定义分词就是通过Character Filters、Tokenizer和Token Filter实现。

Character Filters

在Tokenizer之前对原始文本进行处理,比如增加、删除或替换的字符等。

es自带的如下:
- html_strip:去除html标签和转换html字体
- Mapping:进行字符串替换
- Pattern Replace:进行正则匹配替换

由于它是第一步,所以它的结果会影响Tokenizer和Token Filter解析的position和offset的结果

示例:

POST _analyze
{
    "tokenizer": "keyword",
    "char_filter": [ "html_strip" ],
    "text": "<p>I am good</p>"
}

这里为了看出Character Filters的结果所以制定分词器为keyword,这样就不会分词了。

这里写图片描述

Tokenizer

作用是将原始文本按照一定的规则切分称为单词。

es自带的Tokenizer如下:

  • standard:按照单词切割
  • letter:按照非字符切割
  • whitespace:按照空格切割
  • UAX URL Eamil 按照standard切割,但不会分割邮箱和url
  • NGram和Edge NGram:连词分割(例如搜索时根据输入提示相关内容)
  • path_hierarchy:按照文件路径进行分割

示例:
1、按照路径分割

POST _analyze
{
  "tokenizer": "path_hierarchy",
  "text": "/path/to/file"
}

这里写图片描述

Token Filter

Token Filter 作用是对于 Tokenizer 输出的单词(term)进行增加、删除、修改等操作

es自带的 Token Filter 如下:

  • lowercase:将所有term转化为小写
  • stop:删除stop word
  • NGram和Edge NGram:连词分割
  • Synonym:添加近义词的term

filter可以有多个并按照指定的顺序执行

示例:

POST _analyze
{
  "text": "a Hello World",
  "tokenizer": "standard",
  "filter": [
    "stop",
    "lowercase",
    {
      "type": "ngram",
      "min_gram": 4,
      "max_gram": 4
    }
    ]
}

这里使用了 standard 的 tokenizer 对文本进行分割,然后 filter 指定使用 stop,lowercase,ngram。这里是指定每4位切割一次。min_gram 和 max_gram分别指定最小和最大的切割位数。

这里写图片描述

这个作用是:比如当我输入hell的时候九合一将hello整个单词给出,当然还可以切分的更小。

自定义分词的API

自定义分词需要在索引的配置中设定。

假设现在自定义一个分词器,character filter使用html strip,tokenizer使用standard,token filter使用lowarcase和ascii folding,那么它的定义如下:

PUT test_index
{
  "settings": {
    "analysis": {
      "analyzer": {
        "my_analyzer":{
          "type": "custom",
          "tokenizer": "standard",
          "char_filter": "html_strip",
          "filter": [
            "lowercase",
            "asciifolding"
            ]
        }
      }
    }
  }
}

测试自定义分词器的效果:

POST test_index/_analyze
{
  "analyzer": "my_analyzer",
  "text": "It is <b>a text</b>?!"
}

这里写图片描述

下面是一个比较负载的自定义分词器:
character filter使用自定义的mapping:custom mapping, tokenizer使用custom pattern,token filter使用lowercase和custom stop。

PUT test_index2
{
  "settings": {
    "analysis": {
      "analyzer": {
        "my_az": {
          "type": "custom",
          "char_filter": "emoticons",
          "tokenizer": "punctuation",
          "filter": [
            "lowercase",
            "english_stop"
            ]
        }
      },
      "tokenizer": {
        "punctuation": {
          "type": "pattern",
          "pattern": "[.,!?]"
        }
      },
      "char_filter": {
        "emoticons": {
          "type": "mapping",
          "mappings": [
            ":) => _happy_",
            ":( => _sad_"
            ]
        }
      },
      "filter": {
        "english_stop": {
          "type": "stop",
          "stopwords": "_english_"
        }
      }
    }
  }
}

测试自定义分词器:

POST test_index2/_analyze
{
  "analyzer": "my_az",
  "text": " This's a  :) face, how about you? Amy"
}

这里写图片描述

这样就达到了自定义分词效果的目的。

分词使用说明

分词一般会在以下的情况下使用:

  1. 创建或更新文档的时候,会对相应的文档进行分词处理。
  2. 查询时,会对查询语句进行分词

明确字段是否需要分词,不需要分词的字段就将 type 设置为 keyword,可以节省空间和提高写性能。

善用 _analyze API 查看文档具体分词结果

展开阅读全文

没有更多推荐了,返回首页