以上的routing的值是一个任意的字符串,它默认被设置成文档的_id字段,但是也可以被设置成其他指定的值。这个routing字符串会被传入到一个哈希函数(Hash Function)来得到一个数字,然后该数字会和索引中的主要分片数进行模运算来得到余数。这个余数的范围应该总是在0和number_of_primary_shards - 1之间,它就是一份文档被存储到的分片的号码。
这就解释了为什么索引中的主要分片数量只能在索引创建时被指定,并且将来都不能在被更改:如果主要分片数量在索引创建后改变了,那么之前的所有路由结果都会变的不正确,从而导致文档不能被正确地获取。那么如何水平扩展呢,可以移步。
所有的文档API(get, index, delete, bulk, update)都接受一个routing参数,它用来定制从文档到分片的映射。一个特定的routing值能够确保所有相关文档 - 比如属于相同用户的所有文档 - 都会被存储在相同的分片上。
写操作原理图:
写入的请求流程如图所示(此图源自《Elasticsearch权威指南》):
写入到磁盘流程如下图所示:
由此可见ES的实时并非是完全的实时,而是一种准实时(Near-Real-Time)。
读操作探讨读分为两个阶段,查询阶段(Query Phrase)以及聚合提取阶段(Fetch Phrase)
查询阶段协调节点接受到读请求,并将请求分配到相应的分片上(有可能是主分片或是副本分片,这个机制后续会提及),默认情况下,每个分片创建10个结果(仅包含 document_id 和 Scores)的优先级队列,并以相关性排序,返回给协调节点。
查询阶段如果不特殊指定,落入的分片有可能是 primary 也有可能是 replicas,这个根据协调节点的负载均衡算法来确定。
聚合提取阶段假设查询落入的分片数为 N,那么聚合阶段就是对 N*10 个结果集进行排序,然后再通过已经拿到的 document_id 查到对应的 document 并组装到队列里,组装完毕后将有序的数据返回给客户端。
客户端发送请求到任意一个Node,成为Coordinating node
Coordinating node对Document进行路由,将请求转发到对应的Node上,此时会使用Round-Robin随机轮询算法,在Primary Shard以及其所有Replica中随机选择一个,让读请求负载均衡
接收请求的node返回Document给Coordinating node
Coordinating node返回Document给客户端
ElasticSearch实战ES在.NET平台上的官方客户端是NEST,以下操作都是基于该package的。
常用操作以下操作均基于ES-Head,该工具是一个Chrome插件,非常简单实用,而且可以在GitHub上搜到源码,方便个性化开发。
写入数据:
返回的数据中,可以看到Id是一段字符串,这是因为在写入的过程中并没有指定,所以会由ES默认生成。当然可以指定:
更新数据:
_version值会随着操作次数,逐渐迭代。
删除数据: