一 空搜索

搜索API的最基础的形式是没有指定任何查询的空搜索 ,它简单地返回集群中所有索引下的所有文档:

示例

GET 127.0.0.1:9200/_search

响应

{
  "took": 166,
  "timed_out": false,
  "_shards": {
    "total": 10,
    "successful": 10,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 5,
    "max_score": 1,
    "hits": [
      {
        "_index": "test",
        "_type": "test",
        "_id": "WOTj8GYBuXRyDW5PpvRN",
        "_score": 1,
        "_source": {
          "first_name": "John",
          "last_name": "Smith",
          "age": 25,
          "about": "I love to go rock climbing",
          "interests": [
            "sports",
            "music"
          ]
        }
      },
      {
        "_index": "test",
        "_type": "test",
        "_id": "4",
        "_score": 1,
        "_source": {
          "hello": "world",
          "author": "wuzhe"
        }
      },
      {
        "_index": "test",
        "_type": "test",
        "_id": "6",
        "_score": 1,
        "_source": {
          "test": "test10",
          "author": "wuzhe"
        }
      },
      {
        "_index": "megacorp",
        "_type": "employee",
        "_id": "1",
        "_score": 1,
        "_source": {
          "first_name": "John",
          "last_name": "Smith",
          "age": 25,
          "about": "I love to go rock climbing",
          "interests": [
            "sports",
            "music"
          ]
        }
      },
      {
        "_index": "test",
        "_type": "test",
        "_id": "3",
        "_score": 1,
        "_source": {
          "first_name": "John",
          "last_name": "Smith",
          "age": 25,
          "about": "I love to go rock climbing",
          "interests": [
            "sports",
            "music"
          ]
        }
      }
    ]
  }
}

我们可以看到响应中的hits段,total代表了es中总共查询到的文档个数,hits里的hits部分则是具体文档的内容,包括文档的index、type、id以及source。空搜索默认返回的是前10个文档的内容。

若想返回更多文档,Elasticsearch 接受 from 和 size 参数:

size 表示应该返回的结果数,默认是10

from 表示应该跳过的结果数, 默认是0

GET 127.0.0.1/_search?size=20&from=10

表示获取第11条到30条的文档

  • 需要注意的一点是:

理解为什么深度分页是有问题的,我们可以假设在一个有 5 个主分片的索引中搜索。 当我们请求结果的第一页(结果从 1 到 10 ),每一个分片产生前 10 的结果,并且返回给 协调节点,协调节点对 50 个结果排序得到全部结果的前 10 个。现在假设我们请求第 1000 页--结果从 10001 到 10010 。所有都以相同的方式工作除了每个分片不得不产生前10010个结果以外。 然后协调节点对全部 50050 个结果排序最后丢弃掉这些结果中的 50040 个结果。可以看到,在分布式系统中,对结果排序的成本随分页的深度成指数上升。这就是 web 搜索引擎对任何查询都不要返回超过 1000 个结果的原因。

 

took字段代表的这次搜索的响应时间。

shards 部分告诉我们在查询中参与分片的总数,以及这些分片成功了多少个失败了多少个。正常情况下我们不希望分片失败,但是分片失败是可能发生的。如果我们遭遇到一种灾难级别的故障,在这个故障中丢失了相同分片的原始数据和副本,那么对这个分片将没有可用副本来对搜索请求作出响应。假若这样,Elasticsearch 将报告这个分片是失败的,但是会继续返回剩余分片的结果。

timed_out字段告诉我们查询是否超时。默认情况下,搜索请求不会超时。但如果低响应时间比完成结果更重要,可以指定 timeout超时时间

例:

GET 127.0.0.1:9200/_search?timeout=10ms

这样的话,在搜索超时之前,ES会返回每个分片中已经查询到的结果,

在请求超时之前,Elasticsearch 将会返回已经成功从每个分片获取的结果。 但timeout 不是停止执行查询,它仅仅是告知正在协调的节点返回到目前为止收集的结果并且关闭连接。在后台,其他的分片可能仍在执行查询即使是结果已经被发送了。

 

二 指定索引以及类型

如果想在一个或多个特殊的索引并且在一个或者多个特殊的类型中进行搜索。我们可以通过在URL中指定特殊的索引和类型达到这种效果。

  • GET 127.0.0.1:9200/_search

在所有的索引中搜索所有的类型

  • GET 127.0.0.1:9200/test/_search

在 test索引下搜索所有的类型

  • GET 127.0.0.1:9200/test1,test2/_search

在 test1 和 test2 中搜索。

 

除了指定索引,指定类型的方式和指定索引是一样的

  • 127.0.0.1/9200/test/test/_search

在索引test,类型test下搜索所有文档

 

ES还提供了‘*’作为通配符

  • GET 127.0.0.1:9200/t*/_search

在所有以t开头的索引下搜索

  • GET 127.0.0.1:9200/*/test/_search

在所有索引下的test的类型下搜索

 

三 轻量搜索

ES提供两种形式的搜索API ,一种是轻量的:查询字符串版本,另一种则是更完整的请求体版本。

先来说一下轻量搜索:查询字符串版本,这种查询方式要求在查询字符串中传递所有的参数。这种方式非常适用于通过命令行做即席查询。

这种搜索方式的结构为

ip:port/_search?q=查询字符串

查询字符串的生成是对以下规则生成的字符串做一次urlEncode

1、若想要查询某个字段包含某个单词的所有文档

+name:xx

表示为查询name字段包含xx的所有文档

2、多个条件之间用空格分割

+name:xx +age:20

表示为查询name包含xx且age包含20的所有文档

3、+ 前缀表示必须与查询条件匹配, - 前缀表示一定不与查询条件匹配。没有 + 或者 - 的所有其他条件都是可选的,匹配的越多,文档就越相关。

+name:xx -age:>20

表示为name包含xx并且排除age>20的所有文档

4、对_all字段查询,,ES会取出一个文档所有字段的值拼接成一个大的字符串,作为 _all 字段进行索引

+(xx)

表示查询所有包含xx的文档

 

复杂查询示例

+name:(xx yy) +age:>20 +(football basketball)

表示 查询name属性为xx 或yy 且age属性>20 ,且所有文档内容包含football 或者basketball的文档

编码后的查询字符串为

%2Bname%3A%28xx+yy%29+%2Bage%3A%3E20+%2B%28football+basketball%29

查询请求为

GET 127.0.0.1:9200/_search?q=%2Bname%3A%28xx+yy%29+%2Bage%3A%3E20+%2B%28football+basketball%29

 

从中,我们可以看出轻量搜索可以通过简洁的查询字符串表达很复杂的查询。对于通过命令做一次性查询,或者是在开发阶段,都非常方便。

但是,这种精简让调试更加晦涩和困难。而且很脆弱,一些查询字符串中很小的语法错误,像 - , : , / 或者 " 不匹配等,将会返回错误而不是搜索结果。

最后,查询字符串搜索允许任何用户在索引的任意字段上执行可能较慢且重量级的查询,这可能会暴露隐私信息,甚至将集群拖垮。

所以结论是除非是非常信任用户,否则不推荐直接向用户暴露查询字符串功能。