对比关系型数据库,创建索引就是创建数据库
创建索引:
在Postman中发PUT
请求:http://127.0.0.1:9200/index_name
{
"acknowledged": true, // 响应成功
"shards_acknowledged": true,
"index": "shoping"
}
在Postman中发GET
请求:http//127.0.0.1:9200/index_name
响应:
{
"shoping": {
"aliases": {},
"mappings": {},
"settings": {
"index": {
"routing": {
"allocation": {
"include": {
"_tier_preference": "data_content"
}
}
},
"number_of_shards": "1",
"provided_name": "shoping",
"creation_date": "1647768782140",
"number_of_replicas": "1",
"uuid": "AnHCrE-2SSG45KV5k_TNUQ",
"version": {
"created": "7150299"
}
}
}
}
}
在Postman中发GET
请求:http://127.0.0.1:9200/_cat/indices?v
响应如下:
在Postman中发DELETE
请求:http://127.0.0.1:9200/index_name
ElasticSearch中的文档可以类比关系型数据库中的表数据,添加的数据格式为JSON格式。
在Postman中发起POST
请求:http://127.0.0.1:9200/index_name/_doc
_doc并不指定,你创建文档的时候有可以_creat,过去之后仍然是_doc,因为在 ES 7.0 以后的版本 已经废弃文档类型Type了,一个 index 中只有一个默认的 type,即 _doc。
请求体内容:
{
"title":"小米手机",
"category":"小米",
"images":"http://xxx.com/xm.jpg",
"price":3999.00
}
这里只可以发起POST请求,如果发起PUT请求,会响应报错:
上面方法创建成功后会返回一个唯一的ID(这个是es随机生成的)
你可以指定id,当你指定了id之后,ElasticSearch就不会再自动生成了
在Postman中发起POST
请求:http://127.0.0.1:9200/index_name/_doc/id
{
"_index": "shopping",
"_type": "_doc",
"_id": "1001",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 1,
"_primary_term": 1
}
在Postman中发起GET
请求:http://127.0.0.1:9200/index_name/_doc/id
文档创建成功后会返回一个唯一的id(ElasticSearch随机生成的,也可以是你指定的)
1001是上面创建时指定的id。
{
"_index": "shopping",
"_type": "_doc",
"_id": "1001",
"_version": 3,
"_seq_no": 3,
"_primary_term": 1,
"found": true,
"_source": {
"title": "小米手机",
"category": "小米",
"images": "http://xxx.com/xm.jpg",
"price": 3999.00
}
}
如果查询的文档id不存在:
响应:
{
"_index": "shopping",
"_type": "_doc",
"_id": "2001",
"found": false
}
查询所有index中所有文档:
在Postman中发起GET
请求:http://127.0.0.1:9200/index_name/_search
{
"took": 4,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "shopping",
"_type": "_doc",
"_id": "TYu9pn8BfWqG58AR7Mzw",
"_score": 1.0,
"_source": {
"title": "小米手机",
"category": "小米",
"images": "http://xxx.com/xm.jpg",
"price": 3999.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1001",
"_score": 1.0,
"_source": {
"title": "小米手机",
"category": "小米",
"images": "http://xxx.com/xm.jpg",
"price": 3999.00
}
}
]
}
}
GET
请求:http://127.0.0.1:9200/index_name/_search?q=param:value
但是在请求路径中添加额外的参数是比较麻烦的,而且这里的中文在请求路径中是容易出现乱码的,所以一般会调整为通过请求体来传递参数。
在Postman中发起GET
请求:http://127.0.0.1:9200/index_name/_search
请求体方式:
{
"query":{ // query:查询
"match":{ // match:全文检索匹配(1.2.9有详细讲)
"field1":"value1"
}
}
}
{
"query":{ // query:查询
"match_all":{ // match_all:全匹配
}
}
}
查询category字段为小米的文档
请求体:
{
"query":{
"match":{
"category":"小米"
}
}
}
{
"took": 44,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 4,
"relation": "eq"
},
"max_score": 0.21072102,
"hits": [
{
"_index": "shopping",
"_type": "_doc",
"_id": "TYu9pn8BfWqG58AR7Mzw",
"_score": 0.21072102,
"_source": {
"title": "小米手机",
"category": "小米",
"images": "http://xxx.com/xm.jpg",
"price": 3999.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1001",
"_score": 0.21072102,
"_source": {
"title": "小米手机",
"category": "小米",
"images": "http://xxx.com/xm.jpg",
"price": 3999.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1002",
"_score": 0.21072102,
"_source": {
"title": "小米手机",
"category": "小米",
"images": "http://xxx.com/xm.jpg",
"price": 3999.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1003",
"_score": 0.21072102,
"_source": {
"title": "小米手机",
"category": "小米",
"images": "http://xxx.com/xm.jpg",
"price": 3999.00
}
}
]
}
}
上述条件查询可以通过这样匹配到全部文档:
{
"query":{ // query:查询
"match_all":{ // match_all:全匹配
}
}
}
但是这样查询数量量太多了,而我们只需要一部分数据,怎么办,一般我们我们会采用分页查询,这个时候我们的请求体内容就需要修改:
在Postman中发起GET
请求,携带请求体:http://127.0.0.1:9200/index_name/_search
请求体:
{
"query":{ // query:查询
"match_all":{ // match_all:全匹配
}
},
"from": 0, // 起始页
"size": 1 // 每页文档数
}
请求体:
{
"query":{
"match_all":{
}
},
"from": 0,
"size": 1
}
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 4,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "shopping",
"_type": "_doc",
"_id": "TYu9pn8BfWqG58AR7Mzw",
"_score": 1.0,
"_source": {
"title": "小米手机",
"category": "小米",
"images": "http://xxx.com/xm.jpg",
"price": 3999.00
}
}
]
}
}
但是感觉_source 里的字段有很多都是没啥用的,就可以通过指定字段来查询:
在Postman中发起GET
请求,携带请求体:http://127.0.0.1:9200/index_name/_search
请求体:
{
"query":{
"match_all":{
}
},
"from": 0,
"size": 1,
"_source":["field1","field2"] // 想要的字段
}
只要文档的title字段
请求体:
{
"query":{
"match_all":{
}
},
"from": 0,
"size": 1,
"_source":["title"]
}
{
"took": 5,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 4,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "shopping",
"_type": "_doc",
"_id": "TYu9pn8BfWqG58AR7Mzw",
"_score": 1.0,
"_source": {
"title": "小米手机" // 只有title字段
}
}
]
}
}
在Postman中发起GET
请求,携带请求体:http://127.0.0.1:9200/index_name/_search
请求体:
{
"query":{
"match_all":{
}
},
"sort":{
"field":{
"order":"desc" // desc:降序 || asc:升序
}
}
}
根据price价格进行升序排序:
请求体:
{
"query":{
"match_all":{
}
},
"_source":["price"],
"sort":{
"price":{
"order":"asc"
}
}
}
{
"took": 3,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 6,
"relation": "eq"
},
"max_score": null,
"hits": [
{
"_index": "shopping",
"_type": "_doc",
"_id": "1004",
"_score": null,
"_source": {
"price": 3000.0
},
"sort": [
3000.0
]
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "TYu9pn8BfWqG58AR7Mzw",
"_score": null,
"_source": {
"price": 3999.0
},
"sort": [
3999.0
]
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1001",
"_score": null,
"_source": {
"price": 3999.0
},
"sort": [
3999.0
]
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1002",
"_score": null,
"_source": {
"price": 3999.0
},
"sort": [
3999.0
]
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1003",
"_score": null,
"_source": {
"price": 3999.0
},
"sort": [
3999.0
]
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1005",
"_score": null,
"_source": {
"price": 20000.0
},
"sort": [
20000.0
]
}
]
}
}
在Postman中发起GET
请求,携带请求体:http://127.0.0.1:9200/index_name/_search
{
"query":{
"bool":{ // 多条件查询的话,需要参数bool
"must":[// must:多个提交件必须同时成立 相当于and, should: 多条件不要求同时成立 相当于or
{ // 花括号中就是匹配规则,一个规则一对花括号
"match":{
"field1":"value1"
}
},
{
"match":{
"field2":value2
}
}
]
}
}
}
查询category为小米,且价格为3999.00 的文档:
请求体:
{
"query":{
"bool":{ // 多条件查询的话,需要参数bool
"must":[// must:多个提交件必须同时成立
{ // 花括号中就是匹配规则,一个规则一对花括号
"match":{
"category":"小米"
}
},
{
"match":{
"price":3999.00
}
}
]
}
}
}
{
"took": 13,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 4,
"relation": "eq"
},
"max_score": 1.1290771,
"hits": [
{
"_index": "shopping",
"_type": "_doc",
"_id": "TYu9pn8BfWqG58AR7Mzw",
"_score": 1.1290771,
"_source": {
"title": "小米手机",
"category": "小米",
"images": "http://xxx.com/xm.jpg",
"price": 3999.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1001",
"_score": 1.1290771,
"_source": {
"title": "小米手机",
"category": "小米",
"images": "http://xxx.com/xm.jpg",
"price": 3999.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1002",
"_score": 1.1290771,
"_source": {
"title": "小米手机",
"category": "小米",
"images": "http://xxx.com/xm.jpg",
"price": 3999.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1003",
"_score": 1.1290771,
"_source": {
"title": "小米手机",
"category": "小米",
"images": "http://xxx.com/xm.jpg",
"price": 3999.00
}
}
]
}
}
在Postman中发起GET
请求,携带请求体:http://127.0.0.1:9200/index_name/_search
请求体:
注意: 这个范围是在你 多条件查询 后结果的基础上进一步查找
{
"query":{
"bool":{
"must":[
{
"match":{
"field1":"value1"
}
},
{
"match":{
"field2":value2
}
}
],
"filter":{ // 过滤
"range":{ // 范围
"field":{
"条件运算符": range // eg: gt:5000 大于5000的
}
}
}
}
}
}
查询华为手机或者苹果手机价格大于5000的文档:
请求体:
{
"query":{
"bool":{
"should":[
{
"match":{
"category":"HuaWei"
}
},
{
"match":{
"category":"Apple"
}
}
],
"filter":{ // 过滤
"range":{ // 范围
"price":{
"gt": 5000
}
}
}
}
}
}
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": 1.4417952,
"hits": [
{
"_index": "shopping",
"_type": "_doc",
"_id": "1001",
"_score": 1.4417952,
"_source": {
"title": "苹果手机",
"category": "Apple",
"images": "http://xxx.com/xm.jpg",
"price": 6599.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1006",
"_score": 1.0630683,
"_source": {
"title": "华为手机",
"category": "HuaWei",
"images": "http://xxx.com/xm.jpg",
"price": 44999.00
}
}
]
}
}
回到上面的条件查询,
{
"query":{
"match":{
"category":"米"
}
}
}
上面这个条件仍然会匹配到category
字段为小米的数据,这是因为:
当保存文档数据的时候,ElasticSearch会将数据文字进行分词、拆解操作,并将拆解后的数据保存到倒排索引中去,因此,即使只使用文字的一部分,仍然可以查询到数据,这种方式我们称之为全文检索,而且ElasticSearch对查询内容同样会进行分词,在倒排索引中进行匹配。
全文检索"小华"
http://127.0.0.1:9200/shopping/_search
请求体:
{
"query":{
"match":{
"title":"小华"
}
}
}
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 6,
"relation": "eq"
},
"max_score": 0.9444616,
"hits": [
{
"_index": "shopping",
"_type": "_doc",
"_id": "1005",
"_score": 0.9444616,
"_source": {
"title": "华为手机",
"category": "HuaWei",
"images": "http://xxx.com/xm.jpg",
"price": 5000.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1006",
"_score": 0.9444616,
"_source": {
"title": "华为手机",
"category": "HuaWei",
"images": "http://xxx.com/xm.jpg",
"price": 44999.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1007",
"_score": 0.9444616,
"_source": {
"title": "华为手机",
"category": "HuaWei",
"images": "http://xxx.com/xm.jpg",
"price": 3645.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "TYu9pn8BfWqG58AR7Mzw",
"_score": 0.9444616,
"_source": {
"title": "小米手机",
"category": "小米",
"images": "http://xxx.com/xm.jpg",
"price": 3999.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1004",
"_score": 0.9444616,
"_source": {
"title": "小米手机",
"category": "小米",
"images": "http://xxx.com/xm.jpg",
"price": 3000.00
}
},
{
"_index": "shopping",
"_type": "_doc",
"_id": "1003",
"_score": 0.9444616,
"_source": {
"title": "小米手机",
"category": "小米",
"images": "http://xxx.com/xm.jpg",
"price": 3999.00
}
}
]
}
}
可以看到 你查询的条件是"title":"小华"
,但是却查询到了小米和华为,这就是因为ES对查询内容进行了分词,分成了小
、华
对倒排索引进行了匹配,从而匹配到了小米和华为。
由1.2.9
全文检索可以看出,你在1.2.3
条件匹配的方式并不是完全匹配的。
在Postman中发起GET
请求,携带请求体:http://127.0.0.1:9200/index_name/_search
请求体:
{
"query":{
"match_phrase":{ // 完全匹配
"field":"value"
}
}
}
http://127.0.0.1:9200/shopping/_search
请求体:
{
"query":{
"match_phrase":{ // 完全匹配
"title":"小华"
}
}
}
{
"took": 9,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 0,
"relation": "eq"
},
"max_score": null,
"hits": []
}
}
在Postman中发起GET
请求,携带请求体:http://127.0.0.1:9200/index_name/_search
请求体:
{
"query":{
"match_phrase":{ // 完全匹配
"field":"value"
}
},
"highlight":{
"fields":{
"title":{}
}
}
}
在Postman中发起GET
请求,携带请求体:http://127.0.0.1:9200/shopping/_search
请求体:
{
"query":{
"match_phrase":{ // 完全匹配
"title":"华为手机"
}
},
"highlight":{ // 高亮显示
"fields":{
"title":{}
}
}
}
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 3,
"relation": "eq"
},
"max_score": 2.00324,
"hits": [
{
"_index": "shopping",
"_type": "_doc",
"_id": "1005",
"_score": 2.00324,
"_source": {
"title": "华为手机",
"category": "HuaWei",
"images": "http://xxx.com/xm.jpg",
"price": 5000.00
},
"highlight": {
"title": [
"<em>华</em><em>为</em><em>手</em><em>机</em>" // 高亮显示
]
}
}
]
}
}
如果想查询结果进行分组或者统计分析,就使用聚合查询:
在Postman中发起GET
请求,携带请求体:http://127.0.0.1:9200/index_name/_search
请求体:
{
"aggs":{ // 聚合操作
"group_name": { // 聚合结果的名字,随意起名
"terms":{ // 分组
"field":"field1" // 分组字段
}
}
}
}
在Postman中发起GET
请求,携带请求体:http://127.0.0.1:9200/shopping/_search
请求体:
{
"aggs":{ // 聚合操作
"price_group": { // 聚合结果的名字,随意起名
"terms":{ // 分组 || terms:分组; avg:平均值
"field":"price" // 分组字段
}
}
},
"size":0 // 舍弃原始数据
}
{
"took": 6,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 8,
"relation": "eq"
},
"max_score": null,
"hits": [] // 原始数据
},
"aggregations": {
"price_group": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": 3999.0,
"doc_count": 2
},
{
"key": 3000.0,
"doc_count": 1
},
{
"key": 3645.0,
"doc_count": 1
},
{
"key": 4555.0,
"doc_count": 1
},
{
"key": 5000.0,
"doc_count": 1
},
{
"key": 6599.0,
"doc_count": 1
},
{
"key": 44999.0,
"doc_count": 1
}
]
}
}
}
在Postman中发起GET
请求,携带请求体:http://127.0.0.1:9200/shopping/_search
请求体:
{
"aggs":{ // 聚合操作
"price_avg": { // 聚合结果的名字,随意起名
"avg":{ // 平均值
"field":"price" // 分组字段
}
}
},
"size":0 // 舍弃
}
{
"took": 4,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 8,
"relation": "eq"
},
"max_score": null,
"hits": [] // 原始数据
},
"aggregations": {
"price_avg": {
"value": 9474.5 // 平均值
}
}
}
在Postman中发起PUT
请求:http://127.0.0.1:9200/index_name/_doc/id
修改内容:
{
"title": "华为手机",
"category": "HuaWei",
"images": "http://xxx.com/xm.jpg",
"price": 4000.00
}
{
"_index": "shopping",
"_type": "_doc",
"_id": "1001",
"_version": 4,
"result": "updated", // 修改
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 4,
"_primary_term": 2
}
不可以使用PUT请求,要使用POST请求。
在Postman中发起POST
请求:http://127.0.0.1:9200/index_name/_update/id
请求体内容:
{
"doc":{
"price":5000.00
}
}
{
"_index": "shopping",
"_type": "_doc",
"_id": "1001",
"_version": 5,
"result": "updated",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 5,
"_primary_term": 2
}
在Postman中发起DELETE
请求:http://127.0.0.1:9200/index_name/_update/id
{
"_index": "shopping",
"_type": "_doc",
"_id": "1001",
"_version": 6,
"result": "deleted", // 删除成功
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 6,
"_primary_term": 2
}
如果删除一个不存在的文档:
{
"_index": "shopping",
"_type": "_doc",
"_id": "1001",
"_version": 1,
"result": "not_found", // 未找到
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 7,
"_primary_term": 2
}
请求体:
{
"properties":{
"name":{// 字段名称
"type":"text", // 字段类型。text:文本,可以分词
"index":true // index:true 表示这个字段可以通过索引查询。
},
"sex":{
"type":"keyword", // keyword 表示不可以分词,必须完整匹配
"index":true
},
"tel":{
"type":"keyword",
"index":false // 不可被索引,即不可被查询
}
}
}
响应:
{
"user": {
"mappings": {
"properties": {
"name": {
"type": "text"
},
"sex": {
"type": "keyword"
},
"tel": {
"type": "keyword",
"index": false
}
}
}
}
}
请求体:
{
"name": "小米",
"sex": "男的",
"tel": "1111"
}
请求体:
{
"query":{
"match":{
"name":"小" // 因为name为text类型,是支持分词,也就是全文检索的
}
}
}
响应:
{
"took": 606,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 0.2876821,
"hits": [
{
"_index": "user",
"_type": "_doc",
"_id": "1001",
"_score": 0.2876821,
"_source": {
"name": "小米",
"sex": "男的",
"tel": "1111"
}
}
]
}
}
请求体:
{
"query":{
"match":{
"sex":"男" // sex类型为keyword,只支持完全查询,不支持全文检索
}
}
}
响应:
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 0,
"relation": "eq"
},
"max_score": null,
"hits": []
}
}
请求体:
{
"query":{
"match":{
"tel":"1111" // tel的index:false 不可被查询 所以会报错
}
}
}
会报错:
"reason": "failed to create query: Cannot search on field [tel] since it is not indexed.",
// "reason": "创建查询失败:无法在[tel]字段上搜索,因为它没有被索引",