序
这里主要介绍下Elasticsearch 分布式搜索和聚合的一些知识
分布式搜索
-
过程
- 在搜索(search)API返回一页结果前,来自多个分片的结果必须被组合放到一个有序列表中。 因此,搜索的执行过程分两个阶段,称为查询然后取回(query then fetch)
-
查询阶段
-
在初始化查询阶段(query phase),查询被向索引中的每个分片副本(原本或副本)广播。 每个分片在本地执行搜索并且建立了匹配document的优先队列(priority queue)。 一个优先队列(priority queue is)只是一个存有前n个(top-n)匹配document的有序列表。 这个优先队列的大小由分页参数from+size决定,查询阶段包含以下三步
-
客户端发送一个search(搜索)请求给Node 3,Node 3创建了一个长度为from+size的空优先级队列
-
Node 3 转发这个搜索请求到索引中每个分片的原本或副本。每个分片在本地执行这个查询并且结果将结果到一个大小为from+size的有序本地优先队列里去
-
每个分片返回document的ID和它优先队列里的所有document的排序值给协调节点Node 3。Node 3把这些值合并到自己的优先队列里产生全局排序结果
-
每一个分片在本地执行查询和建立一个长度为from+size的有序优先队列——这个长度意味着它自己的结果数量就足够满足全局的请求要求。 分片返回一个轻量级的结果列表给协调节点。只包含documentID值和排序需要用到的值,例如_score
-
-
取回阶段
-
分发阶段由以下步骤构成
-
协调节点辨别出哪个document需要取回,并且向相关分片发出GET请求
-
每个分片加载document并且根据需要丰富(enrich)它们,然后再将document返回协调节点
-
一旦所有的document都被取回,协调节点会将结果返回给客户端
-
协调节点先决定哪些document是实际(actually)需要取回的。例如,我们指定查询{ “from”: 90, “size”: 10 }, 那么前90条将会被丢弃,只有之后的10条会需要取回。 这些document可能来自与原始查询请求相关的某个、某些或者全部分片
-
-
深分页
- 查询然后取回过程虽然支持通过使用from和size参数进行分页,但是要在有限范围内(within limited)。 还记得每个分片必须构造一个长度为from+size的优先队列吧,所有这些都要传回协调节点。 这意味着协调节点要通过对分片数量 * (from + size)个document进行排序来找到正确的size个document
-
搜索选项
-
preference: preference参数允许你控制使用哪个分片或节点来处理搜索请求,她接受如下一些参数,_primary, _primary_first, _local, _only_node:xyz, _prefer_node:xyz和_shards:2,3。
-
结果震荡: 用户每次刷新页面,结果顺序会发生变化。避免这个问题方法是对于同一个用户总是使用同一个分片。 方法就是使用一个随机字符串例如用户的会话ID(session ID)来设置preference参数。
-
timeout timeout参数告诉协调节点最多等待多久,就可以放弃等待而将已有结果返回。返回部分结果总比什么都没有好
-
routing 在搜索时,你可以指定一个或多个routing 值来限制只搜索那些分片而不是搜索index里的全部分片: GET /_search?routing=user_1,user2
-
search_type 虽然query_then_fetch是默认的搜索类型,但也可以根据特定目的指定其它的搜索类型,例如: GET /_search?search_type=count count(计数), query_and_fetch(查询并且取回), scan(扫描),scan(扫描)搜索类型是和scroll(滚屏)API连在一起使用的,可以高效地取回巨大数量的结果。它是通过禁用排序来实现的
-
-
扫描和滚屏
-
scan(扫描)搜索类型是和scroll(滚屏)API一起使用来从Elasticsearch里高效地取回巨大数量的结果而不需要付出深分页的代价
-
scroll(滚屏): 一个滚屏搜索允许我们做一个初始阶段搜索并且持续批量从Elasticsearch里拉取结果直到没有结果剩下。这有点像传统数据库里的cursors(游标)。 滚屏搜索会及时制作快照。这个快照不会包含任何在初始阶段搜索请求后对index做的修改。 它通过将旧的数据文件保存在手边,所以可以保护index的样子看起来像搜索开始时的样子
-
scan(扫描) 深度分页代价最高的部分是对结果的全局排序,但如果禁用排序,就能以很低的代价获得全部返回结果。 扫描模式让Elasticsearch不排序,只要分片里还有结果可以返回,就返回一批结果
GET /old_index/_search?search_type=scan&scroll=1m { "query": { "match_all": {}}, "size": 1000 }
-
聚合
- 聚合
{
"query": {
"match": {
"last_name": "smith"
}
},
"aggs": {
"all_interests": {
"terms": {
"field": "interests"
}
}
}
}