倒排索引与分词

倒排索引

正排索引:文档ID到文档内容、单词的关联关系
倒排索引:单词到文档ID的关联关系
这里写图片描述
倒排索引查询流程:(以查询包含“搜索引擎”的文档为例)

  • 通过倒排索引获得“搜索引擎”对应的文档ID有1和3
  • 通过正排索引查询1和3的完整内容
  • 返回用户最终结果

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

单词词典(Term Dictionary)(一般由B+Tree实现)

  • 记录所有文档的单词,一般都比较大
  • 记录单词到倒排列表的关联信息

倒排列表(Posting List): 记录单词对应的文档集合,由倒排索引项(Posting)组成

倒排索引项(Posting)主要包含如下信息:

  • 文档ID,用于获取原始信息
  • 单词频率(TF,Term Frequency),记录该单词在该文档中的出现次数,用于后续相关性算分
  • 位置(Position),记录单词在文档中的分词位置(多个),用于做词语搜索(Phrase Query)
  • 偏移(Offset),记录单词在文档的开始和结束位置,用于做高亮显示
    这里写图片描述

分词

官方文档

分词是指将文本转换成一系列单词(term or token)的过程,也可以叫做文本分析,在es里面成为Analysis.

分词器是es中专门处理分词的组件,英文为Analyzer,它的组件如下:

  • Character Filters: 针对原始文本进行处理,比如去除html特殊标记符
  • Tokenizer: 将原始文本按照一定规则切分为单词
  • Token Filters: 针对tokenizer处理的单词进行在加工,比如转小写、删除、或新增等处理

Analyze API

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

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

直接指定analyzer进行测试:

POST _analyze
{
  "analyzer": "standard",   #analyzer:分词器
  "text": "hello world"     #text:测试文本
}

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

POST test_index/_analyze
{
  "field": "username",   #field:测试字段
  "text": "hello world"
}

自定义分词器进行测试:

POST _analyze
{
  "tokenizer": "standard",
  "filter": ["lowercase"],  #自定义analyzer
  "text": "Hello World"     
}

自带分词器

Standard: 按词切分,支持多语言;小写处理
Simple: 按照非字母切分;小写处理
Whitespace: 按照空格切分
Stop: Stop World指语气助词等修饰性的词语,比如the、an、的、这等等,相比simple多了stop word 处理
Keyword: 不分词,直接将输入作为一个单词输出
pattern: 通过正则表达式自定义分隔符;默认是\W+,即非字符的符号作为分隔符
Language: 提供了30+常见语言的分词器

测试:

POST _analyze
{
  "analyzer": "standard",
  "text": "The 2 QUICK Brown-Foxes jumped over the lazy dog's bone"
}

中文分词

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

常用分词系统:
IK

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

jieba:

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

基于自然语言处理的分词系统:
Hanlp:由一系列模型与算法组成的java工具包,目标是普及自然语言处理在生产环境中的应用
THULAC:THU Lexical Analyzer for Chinese,由清华大学自然语言处理与社会人文计算实验室研制推出的一套中文此法分析工具包,具有中文分词和词性标注功能

IK分词器的安装使用:
安装:

./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.0.0/elasticsearch-analysis-ik-6.0.0.zip
对应es版本,在集群所有节点上安装,然后重启服务

ik分词器基础知识:
两种analyzer,ik_smartik_max_word,可以根据需求选择,但一般是选用ik_max_word
ik_max_word:会将文本做最细粒度的拆分。例如,会将“中华人民共和国国歌”差分为“中华人民共和国,中华人民,中华,华人,人民共和国,人民,共和国,共和,国,国歌”,会穷尽各种可能的组合

ik_smart:会做最粗粒度的拆分。例如,会将“中华人民共和国国歌”差分为“中华人民共和国,国歌”
这里写图片描述

使用ik分词:(需要在mapping中指定)

PUT myikindex
{
  "mappings": {
    "doc":{
      "properties": {
        "test":{
          "analyzer": "ik_max_word",
          "type": "text"
        }
      }
    }
  }
}   

自定义分词

当自带的分词无法满足需求时,可以自定义分词,通过自定义Character Filters、TokenizerToken Filters实现。

(1)Character Filters:在Tokenizer之前对原始文本进行处理,比如增加、删除或替换字符等,自带的如下:

  • HTML Strip去除html标签和转换html实体
  • Mapping进行字符替换操作
  • Pattern Replace进行正则匹配替换

会影响后续tokenizer解析的postion和offset信息

