ES3_3URL查询

在URL中使用查询参数是一种轻量查询(Query-string),一些复杂的查询条件最好还是通过请求体查询组织。

当在单一的索引下进行搜索的时候,Elasticsearch 转发请求到索引的每个分片中,可以是主分片也可以是副本分片,然后从每个分片中收集结果。多索引搜索恰好也是用相同的方式工作的——只是会涉及到更多的分片。
搜索一个索引有五个主分片和搜索五个索引各有一个分片准确来所说是等价的,因为索引只是一种逻辑结构,实际上处理请求的是分片。
搜索有两种形式:Query-string(URI) 和请求体查询。

Query String

URI查询的方式

  • q
    指定查询语句
  • df
    默认字段,不指定时,会对所有字段进行查询
  • sort
    排序
  • from, size
    分页参数
  • profile
    可以用于查看查询是如何被执行的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
HEAD /megacorp/employee/1
GET /megacorp/employee/1
GET /megacorp/employee/_search
# 用q指定查询条件
GET /megacorp/employee/_search?q=last_name:Smith
GET /megacorp/employee/_search?q=+first_name:Jane last_name:Smith
GET /_search?q=mary
GET /_search?q=+name:(mary john) +date:>2014-09-10 +(aggregations geo)
GET /_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 类型(指定多个类型但不限制索引)

可以在请求体中指定profile参数为true来展示查询的过程:

1
2
3
4
get /doc/_search?q=name:a
{
"profile": "true"
}

查询条件

  • 其中 ‘_search’ 表示搜索,默认返回 10 条结果;
  • 查询本身赋值给了参数 q,查询链接会被 URL 编码,所以可读性会比较差;
  • “last_name:Smith”表示 last_name 字段中包含 Smith 的文档,”+last_name:Smith”表示必须与查询条件匹配,”-last_name:Smith”表示一定不与查询条件匹配;
    至于多个条件存在的情况下,其实不会发生矛盾,”+first_name:Jane -first_name:Jane”可以看成先查出 first_name 包含”Jane”的,再过滤掉;
  • 区间查询
    可以用区间表示:
    q=year:{2019 TO 2018}
    q=year:[* TO 2018]
    也可以用算数符号来表示:
    q=year:>2010
    q=year:(>2010 && <=2018)
    q=year:(+>2010 +<=2018)

隐含字段

当对文档进行索引时,Elasticsearch 取出所有字段的值拼接成一个大的字符串,作为 _all 字段进行索引。

Query-string 的优点

简洁

Query-string 的缺点

  • 晦涩难懂
  • 脆弱,小的语法错误就会报错
  • 效率较低,查询字符串搜索允许任何用户在索引的任意字段上执行可能较慢且重量级的查询,这可能会暴露隐私信息,甚至将集群拖垮

搜索返回字段

hits:匹配文档总数及所查询结果的前十个文档
_score:衡量文档与查询的匹配程度
took:整个搜索请求耗费的时间(毫秒)
shards:在查询中参与的分片总数,及失败(主分片和副本分片都挂掉)和成功的数量
timeout:返回值中的 timed_out 表示查询是否超时, timeout 不是停止执行查询,它仅仅是告知正在协调的节点返回到目前为止收集的结果并且关闭连接。在后台,其他的分片可能仍在执行查询即使是结果已经被发送了。使用超时是因为 SLA(服务等级协议)对你是很重要的,而不是因为想去中止长时间运行的查询。可以在查询条件中指定时间限制:

1
GET /_search?timeout=10ms

查询条件

分页

size:显示应该返回的结果数量,默认是 10
from:显示应该跳过的初始结果数量,默认是 0

1
GET /_search?size=5&from=5

考虑到分页过深(比如请求 10001 到 10010 的数据)以及一次请求太多结果的情况:结果集在返回之前先进行排序,但请记住一个请求经常跨越多个分片,每个分片都产生自己的排序结果,这些结果需要进行集中排序以保证整体顺序是正确的。
假设在一个有 5 个主分片的索引中搜索。 当我们请求结果的第一页(结果从 1 到 10 ),每一个分片产生前 10 的结果,并且返回给 协调节点 ,协调节点对 50 个结果排序得到全部结果的前 10 个。
现在假设我们请求第 1000 页–结果从 10001 到 10010 。所有都以相同的方式工作除了每个分片不得不产生前 10010 个结果以外。 然后协调节点对全部 50050 个结果排序最后丢弃掉这些结果中的 50040 个结果。可以看到,在分布式系统中,对结果排序的成本随分页的深度成指数上升。这就是 web 搜索引擎对任何查询都不要返回超过 1000 个结果的原因。

preference(偏好)

用来控制由哪些分片或节点来处理搜索请求。 它接受像 _primary, _primary_first, _local, _only_node:xyz, _prefer_node:xyz, 和 _shards:2,3 这样的值,但是最有用的值是某些随机字符串,它可以避免 bouncing results 问题(不同分片上排序顺序不同),这样可能发生每次用户刷新页面,搜索结果表现是不同的顺序,所以最好让同一个用户始终使用同一个分片,可以设置 preference 参数为一个特定的任意值比如用户会话 ID 来解决。

timeout(超时)

在分布式搜索时需要由每个分片处理完、将结果返回给协调节点进行排序、再返回给客户端,所以整个过程的效率受到最慢的那个分片的处理速度和协调节点的处理速度二者的限制;
参数 timeout 告诉 分片允许处理数据的最大时间。如果没有足够的时间处理所有数据,这个分片的结果可以是部分的,甚至是空数据,搜索的返回结果会用属性 timed_out 标明分片是否返回的是部分结果(是否超时);
需要注意可能会影响到整体延迟(并非上面说的超时时间)的条件,比如某些查询类型有大量的工作在文档评估之前需要完成、每次评估时基于每个文档的所以单个文档死循环也会影响整个查询死循环。

routing(路由)

在索引时提供 routing 值可以确保文档被存储到某个分片上,在搜索的时候,不用搜索索引的所有分片,而是通过指定几个 routing 值来限定只搜索几个相关的分片,这个技术在 设计大规模搜索系统 时就会派上用场。

search_type(搜索类型)

缺省的搜索类型是 query_then_fetch。你可能想明确设置 search_type 为 dfs_query_then_fetch 来改善相关性精确度,搜索类型 dfs_query_then_fetch 有预查询阶段,这个阶段可以从所有相关分片获取词频来计算全局词频。

1
2
3
4
5
6
GET /_search?preference=xyzabc123&routing=user_1,user2&search_type=dfs_query_then_fetch
{
"from": 0,
"size": 5,
"timeout": "1s"
}