映射操作
有了索引库,等于有了数据库中的 database。接下来就需要建索引库(index)中的映射了,类似于数据库(database)中的表结构(table)。
创建数据库表需要设置字段名称,类型,长度,约束等;索引库也一样,需要知道这个类型下有哪些字段,每个字段有哪些约束信息,这就叫做映射(mapping)。
创建映射
在 Postman 中,向 ES 服务器发 PUT 请求 :http://127.0.0.1:9200/student/_mapping
(在创建隐射之前应先保证 student
已经创建成功)
- 请求体内容为:
{ "properties": { "name":{ "type": "text", "index": true }, "sex":{ "type": "text", "index": true }, "age":{ "type": "long", "index": true } } }
- 结果如下:
- 服务器响应结果如下:
隐射数据说明:
-
字段名:任意填写
-
type:类型,Elasticsearch 支持的数据类型
- String 类型:text(可分词) 和 keyword(不可分词,即数据作为完整字段进行匹配)
- Numerical 数值类型:
- 基本类型:long、integer、short、byte、double、float、half_float
- 浮点数的高精度类型:scaled_float
- Date: 日常类型
- Array:数组类型
- Object:对象
-
index 是否索引,默认为 true,表示该字段可以被索引
- true:字段会被索引,则可以用来进行搜索
- false:字段不会被索引,不能用来搜索
-
store:是否将数据进行独立存储,默认为 false
原始的文本会存储在_source
里面,默认情况下其他提取出来的字段都不是独立存储的,是从_source
里面提取出来的。当然你也可以独立的存储某个字段,只要设置"store": true
即可,获取独立存储的字段要比从_source
中解析快得多,但是也会占用更多的空间,所以要根据实际业务需求来设置。
查看映射
- 在 Postman 中,向 ES 服务器发 GET 请求 :
http://127.0.0.1:9200/student/_mapping
- 结果如下:
隐射关联索引
- 在 Postman 中,向 ES 服务器发 PUT 请求 :
http://127.0.0.1:9200/student1
,传入json数据如下即在body中定义mappings
用来关联相应的隐射:
{
"settings": {},
"mappings": {
"properties": {
"name":{
"type": "text",
"index": true
},
"sex":{
"type": "text",
"index": false
},
"age":{
"type": "long",
"index": false
}
}
}
}
- 结果如下:
_source、_all、store和index 的区别
如图所示, 第二象限是一份原始文档,有 title 和 content 2个字段,字段取值分别为”我是中国人”和” 热爱共产党”。我们把原始文档写入Elasticsearch,默认情况下,Elasticsearch里面有2份内容。
_source
-
一份是原始文档,也就是 _source 字段里的内容;存储数据如下所示:
-
一份是 倒排索引,倒排索引中的数据结构是倒排记录表,记录了词项和文档之间的对应关系,比如关键词”中国人”包含在文档ID为1的文档中,倒排记录表中存储的就是这种对应关系,当然也包括词频等更多信息。
-
如果先要关闭 source 字段,设置如下:
{ "yourtype":{ "_source":{ "enabled":false }, "properties": { ... } } }
-
如果只想存储某几个字段的原始值到Elasticsearch,可以通过incudes参数来设置,在mapping中的设置如下:
{ "yourtype":{ "_source":{ "includes":["field1","field2"] }, "properties": { ... } } }
-
同样,可以通过excludes参数排除某些字段:
{ "yourtype":{ "_source":{ "excludes":["field1","field2"] }, "properties": { ... } } }
文档索引 index
- 当文档索引到Elasticsearch的时候,默认情况下是对所有字段创建倒排索引的(动态mapping解析出来为数字类型、布尔类型的字段除外),某个字段是否生成倒排索引是由字段的index属性控制的,在Elasticsearch 7之前,index属性的取值有2个,true or false。
_all 字段
_all
字段里面包含了一个文档里面的所有信息,是一个超级字段。以图中的文档为例,如果开启_all
字段,那么title+content
会组成一个超级字段,这个字段包含了其他字段的所有内容,当然也可以设置只存储某几个字段到_all
属性里面或者排除某些字段。- 开启
_all
字段{ "yourtype": { "_all": { "enabled": true }, "properties": { ... } } }
- 指定某些字段成为
_all
字段{ "yourtype": { "properties": { "field1": { "type": "string", "include_in_all": false }, "field2": { "type": "string", "include_in_all": true } } } }
词项的角色转换
- 图一的第一象限,用户输入关键词" 中国人",分词以后,Elasticsearch从倒排记录表中查找哪些文档包含词项"中国人 ", 注意变化,分词之前" 中国人"是用户查询(query),分词之后在倒排索引中" 中国人"是词项(term)。Elasticsearch根据文档ID(通常是文档ID的集合)返回文档内容给用户,如图一第四象限所示。
是否单独存储 store
-
es 的 store 表示是否存储该字段。不存储的话无法展示。默认的
store
属性就是no
,然而我们依然能够检索出所有的字段,原因是还有一个_source
字段,这个字段存储了我们index
的时候的全部属性,所以我们可以通过解析 `source来获得里面的字段,如果我们不指定field的话,甚至不需要解析直接返回整个source。 -
store = yes 会对这个字段做单独存储,es除了构建倒排索引,还会构建一个存储域,倒排索引用来做查询命中文档id,存储域用来存放写入的具体文档.
-
如果store=yes则是将这个 field 单独存储到一个存储域中,因此使用field获取字段的时候不走source,会去额外的区域获取字段值. 当然我们也可以指定从哪个区域取:
GET my_index/_search { "stored_fields": [ "title", "date" ] }
-
可以理解为 store=yes,其实就是用一个新的空间来存储某个字段内容,方便检索时直接返回。避免了从source中进行全局的搜索
-
注意: 如果想要对某个字段实现高亮功能,
_source
和store
至少保留一个。下面会给出测试代码。 -
如果将
_all
字段进行存储:PUT test/test/_mapping { "test": { "_all": { "enabled": true, "store": true } } }
高亮数据
利用 source中的 all 完成高亮搜索
- 首先插入文档
POST test/test/1 { "title":"我是中国人", "content":"热爱共产党" }
- 对
_all
进行搜索并且高亮
结果如下:POST test/_search { "fields": ["_all"], "query": { "match": { "_all": "中国人" } }, "highlight": { "fields": { "_all": {} } } }
{ "took": 3, "timed_out": false, "_shards": { "total": 5, "successful": 5, "failed": 0 }, "hits": { "total": 1, "max_score": 0.15342641, "hits": [ { "_index": "test", "_type": "test", "_id": "1", "_score": 0.15342641, "_all": "我是中国人 热爱共产党 ", "highlight": { "_all": [ "我是<em>中国人</em> 热爱共产党 " ] } } ] } }
- Elasticsearch中的query_string和simple_query_string默认就是查询_all字段
示例如下:GET test/_search { "query": { "query_string": { "query": "共产党" } } }
利用 store 完成高亮搜索
- 关闭
_source
且添加字段的store属性为 true,即用单独的空间进行存储DELETE test PUT test PUT test/test/_mapping { "test": { "_source": { "enabled": false }, "properties": { "title": { "type": "string", "index": "not_analyzed", "store": "true" }, "content": { "type": "string" } } } }
- 对 title 字段进行高亮搜索,如下:
GET test/_search { "query": { "match": { "title": "我是中国人" } }, "highlight": { "fields": { "title": {} } } } { "took": 6, "timed_out": false, "_shards": { "total": 5, "successful": 5, "failed": 0 }, "hits": { "total": 1, "max_score": 0.30685282, "hits": [ { "_index": "test", "_type": "test", "_id": "1", "_score": 0.30685282, "highlight": { "title": [ "<em>我是中国人</em>" ] } } ] } }
高级查询
1. 创建索引
# POST /student/_doc/1001
{
"name":"zhangsan",
"nickname":"zhangsan",
"sex":"男",
"age":30
}
# POST /student/_doc/1002
{
"name":"lisi",
"nickname":"lisi",
"sex":"男",
"age":20
}
# POST /student/_doc/1003
{
"name":"wangwu",
"nickname":"wangwu",
"sex":"女",
"age":40
}
# POST /student/_doc/1004
{
"name":"zhangsan1",
"nickname":"zhangsan1",
"sex":"女",
"age":50
}
# POST /student/_doc/1005
{
"name":"zhangsan2",
"nickname":"zhangsan2",
"sex":"女",
"age":30
}
2. 查询所有文档
- GET 请求 :http://127.0.0.1:9200/student/_search
{ "query": { "match_all": {} } } # "query":这里的 query 代表一个查询对象,里面可以有不同的查询属性 # "match_all":查询类型,例如:match_all(代表查询所有), match,term , range 等等 # {查询条件}:查询条件会根据类型的不同,写法也有差异
- 结果如下:
{ "took【查询花费时间,单位毫秒】" : 1116, "timed_out【是否超时】" : false, "_shards【分片信息】" : { "total【总数】" : 1, "successful【成功】" : 1, "skipped【忽略】" : 0, "failed【失败】" : 0 }, "hits【搜索命中结果】" : { "total"【搜索条件匹配的文档总数】: { "value"【总命中计数的值】: 3, "relation"【计数规则】: "eq" # eq 表示计数准确, gte 表示计数不准确 }, "max_score【匹配度分值】" : 1.0, "hits【命中结果集合】" : [ 。。。 } ] } }
3. 匹配查询
- match 匹配类型查询,会把查询条件进行分词,然后进行查询,多个词条之间是 or 的关系
- 在 Postman 中,向 ES 服务器发 POST 请求 :
http://127.0.0.1:9200/student/_search
{ "query":{ "match":{ "name":"zhangsan" } } }
4. 多字段匹配查询
-
multi_match 与 match 类似,不同的是它可以在多个字段中查询。 - 在 Postman 中,向 ES 服务器发 POST 请求 :
http://127.0.0.1:9200/student/_search
{ "query": { "multi_match": { "query": "zhangsan", "fields": ["name","nickname"] } } }
-
即查询name or nickname 中的 zhangsan
5. 关键字精确查询
- term 查询,精确的关键词匹配查询,不对查询条件进行分词。
在 Postman 中,向 ES 服务器发 POST请求 :http://127.0.0.1:9200/student/_search
{ "query": { "term": { "name": { "value": "zhangsan1" } } } }
- 结果如下:
6. 多关键字查询
- terms 查询和 term 查询一样,但它允许你指定多值进行匹配。
- 如果这个字段包含了指定值中的任何一个值,那么这个文档满足条件,类似于 mysql 的 in
- 在 Postman 中,向 ES 服务器发 POST 请求 :
http://127.0.0.1:9200/student/_search
{ "_source": ["name","nickname"], "query": { "terms": { "nickname": ["zhangsan","zhangsan1"] } } }
- 结果如下:
7. 过滤字段
- includes:来指定想要显示的字段
- excludes:来指定不想要显示的字段
- 在 Postman 中,向 ES 服务器发 POST请求 :
http://127.0.0.1:9200/student/_search
结果如下:{ "_source": { "includes": ["name","nickname"] }, "query": { "terms": { "nickname": ["zhangsan"] } } }
- 发送
exclude
请求,想ES 服务器发送 POST 请求:http://127.0.0.1:9200/student/_search
结果如下:{ "_source": { "excludes": ["name","nickname"] }, "query": { "terms": { "nickname": ["zhangsan"] } } }
8. 组合查询
bool
把各种其它查询通过must
(必须 )、must_not
(必须不)、should
(应该)的方式进行组合
在 Postman 中,向 ES 服务器发 POST 请求:http://127.0.0.1:9200/student/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"name": "zhangsan"
}
}
],
"must_not": [
{
"match": {
"age": "40"
}
}
],
"should": [
{
"match": {
"sex": "男"
}
}
]
}
}
}
9. 范围查询
-
range 查询找出那些落在指定区间内的数字或者时间。range 查询允许以下字符:
作符 说明 t 大于 > te 大于等于 >= t 小于 < te 小于等于 <= -
则向ES发送POST请求:
http://127.0.0.1:9200/student/_search
{ "query": { "range": { "age": { "gte": 30, "lte": 35 } } } }
10. 模糊查询
- 返回包含与搜索字词相似的字词的文档
- 用编辑距离
fuzziness
来衡量词与词之间的相似度,利用fuzzy
返回一定编辑距离内的字词文档。 - 编辑距离是将一个术语转换为另一个术语所需的一个字符更改的次数。这些更改可以包括:
- 更改字符(box → fox)
- 删除字符(black → lack)
- 更改字符(box → fox)
- 转置两个相邻字符(act → cat)
- 向 ES 服务器中发送 GET 请求:
http://127.0.0.1:9200/student/_search
{ "query": { "fuzzy": { "title": { "value": "zhangsan" } } } }
- 我们也可以增加编辑距离,如下:
{ "query": { "fuzzy": { "name": { "value": "zhangsan", "fuzziness": 2 } } } }
11. 单字段排序
sort 可以让我们按照不同的字段进行排序,并且通过 order 指定排序的方式。desc 降序,asc升序
。
- 在 Postman 中,向 ES 服务器发 POST请求 :
http://127.0.0.1:9200/student/_search
{ "query": { "match": { "name":"zhangsan" } }, "sort": [{ "age": { "order":"desc" } }] }
12. 多字段排序
- 假定我们想要结合使用 age 和 _score 进行查询,并且匹配的结果首先按照年龄排序,然后按照相关性得分排序
//http://127.0.0.1:9200/student/_search { "query": { "match_all": {} }, "sort": [ { "age": { "order": "desc" } }, { "_score":{ "order": "desc" } } ] }
13. 高亮查询
- 在进行关键字搜索时,搜索出的内容中的关键字会显示不同的颜色,称之为高亮。
- Elasticsearch 可以对查询内容中的关键字部分,进行标签和样式(高亮)的设置。
- 在使用 match 查询的同时,加上一个 highlight 属性:
- pre_tags:前置标签
- post_tags:后置标签
- fields:需要高亮的字段
- title:这里声明 title 字段需要高亮,后面可以为这个字段设置特有配置,也可以空
- 例子如下,发送ES请求
//post: http://127.0.0.1:9200/student/_search { "query": { "match": { "name": "zhangsan" } }, "highlight": { "pre_tags": "<font color='red'>", "post_tags": "</font>", "fields": { "name": {} } } }
- 服务器响应结果
14. 分页查询
- from:当前页的起始索引,默认从 0 开始。
from = (pageNum - 1) * size
- size:每页显示多少条
- 发送 POST search 请求
{ "query": { "match_all": {} }, "sort": [ { "age": { "order": "desc" } } ], "from": 0, "size": 2 }
- 结果如下,只显示两个:
15. 聚合查询
聚合允许使用者对 es 文档进行统计分析,类似与关系型数据库中的 group by
,当然还有很多其他的聚合,例如取最大值、平均值等等。
- 对某个字段取最大值 max
//:http://127.0.0.1:9200/student/_search { "aggs":{ "max_age":{ "max":{"field":"age"} } }, "size":0 }
- 对某个字段取最小值 min
//http://127.0.0.1:9200/student/_search { "aggs":{ "min_age":{ "min":{"field":"age"} } }, "size":0 }
- 对某个字段求和 sum
//http://127.0.0.1:9200/student/_search { "aggs":{ "sum_age":{ "sum":{"field":"age"} } }, "size":0 }
- 对某个字段取平均值 avg
{ "aggs":{ "avg_age":{ "avg":{"field":"age"} } }, "size":0 }
- 对某个字段的值进行去重之后再取总数
//对某个字段的值进行去重之后再取总数 { "aggs":{ "distinct_age":{ "cardinality":{"field":"age"} } }, "size":0 }
16. State 聚合
- stats 聚合,对某个字段一次性返回
count,max,min,avg 和 sum
五个指标//http://127.0.0.1:9200/student/_search { "aggs":{ "stats_age":{ "stats":{"field":"age"} } }, "size":0 }
- 结果如下:
17. 桶聚合查询
-
桶聚和相当于 sql 中的 group by 语句
-
terms 聚合,分组统计
// http://127.0.0.1:9200/student/_search { "aggs":{ "age_groupby":{ "terms":{"field":"age"} } }, "size":0 }
-
在 terms 分组下再进行聚合
{ "aggs":{ "age_groupby":{ "terms":{"field":"age"}, "aggs":{ "sum_age":{ "sum":{"field":"age"} }a } } }, "size":0 }