POST _analyze
{
  "tokenizer": "keyword",
  "char_filter": ["html_strip"],
  "text": "<p>I&apos;m so <b>happy</b>!</p>"
}

(2)Tokenizer: 将原始文本按照一定规则切分为单词(term or token),自带的如下:

  • standard: 按照单词进行分割
  • letter: 按照非字符类进行分割
  • whitespace: 按照空格进行分割
  • UAX URL Email: 按照standard分割,但不会分割邮箱和url
  • NGram和Edge NGram: 连词分割
  • Path Hierarchy: 按照文件路径进行切割
POST _analyze
{
  "tokenizer": "path_hierarchy",
  "text": "/one/two/three"
}

(3)Token Filters:针对tokenizer处理的单词进行在加工,比如转小写、删除、或新增等处理,自带的如下:

  • lowercase: 将所有term转换为小写
  • stop: 删除stop words
  • NGram和Edge NGram连词分割
  • Synonym添加近义词的term
POST _analyze
{
  "tokenizer": "standard",
  "text": "a Hello,world!",
  "filter": [
    "stop",
    "lowercase",
    {
      "type": "ngram",
      "min_gram": 4,
      "max_gram": 4
    }
    ]
}

自定义分词的api:

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

PUT test_index
{
  "settings": {
    "analysis": {
      "char_filter": {},
      "tokenizer": {},
      "filter": {},
      "analyzer": {}
    }
  }
}   
# "analysis": 分词配置,可以自定义char_filter、tokenizer、filter、analyzer

示例1:
这里写图片描述
这里写图片描述

#配置索引
PUT test_index
{
  "settings": {
    "analysis": {
      "analyzer": {
        "my_custom_abalyzer": {
          "type": "custom",
          "char_filter": ["html_strip"],
          "tokenizer": "standard",
          "filter": [
              "lowercase",
              "asciifolding"
            ]
        }
      }
    }
  }
}   

#测试
POST test_index/_analyze
{
  "analyzer": "my_custom_abalyzer",
  "text": "Is this <b>a box</b>?"
}

示例2:
这里写图片描述
这里写图片描述

#配置索引 
PUT test_index3
{
  "settings": {
    "analysis": {
      "analyzer": {
        "my_custom_analyzer": {
          "type": "custom",
          "char_filter": ["emoticons"],
          "tokenizer": "punctuation",
          "filter": [
              "lowercase",
              "english_stop"
            ]
        }
      },
      "char_filter": {
       "emoticons": {
         "type": "mapping",
         "mappings": [
             ":) => _happy_",
             ":( => _sad_"
           ]
        }
      },
      "tokenizer": {
        "punctuation": {
          "type": "pattern",
          "pattern": "[.,!?]"
       }
      },
      "filter": {
        "english_stop": {
          "type": "stop",
          "stopwords": "_english_"
        }
      }
    }
  }
}
#验证 
POST test_index3/_analyze
{
  "analyzer": "my_custom_analyzer",
  "text": "I'm a :) person,and you?"
}

分词使用说明:

分词会在如下两个时机使用:

  • 创建或更新文档时(Index Time),会对相应的文档进行分词处理
  • 查询时(Search Time),会对查询语句就行分词

索引时分词是通过配置Index Mapping 中每个字段的analyzer属性实现的,如下:

PUT test_index
{
  "mappings": {
    "doc": {
      "properties": {
        "title": {
          "type": "text",
          "analyzer": "whitespace"
        }
      }
    }
  }
}   
# "analyzer"指定分词器

查询时分词的指定方式有如下几种:

  • 查询的时候通过analyzer指定分词器
  • 通过index mapping 设置search_analyzer实现
POST test_index/_search
{
  "query":{
    "match": {
      "message": {
        "query": "hello",
        "analyzer": "standard"
      }
    }
  }
}


PUT test_index
{
  "mappings": {
    "doc": {
      "properties": {
        "title": {
          "type": "text",
          "analyzer": "whitespace"
          , "search_analyzer": "standard"
        }
      }
    }
  }
}

一般不需要特别指定查询时的分词器,直接使用索引时的分词器即可,否则会出现无法匹配的情况。

分词的使用建议:

  1. 明确字段是否需要分词,不需要分词的字段就将type 设置为keyword,可以节省空间和提高写性能
  2. 善用_analyze API,查看文档的具体分词结果
  3. 动手测试

猜你喜欢

转载自blog.csdn.net/wfs1994/article/details/80753353