Elasticsearch 分布式搜索
搜索API(_search)返回一页结果前,先找到所有匹配的文档,并将来自多个分片的文档的结果必须被组合放到一个有序列表中。因此,搜索的执行过程分为两个阶段:查询然后取回
查询段阶
在初始化查询阶段(query phase),查询被向索引中的每个分片副本(原本或副本)广播。每个分片在本地执行搜索并且建立了匹配document的优先队列(priority queue)。
1.客户端发送一个 search(搜索) 请求给 Node 3 , Node 3 创建了一个长度为 from+size 的空优先级队列。
2. Node 3 转发这个搜索请求到索引中每个分片的原本或副本。每个分片在本地执行这个查询并且结果将结果到一个大小为 from+size 的有序本
地优先队列里去。
3.每个分片返回document的ID和它优先队列里的所有document的排序值给协调节点 Node 3 。 Node 3 把这些值合并到自己的优先队列里产生全局排序结果。
分片返回一个轻量级的结果列表给协调节点。只包含documentID值和排序需要用到的值,例如 _score 。
取回阶段
1.协调节点辨别出哪个document需要取回,并且向相关分片发出 GET 请求。
2.每个分片加载document并且根据需要丰富(enrich)它们,然后再将document返回协调节点。
3.一旦所有的document都被取回,协调节点会将结果返回给客户端。
意味着协调节点要通过对 分片数量 * (from +size) 个document进行排序来找到正确的 size 个documen
如果你确实需要从集群里获取大量documents,你可以通过设置搜索类型 scan 禁用排序:扫描和滚屏
也可以通过preference(偏爱)timeout(超时)routing(路由选择)search_type来改变搜索路径
preference 参数允许你控制使用哪个分片或节点来处理搜索请求。她接受如下一些参数 _primary , _primary_first ,
_local , _only_node:xyz , _prefer_node:xyz 和 _shards:2,3 。这些参数在文档搜索偏好(search preference)里有详细
描述。
然而通常最有用的值是一些随机字符串,它们可以避免结果震荡问题(the bouncing results problem)。
想像一下,你正在按照 timestamp 字段来对你的结果排序,并且有两个document有相同的timestamp。由于搜索请求是
在所有有效的分片副本间轮询的,这两个document可能在原始分片里是一种顺序,在副本分片里是另一种顺序。
这就是被称为结果震荡(bouncing results)的问题:用户每次刷新页面,结果顺序会发生变化。避免这个问题方法是对
于同一个用户总是使用同一个分片。方法就是使用一个随机字符串例如用户的会话ID(session ID)来设
置 preference 参数。
通常,协调节点会等待接收所有分片的回答。如果有一个节点遇到问题,它会拖慢整个搜索请求。
timeout 参数告诉协调节点最多等待多久,就可以放弃等待而将已有结果返回。返回部分结果总比什么都没有好。
搜索请求的返回将会指出这个搜索是否超时,以及有多少分片成功答复了:
...
"timed_out": true, (1)
"_shards": {
"total": 5,
"successful": 4,
"failed": 1 (2)
},
...
(1) 搜索请求超时。
(2)
五个分片中有一个没在超时时间内答复。
如果一个分片的所有副本都因为其他原因失败了——也许是因为硬件故障——这个也同样会反映在该答复的 _shards 部分
里。
在路由值那节里,我们解释了如何在建立索引时提供一个自定义的 routing 参数来保证所有相关的document(如属于单个用
户的document)被存放在一个单独的分片中。在搜索时,你可以指定一个或多个 routing 值来限制只搜索那些分片而不是搜
索index里的全部分片:
GET /_search?routing=user_1,user2
这个技术在设计非常大的搜索系统时就会派上用场了。我们在规模(scale)那一章里详细讨论它。
搜索选项
preference(偏爱)
结果震荡(Bouncing Results)
timeout(超时)
routing(路由选择)
虽然 query_then_fetch 是默认的搜索类型,但也可以根据特定目的指定其它的搜索类型,例如:
GET /_search?search_type=count
count(计数)
count(计数) 搜索类型只有一个 query(查询) 的阶段。当不需要搜索结果只需要知道满足查询的document的数量时,可以使
用这个查询类型。
query_and_fetch(查询并且取回)
query_and_fetch(查询并且取回) 搜索类型将查询和取回阶段合并成一个步骤。这是一个内部优化选项,当搜索请求的目标只是
一个分片时可以使用,例如指定了 routing(路由选择) 值时。虽然你可以手动选择使用这个搜索类型,但是这么做基本上不会
有什么效果。
dfs_query_then_fetch 和 dfs_query_and_fetch
dfs 搜索类型有一个预查询的阶段,它会从全部相关的分片里取回项目频数来计算全局的项目频数。我们将在relevance-isbroken(
相关性被破坏)里进一步讨论这个。
scan(扫描)
scan(扫描) 搜索类型是和 scroll(滚屏) API连在一起使用的,可以高效地取回巨大数量的结果。它是通过禁用排序来实现
的。我们将在下一节scan-and-scroll(扫描和滚屏)里讨论它。

浙公网安备 33010602011771号