目录
一 集群
二 索引
三 文档
3.1 文档的定义
3.2 文档元数据
hits
took
shards
timeout
3.3 文档、索引、集群关系
四 分片
4.1 分片、文档、集群关系?
4.2 复制分片作用?
4.3 文档是如何路由的?
五 集群健康
六 分页
6.1 在分布式系统中深度分页
一 集群
一个 Elasticsearch 集群由一个或多个节点(Node)组成,每个集群都有一个共同的集群名称作为标识。
二 索引
索引是一系列相同格式文档的集合。索引实际上是指向一个或者多个物理分片的逻辑命名空间。
索引在 Elasticsearch 语境中有多种含义:
- 索引(名词):
如前所述,一个索引类似于传统关系数据库中的一个数据库 ,是一个存储关系型文档的地方。 索引 (index) 的复数词为 indices 或 indexes 。
- 索引(动词):
索引一个文档,就是存储一个文档到一个索引(名词)中以便被检索和查询。这非常类似于 SQL 语句中的 INSERT 关键词,除了文档已存在时,新文档会替换旧文档情况之外。
- 倒排索引:
关系型数据库通过增加一个索引,比如一个 B树(B-tree)索引 到指定的列上,以便提升数据检索速度。Elasticsearch 和 Lucene 使用了一个叫做倒排索引的结构来达到相同的目的。
三 文档
3.1 文档的定义
它是指最顶层或者根对象, 这个根对象被序列化成 JSON 并存储到 Elasticsearch 中,指定了唯一 ID。
3.2 文档元数据
一个文档不仅仅包含它的数据 ,也包含元数据 —— 有关文档的信息。 三个必须的元数据元素如下:
-
:文档在哪存放。_index
-
:文档表示的对象类别。_type
-
:文档唯一标识。_id
3.2.1
_index
一个索引应该是因共同的特性被分组到一起的文档集合。
一个 _index 索引名字必须小写,不能以下划线开头,不能包含逗号。
3.2.2
_type
数据可能在索引中只是松散的组合在一起,但是通常明确定义一些数据中的子分区是很有用的。
例如,所有的产品都放在一个索引中,但是你有许多不同的产品类别,比如 "electronics" 、 "kitchen" 和 "lawn-care"。
这些文档共享一种相同的(或非常相似)的模式:他们有一个标题、描述、产品代码和价格。他们只是正好属于“产品”下的一些子类。
Elasticsearch 公开了一个称为 types (类型)的特性,它允许您在索引中对数据进行逻辑分区。
一个
_type
命名可以是大写或者小写,但是不能以下划线或者句号开头,不应该包含逗号, 并且长度限制为256个字符。
3.2.3
_id
ID 是一个字符串,当它和
_index
以及
_type
组合就可以唯一确定 Elasticsearch 中的一个文档。 当你创建一个新的文档,要么提供自己的
_id
,要么让 Elasticsearch 帮你生成。
3.2.4 hits
{
"hits" : {
"total" : 14,
"hits" : [
{
"_index": "us",
"_type": "tweet",
"_id": "7",
"_score": 1,
"_source": {
"date": "2014-09-17",
"name": "John Smith",
"tweet": "The Query DSL is really powerful and flexible",
"user_id": 2
}
},
... 9 RESULTS REMOVED ...
],
"max_score" : 1
},
"took" : 4,
"_shards" : {
"failed" : 0,
"successful" : 10,
"total" : 10
},
"timed_out" : false
}
hits
返回结果中最重要的部分是
hits
,它包含
total
字段来表示匹配到的文档总数,并且一个
hits
数组包含所查询结果的前十个文档。
在
hits
数组中每个结果包含文档的
_index
、
_type
、
_id
,加上
_source
字段。这意味着我们可以直接从返回的搜索结果中使用整个文档。这不像其他的搜索引擎,仅仅返回文档的ID,需要你单独去获取文档。
每个结果还有一个
_score
,它衡量了文档与查询的匹配程度。默认情况下,首先返回最相关的文档结果,就是说,返回的文档是按照
_score
降序排列的。在这个例子中,我们没有指定任何查询,故所有的文档具有相同的相关性,因此对所有的结果而言
1
是中性的
_score
。
max_score
值是与查询所匹配文档的
_score
的最大值。
took
took
值告诉我们执行整个搜索请求耗费了多少毫秒。
shards
_shards
部分告诉我们在查询中参与分片的总数,以及这些分片成功了多少个失败了多少个。正常情况下我们不希望分片失败,但是分片失败是可能发生的。如果我们遭遇到一种灾难级别的故障,在这个故障中丢失了相同分片的原始数据和副本,那么对这个分片将没有可用副本来对搜索请求作出响应。假若这样,Elasticsearch 将报告这个分片是失败的,但是会继续返回剩余分片的结果。
timeout
timed_out
值告诉我们查询是否超时。默认情况下,搜索请求不会超时。如果低响应时间比完成结果更重要,你可以指定
timeout
为 10 或者 10ms(10毫秒),或者 1s(1秒):
应当注意的是
timeout
不是停止执行查询,它仅仅是告知正在协调的节点返回到目前为止收集的结果并且关闭连接。在后台,其他的分片可能仍在执行查询即使是结果已经被发送了。
使用超时是因为 SLA(服务等级协议)对你是很重要的,而不是因为想去中止长时间运行的查询。
3.3 文档、索引、集群关系
- 每个 Elasticsearch 集群可以包含多个索引。
- 每个索引可以包含多个类型 (Elasticsearch 6.x 已不支持一个索引下多个Type)。
- 每个类型存储着多个文档。
- 每个文档又有多个属性。
四 分片
- 一个分片是一个底层的工作单元 ,它仅保存了全部数据中的一部分。
- 分片可分为主分片( primary shard)和复制分片(replica shard),复制分片是主分片的拷贝。
- 索引内任意一个文档都归属于一个主分片,所以主分片的数目决定着索引能够保存的最大数据量。
技术上来说,一个主分片最大能够存储 Integer.MAX_VALUE - 128 个文档,但是实际最大值还需要参考你的使用场景:
包括你使用的硬件, 文档的大小和复杂程度,索引和查询文档的方式以及你期望的响应时长。
- 默认每个主分片有一个复制分片(默认一个索引创建后会有5个主分片,即:5主+5复制=10个分片),
- 一个索引的复制分片的数量可以动态地调整,复制分片从不与它的主分片在同一个节点上(防止单点故障)。
4.1 分片、文档、集群关系?
- 分片是数据的容器。
- 文档保存在分片内。
- 分片又被分配到集群内的各个节点里。
4.2 复制分片作用?
- 提高恢复能力:当主分片挂掉时,某个复制分片可以变成主分片。
- 提高性能:get 和 search 请求既可以由主分片又可以由复制分片处理。
4.3 文档是如何路由的?
当索引一个文档的时候,文档会被存储到一个主分片中。 Elasticsearch 如何知道一个文档应该存放到哪个分片中呢?当我们创建文档时,它如何决定这个文档应当被存储在分片
1
还是分片
2
中呢?
首先这肯定不会是随机的,否则将来要获取文档的时候我们就不知道从何处寻找了。实际上,这个过程是根据下面这个公式决定的:
shard = hash(routing) % number_of_primary_shards
-
是一个可变值,默认是文档的routing
,也可以设置成一个自定义的值。_id
-
通过 hash 函数生成一个数字,然后这个数字再除以routing
(主分片的数量)后得到余数 。number_of_primary_shards
- 这个分布在 到
之间的余数,就是我们所寻求的文档所在分片的位置。number_of_primary_shards-1
这就解释了为什么我们要在创建索引的时候就确定好主分片的数量,并且永远不会改变这个数量:因为如果数量变化了,那么所有之前路由的值都会无效,文档也再也找不到了。
五 集群健康
- green
所有的主分片和副本分片都正常运行。
- yellow
所有的主分片都正常运行,但不是所有的副本分片都正常运行。
- red
有主分片没能正常运行。
六 分页
和 SQL 使用
LIMIT
关键字返回单个
page
结果的方法相同,Elasticsearch 接受
from
和
size
参数:
size
:显示应该返回的结果数量,默认是
10。
from
:显示应该跳过的初始结果数量,默认是
0。
6.1 在分布式系统中深度分页
理解为什么深度分页是有问题的,我们可以假设在一个有 5 个主分片的索引中搜索。 当我们请求结果的第一页(结果从 1 到 10 ),每一个分片产生前 10 的结果,并且返回给 协调节点 ,协调节点对 50 个结果排序得到全部结果的前 10 个。
现在假设我们请求第 1000 页—结果从 10001 到 10010 。所有都以相同的方式工作除了每个分片不得不产生前10010个结果以外。 然后协调节点对全部 50050 个结果排序最后丢弃掉这些结果中的 50040 个结果。
可以看到,在分布式系统中,对结果排序的成本随分页的深度成指数上升。这就是 web 搜索引擎对任何查询都不要返回超过 1000 个结果的原因。