ElasticSearch(五)--搜索Search

前边的学习,我们已经可以将ElasticSearch作为一个分布式存储系统使用,但是ES的真正强大之处在于可以在混乱的数据中找出有意义的信息.

每个文档里的字段都会被索引并被查询,关于搜索Search,可以做:

结构化查询:比如在gender性别和年龄age这样的字段上使用结构化查询,在join_date这样的字段上使用排序.

全文查询:可以使用所有字段来匹配关键字,然后按照关联性relevance排序返回结果.

也可以两者结合使用.

搜索都是开箱即用的,为了深入了解ES的潜力,需要三个概念:

映射Mapping:数据在每个字段中的解释说明

分析Analysis:全文是如何被处理,被搜素的

特定领域语言查询Query DSL(Domian Specific Language):ES灵活强大的查询语言.

这三个概念每一个都是巨大的话题,后续详细学习,本章节简单介绍.

下边详细学习search API

1. 空搜索

最基本的search API是空搜索empty search,它没有指定任何搜索条件,返回的是集群索引中所有的文档.

GET /_search
响应内容类似于:

{
  "took": 15,
  "timed_out": false,
  "_shards": {
    "total": 15,
    "successful": 15,
    "failed": 0
  },
 "hits" : {
       "total" :       14,
       "max_score" :   1
       "hits" : [
        {
          "_index":   "us",
          "_type":    "tweet",
          "_id":      "7",
          "_score":   1,
          "_source": {
             "date":    "2014-09-17",
             "name":    "John Smith",
             "tweet":   "The Query DSL is really powerful and flexible",
             "user_id": 2
          }
       },
        ... 9 RESULTS REMOVED ...
      ],
     
   },
}


hits字段是响应中最重要的一部分,它包含total字段来表示匹配到的文档总数;max_score是所有匹配文档中相关性最高的值;hits数组包含了匹配到的前10条数据,数组的每个元素代表一个文档,其中_score为文档相关性指标,因为是空搜索,所以所有文档的_score都为1;

took字段,指请求花费的时间,单位为毫秒;

_shards代表参与查询的分片数的情况,total是参与的总分片数,successful是成功的分片数,通常我们不希望分片失败,但也有可能发生,如果硬件遭受大的故障导致主分片和复制分片都失效,那么这个分片将无法响应请求,ES将该分配报告为failed,但仍然继续返回剩余分片上的结果.

timed_out告诉我们查询是否超时;一般情况不会超时;如果要求的响应速度比结果更重要,可以在搜索的时候指定时间限,为10或者10ms,或者1s

GET /_search?timeout=10ms

ES将返回在时间限前查询到的结果.

注意:超过指定的timeout之后,不会停止执行查询,它仅顺利返回目前查询到的结果,然后关闭连接.在后台其他分片可能依旧查询操作;

使用超时是因为对业务的响应速度需求比结果重要,但并不是中断需要长时间进行的查询.

2. 多索引多类别搜索

通过限制搜索的索引或类型,可以在集群中跨所有文档搜索.ES通过转发请求到集群中主分片和复制分片上,收集结果后选择顶部的10个结果返回给客户端.

类型user属于索引us,类型tweet属于索引gb

根据索引和类型多样的搜索方式:

/_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类型中搜索

当节点收到搜索请求后,节点转发请求到索引的主分片和复制分片上,然后收集每个分片的结果.

3. 分页

ES默认只在响应中返回top10的相关文档,如何更具应用的需要返回其他文档呢?就像SQL中LIMIT关键词的功效一样.

ES的请求URL接受size和from参数,

size:结果数,默认为10

from :跳过的数目,默认为0

所以在没指定size和from参数时,返回开始的10个相关文档.

如果显示每页五个结果,页码从1到3:

GET /_search?size=5
GET /_search?size=5&from=5
GET /_search?size=5&from=10
这里需要注意的问题,注意分页太深,和一次请求结果太多的问题.

一个请求常涉及到多个分片,每个分片都会生成自己的排序结果,它们需要再次集中起来排序以返回请求需要的结果给客户端.

深度分页存在的:

假设有五个分片,每一页返回10个结果,那么在请求第一页时(也就是top10的结果),每个分片需要各自产生10个结果,然后每个分片把产生的这10个结果返回个请求节点,请求节点对收到的10*5=50个结果再进行排序,选择前10个返回客户端;

但是当请求第1001页时,也就是请求(10000-10010)的结果,同样每个分片产生10010个结果,请求节点收到10010*5=50050的结果,请求节点对这50050个结果进行排序,然后返回第1000-10010的结果;

显然排序的花费随着分页的加深而成倍增长.

4. query-string方法

search API有两种方式:

精简版的,查询字符串query-string方法,通过在请求URL后加参数的方式;

请求体方式,使用一个JSON格式的请求体,这种成为DSL查询语言.

查询字符串方法在命令行下运行即席查询ad hoc queries特别有用.

查询所有类型为tweet,并且字段tweet中包含elasticsearch字符的文档:

GET /_all/tweet/_search?q=tweet:elasticsearch
如果还想查找name中包含join,tweet中包含mary的文档:

GET /_all/tweet/_search?q=name:join+tweet:mary
使用+符号连接,结果集为两个条件的合集,即有的结果文档中只匹配一个条件.

如果要是选择不满足条件的,比如name不包含join的:

GET /_all/tweet/_search?q=-name:join

比如,name包含join但tweet不包含jmary的:

GET /_all/tweet/_search?q=name:join+-tweet:mary
注意使用+号连接 -tweet:mary

_all字段:

返回所有包含mary字符串的文档,无论是在哪个字段中包含,只有有就返回:

GET /_search?q=mary
那么ES是如何实现这功能的呢?实际上文档有一个特殊的_all字段,该字段把所有的字段的数据连接成以一个大的字符串,匹配时通过_all字段进行匹配.

例如文档内容:

{
    "tweet":    "However did I manage before Elasticsearch?",
    "date":     "2014-09-14",
    "name":     "Mary Jones",
    "user_id":  1
}
这个_all字段为:

"However did I manage before Elasticsearch? 2014-09-14 Mary Jones 1"
实际上请求就是:

GET /_search?q=_all:mary
结果是一样的.

更复杂的搜索

搜索要求:

  • name字段包含"mary""john"
  • date晚于2014-09-10
  • _all字段包含"aggregations""geo"
搜索命令:

GET /_search?q=name:(mary john) +date:>2014-09-10 +(aggregations geo)
但实际上(mary join)中间的空格并不正确,使用+号反而可以运行,日期的比较也是错误的:

GET /_search?q=name:(mary+john) +(aggregations+geo)
不知道日期如何比较...

可以看出字符串查询是非常强大的,它在命令行下一次性查询或者开发模式下非常有用.

但也可以看出,其是非常脆弱的,一点的符号错误都有可能到是查询失败.

还有就是安全性问题,不建议直接暴露查询字符串给用户,除非用户对集群可信.

所以取而代之,我们一般使用全功能的请求体API的方式,在学习请求体时,先了解数据是如何在ES中被索引的.

猜你喜欢

转载自blog.csdn.net/WuyZhen_CSDN/article/details/51407494