Elasticsearch-16-_search搜索详解

multi-index和multi-type搜索模式

就是一次性搜索多个index和type下的数据

示例
  1. 搜索所有index,所有type下的所有数据

    1
    GET /_search
  2. 指定一个index,搜索其下所有的type的数据

    1
    GET /index/_search
  3. 查询某个index下指定的type的数据

    1
    GET /index/type/_search
  4. 同时搜索多个index下的所有数据

    1
    GET /index1,index2,index3,.../_search
  5. 按照通配符去匹配多个index

    1
    2
    GET /*1,*2/_search
    # 查询以 1 和 2 结尾的index
  6. 搜索一个index下指定的多个type的数据

    1
    GET /index/type1,type2/_search
  7. 搜索多个index下的多个type的数据

    1
    GET /index1,index2/type1,type2/_search
  8. 搜索所有index下的指定type的数据

    1
    GET /_all/type1,type2/_search

搜索原理

客户端发送一个请求,会把请求打到所有的primary shard上去执行,因为每个shard都包含部分数据,所以每个shard上都可能包含搜索请求的结果
但是如果primary shard有replica shard,那么请求也可以打到replica shard上面

分页搜索

查询时传入参数 size 和 from 即可

示例

比如我们要查询movies/movie下的数据一共是6条,分三页查询

1
2
3
4
5
6
7
8
# 查询第一页
GET /movies/movie/_search?size=2&from=0

# 查询第二页
GET /movies/movie/_search?size=2&from=2

# 查询第三页
GET /movies/movie/_search?size=2&from=4

from 是从0开始的

deep paging问题

什么是deep paging问题? 为什么会产生这个问题? 他的底层原理是什么?

场景,比如我们现在有4个shard 一共有60000条数据,在其中3个shard中,每个有20000条数据,这个时候要进行搜索第1000页的数据,每页显示10条,实际上这里拿到的是第10001~10010条数据

假设这个请求先打到一个不包含这些数据的节点上去,那么这个节点就是一个协调节点(coordinate node),然后这个协调节点会将请求转发到包含数据的节点上去,如图:

分页查询

查询60000条数据中的第1000页,实际上每个shard都要将内部的20000条数据中的1000页,也就是10001~10010条的数据拿出来, 这时候实际上不是只返回这10条数据 是返回第一条到10010条数据, 3个shard都返回10010条数据给coordinate node,coordinate node 总共会受到30030条数据,然后进行排序,在这30030条数据中取到第10页,也就是这些数据中的第10001~10010条数据返回.

分页查询2

总的来说就是先要把所有shard上的数据集中起来排序后再去分页.

搜索过深的时候,就要在coordinate node上保存大量的数据,还要进行排序,排序之后,再取出对应的那一页,所以这个过程,既耗费网络带宽,耗费内存,还耗费CPU,影响性能,我们应该尽量避免出现这种deep paging的操作

query string

其实就是在http请求中,把一些搜索的参数做为query string附加到url上面.

示例

查询 /movies/movie 下title包含kill这个词的数据

1
GET /movies/movie/_search?q=title:kill

查询 /movies/movie 下title必须包含kill这个词的数据

1
GET /movies/movie/_search?q=+title:kill

查询/movies/movie 下title不包含kill这个词的数据

1
GET /movies/movie/_search?q=-title:kill

其实第一个和第二个的作用是差不多的,主要是 “+” 和 “-“ 的区别 一个是必须包含,一个是不包含

_all metadata 原理和作用

查询所有filed下包含kill的数据

1
GET /movies/movie/_search?q=kill

上面这个查询中并没有指定具体是哪个field包含kill这个词,是直接搜索的所有field的.
当我们添加一个document的时候,它里面包含了多个field,此时es会自动将多个field的值,用字符串的方式串联起来,变成一个长字符串,作为_all 的值,同时对 _all进行分词建立索引.
当我们搜索没有指定具体哪一个field的时候,就默认对_all 进行搜索,其实它里面就包含了所有field的值

举例说明

我们新添加一个document,内容是

1
2
3
4
5
6
{
"name":"jack",
"age":26,
"email" : "jack@sina.com",
"address":"hangzhou"
}

“jack 26 jack@sina.com hangzhou”,就作为这一条document的_all元数据的值,同时进行分词后建立对应的倒排索引