ElasticSearch倒排索引、分词的详解和使用建议

时间:2024-05-19 07:24:03

一、倒排索引(Inverted Index)


ElasticSearch引擎把文档数据写入到倒排索引(Inverted Index)的数据结构中,倒排索引建立的是分词(Term)和文档(Document)之间的映射关系,在倒排索引中,数据是面向词(Term)而不是面向文档的。

一个倒排索引由文档中所有不重复词的列表构成,对于其中每个词,有一个包含它的文档列表。


举个例子:
对以下三个文档去除停用词后构造倒排索引

ElasticSearch倒排索引、分词的详解和使用建议

 

倒排索引-查询过程

对上面图片中查询包含“搜索引擎”的文档,通过倒排索引获得“搜索引擎”对应的文档id列表,有1、3。

通过正排索引查询1和3的完整内容,返回最终结果。


倒排索引-组成

  • 单词词典(Term Dictionary)
  • 倒排列表(Posting List)

 

单词词典(Term Dictionary)


单词词典的实现一般用B+树,B+树构造的可视化过程网址:B+ Tree Visualization


倒排列表(Posting List)

倒排列表记录了单词对应的文档集合,由倒排索引项(Posting)组成,倒排索引项主要包含如下信息:

  1. 文档id用于获取原始信息。
  2. 单词频率(TF,Term Frequency),记录该单词在该文档中出现的次数,用于后续相关性算分。
  3. 位置(Posting),记录单词在文档中的分词的位置(可能有多个的位置),用于做短语搜索(Phrase Query)。
  4. 偏移(Offset),记录单词在文档的开始和结束位置下标,用于高亮显示。

ElasticSearch倒排索引、分词的详解和使用建议

B+树内部结点存索引,叶子结点存数据,这里的 单词词典就是B+树索引,倒排列表就是数据,整合在一起后如下所示:

ElasticSearch倒排索引、分词的详解和使用建议

ES存储的是一个JSON格式的文档,其中包含多个字段,每个字段会有自己的倒排索引。

 

倒排索引的结构

  1. 包含这个关键词的document list
  2. 包含这个关键词的所有document的数量:IDF(inverse document frequency)
  3. 这个关键词在每个document中出现的次数:TF(term frequency)
  4. 这个关键词在这个document中的次序
  5. 每个document的长度:length norm
  6. 包含这个关键词的所有document的平均长度

倒排索引的好处

  1. 不需要锁,提升并发能力,避免锁的问题
  2. 数据不变,一直保存在 cache中,只要cache内存足够
  3. filter cache一直留在内存,因为数据不变
  4. 可以压缩,节省cpu和io开销

二、分词


分词是将文本转换成一系列单词(Term or Token)的过程,也可以叫文本分析,在ES里面称为Analysis

ElasticSearch倒排索引、分词的详解和使用建议

分词器


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

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

 

分词器的组成

Character Filters

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

                HTML Strip Character Filter:去除HTML标签和转换HTML实体

                Mapping Character Filter:进行字符替换操作

                Pattern Replace Character Filter:进行正则匹配替换

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

ElasticSearch倒排索引、分词的详解和使用建议

 

Tokenizers

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

              1.standard 按照单词进行分割
              2.letter 按照非字符类进行分割
              3.whitespace 按照空格进行分割
              4.UAX URL Email 按照standard进行分割,但不会分割邮箱和URL
              5.Ngram 和 Edge NGram 连词分割
              6.Path Hierarchy 按照文件路径进行分割

ElasticSearch倒排索引、分词的详解和使用建议

 

Token Filters

  • 对于tokenizer输出的单词(term)进行增加、删除、修改等操作
  • 自带的如下:

              1.lowercase 将所有term转为小写
              2.stop 删除停用词
              3.Ngram 和 Edge NGram 连词分割
              4.Synonym 添加近义词的term

ElasticSearch倒排索引、分词的详解和使用建议

 

分词器调用顺序

ElasticSearch倒排索引、分词的详解和使用建议

 


在Kibana上分词的案例

ElasticSearch倒排索引、分词的详解和使用建议

 

 

 

ES中预定义的分词器

1.Standard Analyzer
     默认分词器
     按词切分,支持多语言
     小写处理
2.Simple Analyzer
     按照非字母切分
     小写处理
3.Whitespace Analyzer
     空白字符作为分隔符
4.Stop Analyzer
     相比Simple Analyzer多了去除请用词处理
     停用词指语气助词等修饰性词语,如the, an, 的, 这等
5.Keyword Analyzer
     不分词,直接将输入作为一个单词输出
6.Pattern Analyzer
     通过正则表达式自定义分隔符
     默认是\W+,即非字词的符号作为分隔符
7.Language Analyzer
     提供了30+种常见语言的分词器


三、自定义分词


自定义分词需要在索引配置中设定 char_filter、tokenizer、filter、analyzer等。

ElasticSearch倒排索引、分词的详解和使用建议

 

四、分词使用说明


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

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

               1.查询时通过analyzer指定分词器
               2.通过index mapping设置search_analyzer实现
               3.一般不需要特别指定查询时分词器,直接使用索引分词器即可,否则会出现无法匹配的情况

 

五、ElasticSearch的使用建议

   1.在java实体类中定义往ES存入数据的格式

                        >定义实体类对应ES中的索引和类型 @Document(indexName = "contractcenter-cargoitem", type = "plcCargoItemESVO")、 

                        >定义非日期类型数据是否分词 @Field(index = FieldIndex.analyzed)、

                        >定义日期类型数据时间格式 @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ", timezone = "GMT+8")

          

    2.存入ES日期类型数据常见问题

      2.1.实体类日期类型数据时间格式 要与 手工录入 或 接口调用存入ES的日期类型数据时间格式一致,

        例如:实体类是yyyy-MM-dd'T'HH:mm:ss.SSSZ+0800,ES也必须是yyyy-MM-dd'T'HH:mm:ss.SSSZ+0800

      2.2.ES存入数据时,会规定数据的类型,日期类型最好是简约形式,不要用其他的属性,例如:

        "shipmentDate": {

            "type": "date"

          }

      2.3.在往ES存入数据的时候,如果要存入的数据 ES里没有,ES会自动为那些没有的数据创建索引。

      2.4.在第一次java或手工往ES存数据时,会生成数据的索引和数据的类型, 如果后面改变数据的类型,会由于与第一次存数据的类型不一致而报数据解析异常。

  3. 明确字段是否需要分词,需要分词的字段就将type设置为keyword,可以提高查询效率。

  4.在使用analyze API时,需要十分注意,并且要查看文档的分词结果是否正确。