Read elastic search doc

官方的doc无疑是最有价值的。

0 关于倒排索引

倒排索引

在基本的文本处理后(分词/变小写等), 如上三个文档变成了如图的倒排索引.

倒排索引将 “terms” 映射到 “doc” 上, 如图, 因为 terms 在 dictionary 中是有序的, 所以可以很快的找到这个词, 进而找到包含这个词的文档.

在倒排索引结构中, term 是搜索的单元. 举个例子, 在如上的 dictionay 中, 我么可以高效的找到已 c 字母开头的词, 但是,找包含 ours 词却 很困难, 因为这会遍历所有的 terms, 去找到像 yours 这样的词. 当索引很大时这种操作是十分好资源的.

实际上, 在 es 中, 他为每一个 JSON 字段都建立了自己的倒排索引.

1 描述

Elasticsearch也使用Java开发并使用 Lucene作为其核心 来实现所有索引和搜索的功能,但是它的目的是通过简单的RESTful API来 隐藏 Lucene的复杂性,从而让全文搜索变得简单。
不过,Elasticsearch不仅仅是Lucene和全文搜索,我们还能这样去描述它:

  • 分布式的实时文件存储,每个字段 都被索引并可被搜索
  • 分布式的实时分析搜索引擎
  • 可以扩展到上百台服务器,处理PB级 结构化或非结构化 数据

2 shard & node & index 关系

一个分片(shard)是一个最小级别“工作单元(worker unit)”,它只是保存了索引中所有数据的一部分。分片就是一个Lucene实例,并且它本身就是一个完整的搜索引擎。我们的文档存储在分片中,并且在分片中被索引,但是我们的应用程序不会直接与它们通信,取而代之的是,直接与索引通信。 分片是Elasticsearch在集群中分发数据的关键。把 分片想象成数据的容器。文档存储在分片中,然后分片分配到你集群中的节点上。当你的集群扩容或缩小,Elasticsearch将会自动在你的节点间迁移分片,以使集群保持平衡。

3 副本与节点数对性能的影响

情景 结论 扩容方法
同样主副本,增加节点 每个分片获得更多的机器资源,主副本都能处理请求,吞吐量成倍增加 不修改副本数,直接加机器
同样节点,增加副本 优点:冗余了数据,其他的挂了,还能服务. 缺点:每个分片的所占有的硬件资源就减少了,而且大部分请求都聚集到了分片少的节点,导致一个节点吞吐量太大,反而降低性能 增加副本同时需要同时增加机器

4 几个概念

文档

它特指最顶层结构或者根对象(root object)序列化成的JSON数据(以唯一ID标识并存储于Elasticsearch中)。

包含元数据:

5 文档存储路由

进程不能是随机的,因为我们将来要检索文档。事实上,它根据一个简单的算法决定:

shard = hash(routing) % number_of_primary_shards

routing值是一个任意字符串,它默认是_id但也可以自定义。这个routing字符串通过哈希函数生成一个数字,然后除以主切片的数量得到一个余数(remainder),余数的范围永远是0到number_of_primary_shards - 1,这个数字就是特定文档所在的分片。

5 写和读操作的分片路由逻辑

基本逻辑是:

读和写还不太相同,具体见:
http://es.xiaoleilu.com/040_Distributed_CRUD/15_Create_index_delete.html
http://es.xiaoleilu.com/040_Distributed_CRUD/20_Retrieving.html

6映射

映射决定了这个字段的查询与分析。所以还是应该在存储之前将映射写好。

如:


PUT /order
{
  "mappings": {
    "orderDetail" : {
      "properties" : {
        "orderId" : {
          "type" :    "long"
        },
        "phone" : {
          "type" :   "long"
        },
        "name" : {
          "type" :   "string"
          "index":    "not_analyzed"
        },
        "user_id" : {
          "type" :   "long"
        }
      }
    }
  }
}

如此创建后,name字段可直接通过term查询即可,如:

{
    "filter": {
        "bool": {
            "must": [
               {"term": {
                  "name": "hz"
               }}
            ]
        }
    }
}

7. 使用别名,零停机时间迁移索引

参考:http://es.xiaoleilu.com/070_Index_Mgmt/55_Aliases.html

8. 近实时查询之 倒排索引、段

关于倒排索引:
http://blog.csdn.net/hguisu/article/details/7962350

关键点就是:

段(segment):
一个段(segment)是有完整功能的倒排索引,但是现在Lucene中的索引指的是段的集合。

合并段:
目的就是遍历的段的数量变少,优化查询。
但是ES默认的合并方式已经可以满足,不需要手动调用api合并段。
见:http://es.xiaoleilu.com/075_Inside_a_shard/60_Segment_merging.html

9. 使用filter查询与cache

9.1 filter缓存的步骤

http://es.xiaoleilu.com/080_Structured_Search/05_term.html

Elasticsearch 在内部会通过一些操作来执行一次过滤:

  1. 查找匹配文档。
    term 过滤器在倒排索引中查找词 XHDK-A-1293-#fJ3,然后返回包含那个词的文档列表。在这个例子中,只有文档 1 有我们想要的词。
  2. 创建字节集
    然后过滤器将创建一个 字节集 —— 一个由 1 和 0 组成的数组 —— 描述哪些文档包含这个词。匹配的文档得到 1 字节,在我们的例子中,字节集将是 [1,0,0,0]
  3. 缓存字节集
    最后,字节集被储存在内存中,以使我们能用它来跳过步骤 1 和 2。这大大的提升了性能,让过滤变得非常的快。
    当执行 filtered 查询时,filter 会比 query 早执行。结果字节集会被传给 query 来跳过已经被排除的文档。这种过滤器提升性能的方式,查询更少的文档意味着更快的速度。

9.2 filter过滤器的分类与使用

bool过滤器的组成。

{
   "bool" : {
      "must" :     [],
      "should" :   [],
      "must_not" : [],
   }
}

must:所有分句都必须匹配,与 AND 相同。
must_not:所有分句都必须不匹配,与 NOT 相同。
should:至少有一个分句匹配,与 OR 相同。

9.3 filter使用的优化点

什么样的过滤器会被缓存?

首先,term和terms,exist这样的过滤器都会被缓存,但是range却不一定。在我们的查询中,我们用的range过滤器都是针对long型字段的,这种 可以被缓存,但是想range date的这种,如果有now这样的条件,就不会。可以拆成两个range查询。一个是查大于的,一个是查小于的,这样还至少 能缓存一个range。

具体见:http://es.xiaoleilu.com/080_Structured_Search/40_bitsets.html

其次,大部分直接处理字段的 枝叶过滤器(例如 term) 会被缓存,而像 bool 这类的组合过滤器则不会被缓存。

filter的过滤顺序是很大的优化点。

按区分度排序过滤条件的过滤器。

在 bool 条件中过滤器的顺序对性能有很大的影响。更详细的过滤条件应该被放置在其他过滤器之前,以便在更早的排除更多的文档。 假如条件 A 匹配 1000 万个文档,而 B 只匹配 100 个文档,那么需要将 B 放在 A 前面。