上机实操:ES查询语法


es查询语法

Searchtimeout

  1. 默认没有timeout,如果设置了timeout,name会执行timeout机制。

  2. timeout机制:假设用户查询结果有1W条数据,但是需要10s才能查询完毕,但是用户设置了1s的timeout,name不管当前以供查询到了多少数据,都会在1s后ES将停止查询,并返回当前数据。

ES查询

  1. queryString查询
    类似URL传参的形式

1
2
3
4
5
6
7
8
GET /index/_search

GET /index/_doc/_search?q=name:xiaomi(有相关度分数_score)

GET /index/_search?from=0&size=2&sort=price:asc(无相关度分数_score)

GET /index/_search?from=0&size=20

tips:

types removal specifying types in search requests is deprecated
7.X 还能用, 8.X已删除

为什么加了排序,没有相关度分数?

答:默认按照_score 排序,如果使用了sort 这个时候_score:null

  1. query DSL

如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
//查询全部 match_all

GET /index/_search
{
"query":{
"natch_all":{}
}
}
//匹配查询 match

GET /index/_search
{
"query":{
"match":{
"name":"xiaomi"
}
}
}
// 排序 sort

GET /index/_search
{
"query":{
"match":{
"name":"xiaomi"
}
},
"sort":[
{
"price":"desc"
}
]
}
//多字段匹配 multiples match

GET /index/_search{
"query":{
"multi_match":{
"query": "xiaomi",
"fields":["name","desc"]
}
},
"sort":[
{
"price":"desc"
}
]
}
//_source 元数据(指定字段)
GET /index/_search{
"query":{
"match":{
"name":"xiaomi"
}
},
"_source":["name","price"]
}
//deep-paging分页

GET /index/_search
{
"query":{
"natch_all":{}
},
"from":0,
"size":20
}



  1. Full-text queries 全文检索
    1. query-term:不会被分词
      关键词作为一个完整的词,进行匹配查询
    2. match 和 term
      • match 的关键词会被分词后进行匹配查询,
      • term 的 关键词不会被分词,进行匹配查询
    3. 全文检索

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      全文检索
      GET /index/_search
      {
      "query":{
      "term":{
      "name":"xiaomi"
      }
      }
      }

      # term 关键词 不分词
      GET /index/_search
      {
      "query":{
      "bool":{
      "must":[
      {"term":{"name":"xiaomi"}},
      {"term":{"name":"phone"}}
      ]
      }
      }
      }

      # name in("xiaomi", "phone")

      GET /index/_search
      {
      "query":{
      "terms":{
      "name":["xiaomi","phone"]
      }
      }
      }



      # 默认分词器

      GET /_analyze
      {
      "analyzer": "standard"
      "test":"xiaomi nfc phone"
      }

GET 和 POST 也能查

  1. 短语搜索
1
2
3
4
5
6
7
8
GET /index/_search
{
"query":{
"match_phrase":{
"name":"xiaomi phone"
}
}
}
  1. query and filter 查询和过滤
    1. bool: 可以组合多个查询条件,bool查询也是采用more_matches_is_batter的机制,因此满足must和should的字句的文档将会合并起来计算分值。
      1. must:必须满足
      2. filter:过滤器 不计算相关度分数的(性能比must高),支持缓存
      3. should: 可能满足 or
      4. must_not:必须不满足 不计算相关度分数的
      5. minimum_should_match: 默认 1 ,配置should 里面必须匹配的条件数量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
GET /index/_search
{
"query":{
"bool":{
"must":[
{"match":{"name":"xiaomi"}},
{"match":{"desc":"shouji"}}
],
"filter":[
{"match_phrase":{"naem":"xiaomi"}},
{"range":{"price":{"gt":1999}}}

]
}
}
}

GET /index/_search
{
"query":{
"bool":{
"must":[

{"match":{"name":"xiaomi"}}
],
"must_not":[

{"match":{"name":"xiaomi"}}
],
"should":[

{"match":{"name":"xiaomi"}}
],
"filter":[
{"rang":{"price":{"gt":4999}}}
]
}
}
}

