通过限制搜索的不同索引或类型,我们可以在集群中跨所有文档搜索。Elasticsearch转发搜索请求到集群中平行的主分片或每个分片的复制分片上,收集结果后选择顶部十个返回给我们。
通常,当然,你可能想搜索一个或几个自定的索引或类型,我们能通过定义URL中的索引或类型达到这个目的,像这样:
/_search
在所有索引的所有类型中搜索。
/gb/_search
在索引 gb 的所有类型中搜索。
/gb,us/_search
在索引 gb 和 us 的所有类型中搜索。
/g*,u*/_search
在以 g 或 u 开头的索引的所有类型中搜索。
/gb/user/_search
在索引 gb 的类型 user中搜索。
/gb,us/user,tweet/_search
在索引 gb 和 us 的类型为 user 和 tweet中搜索。
/_all/user,tweet/_search
在所有索引的user和tweet中搜索search types user and tweet in all indices
当你搜索包含单一索引时,Elasticsearch转发搜索请求到这个索引的主分片或每个分片的复制分片上,然后聚集每个分片的结果。搜索包含多个索引也是同样的方式——只不过或有更多的分片被关联。
重要:搜索一个索引有5个主分片和5个索引各有一个分片事实上是一样的。
-
分页
和SQL使用LIMIT关键在返回只有一页的结果一样,Elasticsearch接受from和size参数:
size:结果数,默认10.
from:跳过开始的结果数,默认0.
如果你想每页显示5个结果,页码从1到3,那请求如下:
GET /_search?size=5
GET /_search?size=5&from=5
GET /_search?size=5&from=10
应该当心分页太深或者一次请求太多的结果。结果在返回前会被排序。但是记住一个搜索请求常常涉及多个分片。每个分片生成自己排好序的结果,他们接着需要集中起来排序以确保整体排序正确。
在集群系统中深度分页
为了理解为什么深度分页是有问题的,让我们假设在一个有5个主分片的索引中搜索。当我们请求结果的第一次(结果1到10)时,每个分片产生自己最顶端10个结果然后返回它们给请求节点(requesting node),它再排序这所有的50个结果以选出顶端的10个结果。
现在假设我们请求第1000页——结果10001到10010。工作方式都相同,不同的是每个分片都必须产生顶端的10010个结果。然后请求节点排序50050个结果并丢弃50040个。
你可以看到在分布式系统中,排序结果的花费随着分页的深入而成倍增长。这也是为什么网络搜索引擎中任何语句不能返回多于1000个结果的原因。
-
简易搜索
search API有两种表单:一种是“简易版”的查询字符串(query string)将所有参数通过查询字符串定义,另一种版本使用JSON完整的表示请求体(request body),这种富搜索语言叫做结构化查询语句(DSL)。
查询字符串搜索对于在命令行下运行点对点(ad hoc)查询特别有用。例如这个语句查询所有类型为tweet并在tweet字段中包含elasticsearch字符的文档:
GET /_all/tweet/_search?q=tweet:elasticsearch
下一个语句查找name字段中包含“john”和tweet字段包含“mary”的结果。实际的查询只需要:
+name:join + tweet:mary
但是percent encoding(注:就是url编码)需要将查询字符串参数变得更加神秘:
GET /_search?q=%2Bname%3Ajohn+%2Btweet%3Amary
"+"前缀表示语句匹配条件必须被满足。类似的“-”前缀表示条件必须不被满足。所有条件如果没有 + 或 - 表示是可选的——匹配越多,相关的文档就越多。
-
_all字段
返回包含“mary”字符的所有文档的简单搜索:
GET /_search?q=mary
在前一个例子中,我们搜索tweet或name字段中包含某个字符的结果。然而,这个语句返回的结果在三个不同的字段中包含“mary”:
- 用户的名字是"Mary"
- "Mary"发的六个推文
- 针对“@mary”的一个推文
Elasticsearch是如何设法找到三个不同字段的结果的?
当你索引一个文档,Elasticsearch把所有字符串字段值连接起来放在一个大字符串中,它被索引为一个特殊的字段_all。例如,当索引这个文档:
这好比我们增加了一个叫做_all的额外字段值:
查询字符串在其他字段被定以前使用_all字段搜索。
TIP:_all字段对于开始一个新应用时是一个有用的特性。之后,如果你定义字段来代替_all字段,你的搜索结果将更加可控。当_all字段不再使用,你可以停用它。
-
更复杂的语句
下一个搜索推特的语句:
_all field
- name字段包含“mary”或"join"
- date晚于2014-09-10
- _all字段包含“aggregations”或“geo”
+name:(mary john) + date:>2014-09-10 + (aggregations geo)
编码后的查询字符串变得不太容易阅读:
?q=%2Bname%3A(mary+john)+%2Bdate%3A%3E2014-09-10+%2B(aggregations+geo)
就像你上面看到的例子,简单(lite)查询字符串搜索惊人的强大。这对于命令行下一次性查询或者开发模式非常有用。
然而,你可以看到简洁带来了隐晦和调试困难。而且它很脆弱——查询字符串中一个细小的语法错误,像-、:、/或''错位就会导致返回错误而不是结果。
最后,查询字符串搜索允许任意用户在索引中任何一个字段上运行潜在的慢查询语句,可能暴露私有信息甚至使你的集群瘫痪。
TIP:因为这些原因,我们不建议直接暴露查询字符串搜索给用户,除非这些用户对于你的数据和集群可信。
取而代之的,生产环境我们一般依赖全功能的请求体搜索API,它能完成前面所有的事情,甚至更多。