es总结4

Search API

URI Search : 在URL中使用查询参数

Request Body Search : 使用 Elasticsearch提供的,基于JSON格式的更加完备的 Query Domain Specific Language(DSL)

指定查询的索引

avatar

URI查询

  • 使用 “q” ,指定查询字符串
  • “query string syntax”, KV 键值对
1
curl -XGET "http://localhost:9200/index1/_search?q=name:dog"

Request Body

avatar

搜索Response

avatar

URI Search字段解释

avatar

Query String Sytax

  • 指定字段 v.s 泛查询 : q=title:2012 /q=2012
  • Term v.s Phrase
    • Beautiful Mind 等效于 Beautiful OR Mind
    • “Beautiful Mind”, 等效于 Beautiful AND Mind。 Phrase查询,还要求前后顺序保持一致。
  • 分组与引号
    • title:(Beautiful AND Mind)
    • title=”Beautiful Mind”
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
//带profile
GET /movies/_search?q=2012&df=title
{
"profile":"true"
}

//泛查询,正对_all,所有字段
GET /movies/_search?q=2012
{
"profile":"true"
}

//指定字段
GET /movies/_search?q=title:2012
{
"profile":"true"
}

//使用引号,Phrase查询
GET /movies/_search?q=title:"Beautiful Mind"
{
"profile":"true"
}

//Mind为泛查询
GET /movies/_search?q=title:Beautiful Mind
{
"profile":"true"
}

//分组, Bool查询
GET /movies/_search?q=title:(Beautiful Mind)
{
"profile":"true"
}

//分组, Bool查询
GET /movies/_search?q=title:(Beautiful Mind)
{
"profile":"true"
}

Query String Syntax2

  • 布尔操作
    • AND / OR / NOT 或者 && / || / !
    • 必须大写
    • title:(matrix NOT reloaded)
  • 分组
    • +表示 must
    • -表示 must_not
    • title:(+matrix -reloaded)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
GET /movies/_search?q=title:(Beautiful AND Mind)
{
"profile":"true"
}

GET /movies/_search?q=title:(Beautiful OR Mind)
{
"profile":"true"
}

GET /movies/_search?q=title:(Beautiful %2BMind)
{
"profile":"true"
}

Query String Syntax3

  • 范围查询
    • 区间表示: []闭区间,{}开区间
    • year:{2019 TO 2020}
    • year:[* TO 2020]
  • 算数符号
    • year :>2010
    • year:(>2010 && <= 2018)
    • year:(+>2010 +<2018>)
1
2
3
4
GET /movies/_search?q=year>=1980
{
"profile":"true"
}

Query String Syntax4

  • 通配符查询(通配符查询效率低,占用内存大,不建议使用。特别放在最前面)
    • ?代表一个字符,*代表0或者多个字符
    • title:mi?d
    • title:be*
  • 正则表达
    • title:[bt]oy
  • 模糊匹配与近似查询
    • title:befutifl~1
    • title:”lord rings”~2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
GET /movies/_search?q=title:b*
{
"profile":"true"
}

GET /movies/_search?q=title:befutifl~1
{
"profile":"true"
}

GET /movies/_search?q=title:"lord rings"~2
{
"profile":"true"
}

RequestBody与QueryDSL简介

Query-string 搜索通过命令非常方便地进行临时性的即席搜索 ,但它有自身的局限性(参见 轻量 搜索 )。Elasticsearch 提供一个丰富灵活的查询语言叫做 查询表达式 , 它支持构建更加复杂和健壮的查询。

领域特定语言 (DSL), 使用 JSON 构造了一个请求。我们可以像这样重写之前的查询所有名为 Smith 的搜索 :

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
PUT /megacorp/_doc/1
{
"first_name" : "John",
"last_name" : "Smith",
"age" : 25,
"about" : "I love to go rock climbing",
"interests": [ "sports", "music" ]
}

PUT /megacorp/_doc/2
{
"first_name" : "Jane",
"last_name" : "Smith",
"age" : 32,
"about" : "I like to collect rock albums",
"interests": [ "music" ]
}

PUT /megacorp/_doc/3
{
"first_name" : "Douglas",
"last_name" : "Fir",
"age" : 35,
"about": "I like to build cabinets",
"interests": [ "forestry" ]
}

GET /megacorp/_search?q=last_name:Smith