# filter 单独查询,结果不排序

GET /index/_search
{
"query":{
"constant_score":{
"filter":[
{"rang":{"price":{"gt":4999}}}
]
}
}
}



  1. 嵌套查询
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
GET /index/_search
{
"query":{
#去除相关度查询
"constant_score":{
"filter":[
"bool":{
"must":[

{"match":{"name":"xiaomi"}}
],
"must_not":[

{"match":{"name":"xiaomi"}}
],
"should":[

{"match":{"name":"xiaomi"}}
],
"filter":[
{"rang":{"price":{"gt":4999}}}
]
}
]
}
}
}

  1. 高亮查询
    匹配到的结果 高亮返回

Deep paging 问题

size 500
index 11
如: 用户查询 50条 价格 由低到高的数据

数据在不同保证的分片上。5个分片
每个分片 1W

都去取 5050 全部拿出来,进行排序,在去取,排完序后取50条数据

  • 数据大于1W ,不要使用
  • 返回数据数量不要大于1W

解决方法:

  1. 尽量避免
  2. 使用scroll search

scroll 游标
1m 开窗期:1分钟时间到了,就不能查询了

1
2
3
4
5
6
7
8
GET /index/_search?scroll=1m
{
"query"{
"match_all":{}
},
"sort":[{"price":"asc"],
"size":2
}

会返回 scroll_id 标记 最后查询的位置

下一次查询,如下:

1
2
3
4
5
6
GET /_search/scroll
{
"scroll":1m # 第二次查询的时候更新这个到期时间
"scroll_id" :"SD9SU92398HR29SHH929X7" #每一次查询必须带上前一次的ID
}

filter 缓存

  1. filter不是每次执行否会进行缓存,而是当执行一定次数的时候才会进行cache一个二进制数组,1表示匹配,2表示不匹配,这个次数是不固定的。
  2. filter会从有限过滤掉稀疏的数据中,保留匹配的cache数组。
  3. filter cache 保存的是匹配的结果,不需要再从倒排索引中去查找比对,大大涂改可查询速度,
  4. filter 一般会在query之前执行,过滤掉一部分数据,从而提高query的速度
  5. filter不计算相关度分数,在执行效率上比query高。
  6. 当元数据发生改变时,cache也会更新。

filter没有匹配度查询

mapping

概念:mapping 就是ES数据字段field的type元数据,ES在创建索引的时候,dynamic mapping会自动为不同的数据指定相应mapping,mapping中包含了字段的类型、搜索方式(exact value或者full text)、分词器等。

1
2
3
4
PUT /index/_doc/100
{
"name":123
}
1
2
GET /product/_mapping/type(旧)
GET /product/_mapping*s*(新)

如果 字段属性 类型是text ,会默认keyword 的type是keyword 关键词长度是256后忽视

  1. Dynamic mapping

    1. “Elasticsearch” : text/keyword
    2. 123456 => long ? 为啥不是integer
    3. 123.123 => double
    4. true => boolean
    5. 2020-05-30 => date
      为啥price是long类型而不是integer类型,因为es的mapping_type 是由json分析器检测数据类型,而json没有隐式类型转换(integer=>long or float => double),所以dynamic mapping 会选择比较宽的数据类型
  2. 搜索方式

    1. exact value 精确匹配: 在倒排索引过程中,分词器会将field作为一个整体创建到索引中,

    注短语搜索:关键词作为整体匹配

    1. full text 全文索引: 分词、近义词同义词、混淆词、大小写、过滤、时态转换等(normalzition)

      exact value 类型字段 必须完全匹配 如:date 类型
      string 的 text 是 full text,keyword 是 exact value

  3. ES 数据类型

    1. 核心类型
      1. 数字类型
        • long/integer/short/byte/float/half_foat/scaled_float
      2. 字符串:string
        • keyword: 适用于索引结构化的字段,可以用于过滤、排序、聚合。keyword类型的字段只能通过精确值(exact value) 搜索到。如id应该用keyword
        • text: 当一个字段是要被全恩搜索的,比如email内容、产品描述,这些字段应该使用text类型。设置text类型以后,字段内容会被分析,在生成倒排序索引以前,字符串会被分析器分恒一个一个词项。text类型的字段不用于排序,很少用于聚合
        • 有时,在同一个字段汇总同时具有全文和关键词版本会很有用,一个用于全文本搜索,另一个用于聚合和排序。
      3. date
      4. 布尔类型
      5. binary:二进制
      6. range(区间类型):integer_range/float_range/long_range/double_range/date_range
      7. 复杂类型
        1. object:用于单个JSON字符串
        2. Nested: 用于JSON字符串数组
      8. 地理位置
      9. 特有类型
        1. Array
  4. 创建mapping

1
2
3
4
5
6
7
8
9
10
PUT /index
{
"mappings":{
"properties":{
"create_date":{
"type":"date"
}
}
}
}

索引、名字、字段 一律小写

  1. mapping parameters
    1. index:是否创建对当前字段创建索引,默认 true,如果不创建索引,该字段不会被通过这个字段检索数据。
    2. analyzer: 指定分析器(character filter、tokenizer、Token filter)
    3. coerce: 是否允许被强制类型转换
    4. bost:权重 默认1,权重
    5. copy_to:
    6. doc_value:为了提高排序和聚合效率,默认true。如果确定不需要对字段进行排序或聚合,也不需要通过脚本访问字段值,呢可以禁用doc值一节省磁盘空间(不支持text和annotated_text),如果不需要聚合查询,可以设置为false,提高查询效率,如果设置成false,不能再改了, 如果想改,只能重新创建索引。
    7. dynamic: 控制是否可以动态添加新字段
      1. true新检测到的字段将添加到映射中。(默认)
      2. false 新检测到的字段将被忽略,这些字段将不会被索引,因此将无法搜索,单人会出现在_source返回的匹配相中,这些字段不会添加到映射总,必须显示添加新字段。
      3. strict如果检测到新字段,则会引发异常并拒绝文档。必须将新字段显示添加到映射中。
    8. eager_global_ordinals: 用于集合的字段上,优化聚合性能。
    9. enable:是否创建倒排索引,可以对字段操作。
    10. fielddate:查询是内存数据结构,在首次用当前字段聚合、排序或者在脚本中使用时,需要字段为fielddata数据结构,并且创建正排索引保存到堆中。
    11. fields: 给filed创建多个字段,用于不同目的(全文检索或聚合分析排序)
    12. format: 格式化 如果date 的格式化
    13. norms: 是否禁用评分(filter和聚合字段上应该禁用)
    14. null_value: 为null 设置默认值
    15. search_analyzer: 单独设置查询时分析器
    16. similarity: 相关度算法。
    17. …(其他看官网)

聚合搜索

  1. bucket 和 metirc
  2. 语法
    1
    2
    3
    aggs:{

    }
  3. “group by”:
    {

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
GET /index/_search
{
"query":{},
"aggs":{
#聚合查询的名字,自定义
"name":{
"terms":{
"field":"tags.keyword" #test类型本身不支持聚合,推荐用 keyword聚合 ,(mapping 的 fielddata性能低)
}
}
},
"size":0 #只显示聚合查询结果

}
  1. avg
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
GET /index/_search
{
"aggs":{
"avg":{
"terms":{
"field":"tags.keyword",
"order":{
"_term":"asc"
}
},
"aggs":{
"avg_price":{
"avg":{
"filed":"price"
}
}
}
}
},
size:0
}
  1. 分组查询
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
GET /index/_search
{
"aggs":{
"tag_agg_grup":{
"range":{
"field":"price",
"ranges":[
{
"from": 100,
"to":1000
},
{
"from": 2000,
"to":3000
},
{
"from": 3000,
"to":4000
},

]
},
"aggs":{
"price_agg":{
"avg":{
"field":"price"
}
}
}

}
},
size:0
}

文章作者: TheMoonLight
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 TheMoonLight !
评论
  目录