Skip to content

Latest commit

 

History

History
159 lines (119 loc) · 4.08 KB

inverted_index.asciidoc

File metadata and controls

159 lines (119 loc) · 4.08 KB

关于倒排索引

什么是倒排索引

Elasticsearch 用的倒排索引,就是一种结构,或者说数据结构。

比如举个例子:想搜索 apple iphone ,Elasticsearch 默认的分词器会将这个搜索内容,切分为 appleiphone

这也就是所谓分词器的作用,用来切词。没人使用的分词器 standard 标准分词器,是按照空格来切分的。

如果想使用中文,就需要安装ik分词器。对中文进行分词。

默认的 standard 分词器,比如 中国 ,直接就切分成 中 和 国了。不会把中国看成是一个词。

举例:有这两个document

  1. The quick brown fox jumped over the lazy dog

  2. Quick brown foxes leap over lazy dogs in summer

创建倒排索引后,会把字段内容切分成每个词,并且标记在每个每个文档出现过。

Term      Doc_1  Doc_2
-------------------------
Quick   |       |  X
The     |   X   |
brown   |   X   |  X
dog     |   X   |
dogs    |       |  X
fox     |   X   |
foxes   |       |  X
in      |       |  X
jumped  |   X   |
lazy    |   X   |  X
leap    |       |  X
over    |   X   |  X
quick   |   X   |
summer  |       |  X
the     |   X   |
------------------------

比如想搜索 quick brown ,只要找到哪个文档出现 quick 或者 brown

Term      Doc_1  Doc_2
-------------------------
brown   |   X   |  X
quick   |   X   |
------------------------
Total   |   2   |  1

这是官方给的例子。其实已经很明了了。

但是这里要注意个问题:quick brown 是搜索词,搜索时候是要被分词或切词的。

而document是创建倒排索引的时候被分词或切词的。

Doc_1 匹配到了两个词,Doc_2匹配到了一个词,这样Elasticsearch 会有一个相关度的评分算法,把Doc_1排到数据结果的上边。

英文分词的几个问题

当然还有一些其他问题,比如:

  1. Quick 和 quick,作为单独的terms出现,而用户可能认为它们是同一个单词。

  2. fox 和 foxes 他们是相似的,也还是一个意思。

  3. jumped 和 leap , 他们的意思是一样的。

好像这三个问题,在中文里边没有场景会有问题吧!我得想想。

分析器也就做了一些事情

  1. Quick 变成小写的 quick。

  2. foxes 变成 fox, dogs 变成 dog。 英文里这叫单词的根状态吧!不知道,官方文档是这么解释的。

  3. jumped 和 leap 就是同意词,都 term jump。

然后就变成这样:

Term      Doc_1  Doc_2
-------------------------
brown   |   X   |  X
dog     |   X   |  X
fox     |   X   |  X
in      |       |  X
jump    |   X   |  X
lazy    |   X   |  X
over    |   X   |  X
quick   |   X   |  X
summer  |       |  X
the     |   X   |  X
------------------------

正排索引

可以相对再举个例子,那先说什么是正排索引。

Elasticsearch 搜索是用倒排索引,而排序和聚合就是正排索引。这里边牵扯到两个概念,一个是doc_value 另一个就是fieldata。

什么正排索引呢?

你可以把他想象成你执行了一条sql语句,在mysql 查询出来的结果应该是这个样子的:

ID     字段1  字段2
-------------------------
1   |   X   |  X
2   |   X   |  X
3   |   X   |  X
4   |   X   |  X
5   |   X   |  X
6   |   X   |  X
------------------------

这就是正排索引,上边的例子存成倒排索引,就是这个样子的:

词项        文档 ID
-------------------------
词1    ->   1,2....
词2    ->   2,3....
词3    ->   1,3....
词4    ->   1....
词5    ->   2....
词6    ->   3....
------------------------

优化的建议

如果在业务需求的时候,能够明确这个字段不需要做排序和聚合,可以考虑将正排索引关掉,能省则省吧,比如下边例子的 age字段,关闭doc_value :

PUT users
{
    "mappings" : {
      "properties" : {
        "name" : {
          "type" : "text"
        },
        "mobile" : {
          "type" : "keyword"
        },
        "age" : {
          "type" : "integer",
          "doc_values": false
        }
      }
    }
}