GET /megacorp/_search
{
"query" : {
"match" : {
"last_name" : "Smith"
}
}
}
  • 将 查询语句通过HTTP Request Body 发送给Elasticsearch
  • Query DSL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
GET /megacorp/_search
{
"query" : {
"bool": {
"must": {
"match" : {
"last_name" : "smith"
}
},
"filter": {
"range" : {
"age" : { "gt" : 30 }
}
}
}
}
}

分页

  • from 从0开始,默认返回10个结果
  • 获取靠后的翻页成本较高
1
2
3
4
5
6
7
8
POST /myindex/_search
{
"from":10,
"size":20,
"query":{
"match_all":{}
}
}

排序

  • 最好在“数字型”与“日期型”字段上排序
  • 因为对于多值类型或分析过的字段排序,系统会选一个值,无法得知该值。
1
2
3
4
5
6
7
8
9
POST /myindex/_search
{
“sort”:[{"order_date":"desc"}]
"from":10,
"size":20,
"query":{
"match_all":{}
}
}

_source filtering

  • 如果_source没有存储,那就只返回匹配的文档的元数据
  • _source支持使用通配符, _source[“name“,”desc“]
1
2
3
4
5
6
7
8
9
10
POST /myindex/_search
{
"_source":["order_date","category.keyword"]
“sort”:[{"order_date":"desc"}]
"from":10,
"size":20,
"query":{
"match_all":{}
}
}

Simple Query String Query

1
2
3
4
5
6
7
8
9
10
POST /myindex/_search
{
"query":{
"simple_query_string":{
"query":"category",
"fields":["name"],
"default_operator":"AND"
}
}
}
  • 类似Query String,但是会忽略错误的语法,同时只支持部分查询语法
  • 不支持 AND OR NOT,会当作字符串处理
  • Term之间默认的关系是OR,可以指定Operator,
  • 支持部分逻辑 +替代 AND,|替代OR,-替代NOT

整体小结

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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
PUT /megacorp/_doc/1
{
"first_name" : "John",
"last_name" : "Smith",
"age" : 25,
"about" : "I love to go rock climbing",
"interests": [ "sports", "music" ]
}

PUT /megacorp/_doc/2
{
"first_name" : "Jane",
"last_name" : "Smith",
"age" : 32,
"about" : "I like to collect rock albums",
"interests": [ "music" ]
}

PUT /megacorp/_doc/3
{
"first_name" : "Douglas",
"last_name" : "Fir",
"age" : 35,
"about": "I like to build cabinets",
"interests": [ "forestry" ]
}

GET /megacorp/_search?q=last_name:Smith

GET /megacorp/_search
{
"query" : {
"match" : {
"last_name" : "Smith"
}
}
}

#复杂搜索
GET /megacorp/_search
{
"query" : {
"bool": {
"must": {
"match" : {
"last_name" : "smith"
}
},
"filter": {
"range" : {
"age" : { "gt" : 30 }
}
}
}
}
}
#全文搜索
GET /megacorp/_search
{
"query" : {
"match" : {
"about" : "rock climbing"
}
}
}

#短语搜索
GET /megacorp/_search
{
"query" : {
"match_phrase" : {
"about" : "rock climbing"
}
}
}

# 高亮搜索
GET /megacorp/_search
{
"query" : {
"match_phrase" : {
"about" : "rock climbing"
}
},
"highlight": {
"fields" : {
"about" : {}
}
}
}

PUT megacorp/_mapping/
{
"properties": {
"interests":{
"type":"text",
"fielddata": true
}
}
}

GET /megacorp/_search
{
"aggs": {
"all_interests": {
"terms": { "field": "interests" }
}
}
}

GET /megacorp/_search
{
"query": {
"match": {
"last_name": "smith"
}
},
"aggs": {
"all_interests": {
"terms": {
"field": "interests"
}
}
}
}

GET /megacorp/_search
{
"aggs" : {
"all_interests" : {
"terms" : { "field" : "interests" },
"aggs" : {
"avg_age" : {
"avg" : { "field" : "age" }
}
}
}
}
}

Mapping

什么是Mapping

  • Mapping 类似数据库中的schema的定义,作用如下

    • 定义索引中的字段的名称
    • 定义字段中的数据类型,例如字符串,数字,布尔…
    • 字段,倒排索引的相关配置,(Analyzed or Not Analyzed, Analyzer)
  • Mapping 会把JSON文档映射成Lucence所需要的扁平格式

  • 一个Mapping属于一个索引的Type
    • 每个文档都属于一个Type
    • 一个Type有一个Mapping定义
    • 7.0开始,不需要在Mapping定义中指定type的信息

字段的数据类型

  • 简单类型
    • Text/Keyword
    • Date
    • Integer/Floating
    • Boolean
    • IPv4 & IPv6
  • 复杂类型
    • 对象类型/嵌套类型
  • 特殊类型
    • geo_point & geo_shape/percolator

什么是Dynamic Mapping

  • 在写入文档时候,如果索引不存在,会自动创建索引
  • Dynamic Mapping的机制,使得我们无需手动定义Mappings。ElasticSearch会自动根据文档信息,推算出字段的类型。
  • 但是有时候会推算的不对,例如地理位置信息
  • 当类型如果设置不对时,会导致一些功能无法正常运行,例如Range查询。

avatar

能否更改Mapping的字段类型

  • 两种情况
    • 新增加字段
      • Dynamic 设置为true时,一旦有新增字段的文档写入,Mapping也同时被更新
      • Dynamic 设置为false时,Mapping不会被更新,新增字段的数据无法被索引,但是信息会出现在 _source 中
      • Dynamic 设置为strict时,文档写入失败
    • 对已有字段, 一旦有数据写入,就不再支持修改字段定义
      • Lucence实现的倒排索引,一旦生成后,就不允许修改
    • 如果希望改变字段类型,必须Reindex API,重建索引
  • 原因
    • 如果修改了字段的数据类型,会导致已被索引的属于无法被索引
    • 但是如果是新增的字段, 就没有这样的影响。

显式Mapping设置与常见参数介绍

定义一个mapping

1
2
3
4
5
6
PUT movies
{
"mappings":{
// define your mapping
}
}

自定义mapping的建议

  • 可以参考API手册,纯手写
  • 为了减少输入的工作量,减少出错率,可以依照以下步骤
    • 创建一个临时的index,写入一些样本数据
    • 通过访问Mapping API获得该临时文件的动态Mapping定义
    • 修改后用,使用该配置创建你的索引
    • 删除临时索引

控制当前字段是否被索引

  • index 控制当前字段是否被索引。默认为true,如果设置成false,该字段不可被索引。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
PUT users
{
"mappings":{
"properties":{
"firstName":{
"type":"text"
},
"lastName":{
"type":"text"
},
"mobile":{
"type":"text",
"index":false
}
}
}
}

Index Options

  • 四种不同级别的Index Options配置,可以控制倒索引记录的内容
    • docs 记录 doc id
    • freqs 记录 doc id 和term frequencies
    • positions 记录doc id /term frequencies/ term position
    • offset 记录 doc id /term frequencies /term position / character offects
  • Text 类型默认记录positions,其他默认为docs
  • 记录内容越多,占用存储空间越大
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
PUT users
{
"mappings":{
"properties":{
"firstName":{
"type":"text"
},
"lastName":{
"type":"text"
},
"mobile":{
"type":"text",
"index":false
}
"bio":{
"type":"text",
"index_options":"offsets"
}
}
}
}

null_value

  • 需要对Null值实现搜索
  • 只有Keyword类型支持设置Null_Value
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
PUT users
{
"mappings":{
"properties":{
"firstName":{
"type":"text"
},
"lastName":{
"type":"text"
},
"mobile":{
"type":"text",
"null_value":"NULL"
}
}
}
}

GET users/_search?q=mobile:NULL

"_source":{
"firstName":"test",
"lastName":"last",
"mobile":null
}

copy_to设置

  • _all在7中被copy_to所替代
  • 满足一些特定的搜索需求
  • copy_to将字段的数值拷贝到目标字段,实现类似_all的作用
  • copy_to的目标字段不出现在_source中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
PUT users
{
"mappings":{
"properties":{
"firstName":{
"type":"text"
"copy_to":"fullName"
},
"lastName":{
"type":"text"
"copy_to":"fullName"
}
}
}
}

数组类型

  • Elasticsearch中不提供专门的数组类型。但是任何字段,都可以包含多个相同类型的值
1
2
3
4
5
6
7
8
9
10
PUT users/_doc/1
{
"name":"onebird",
"interests":"reading"
}
PUT users/_doc/2
{
"name":"onebird",
"interests":["reading","music"]
}