注意点:现在kibana/elasticsearch最新版本为7.0,与5.2.0的语法有出入,需要注意
语法,自己查询
kibana为操作elasticserch的界面,地址可以在启动日志中看到:
界面展示:
一下为一些操作练习:
写入
PUT /ecommerce/product/1
{
"name" : "gaolujie yagao",
"desc" : "gaoxiao meibai",
"price" : 30,
"producer" : "gaolujie producer",
"tags": [ "meibai", "fangzhu" ]
}
写入
PUT /ecommerce/product/2
{
"name" : "jiajieshi yagao",
"desc" : "youxiao fangzhu",
"price" : 25,
"producer" : "jiajieshi producer",
"tags": [ "fangzhu" ]
}
写入
PUT /ecommerce/product/3
{
"name" : "zhonghua yagao",
"desc" : "caoben zhiwu",
"price" : 40,
"producer" : "zhonghua producer",
"tags": [ "qingxin" ]
}
查询所有
GET /ecommerce/product/_search
{
"query": {
"match_all": {}
}
}
查询name中带有yagao的数据
GET /ecommerce/product/_search
{
"query": {
"match": {
"name": "yagao"
}
}
}
查询name为yagao并且按照price降序排序
GET /ecommerce/product/_search
{
"query": {
"match": {
"name":"yagao"
}
},
"sort":[
{
"price":"desc"
}
]
}
分页查询,只查询一条
GET /ecommerce/product/_search
{
"query": {
"match_all": {}
},
"from": 0,
"size": 1
}
只查询price与name
GET /ecommerce/product/_search
{
"query":{
"match_all": {}
},
"_source": ["price","name"]
}
查询name中匹配价格大于30牙膏
GET /ecommerce/product/_search
{
"query": {
"bool": {
"must": [
{"match": {
"name": "yagao"
}}
],
"filter": {
"range": {
"price": {
"gt": 30
}
}
}
}
}
}
全文检索
GET /ecommerce/product/_search
{
"query": {
"match": {
"producer": "yagao producer"
}
}
}
短语短语匹配
GET /ecommerce/product/_search
{
"query": {
"match_phrase": {
"producer": "jiajieshi producer"
}
}
}
高亮显示xianshi高亮显示显示producer
GET /ecommerce/product/_search
{
"query": {
"match": {
"producer": "yagao producer"
}
},
"highlight": {
"fields": {
"producer": {}
}
}
}
将文本field的fielddata属性设置为true
PUT /ecommerce/_mapping/product
{
"properties": {
"tags": {
"type": "text",
"fielddata": true
}
}
}
计算每个tag下的商品数量
GET /ecommerce/product/_search
{
"size": 0,
"aggs": {
"group_by_tags": {
"terms": {
"field": "tags"
}
}
}
}
对名称中包含yagao的商品,计算每个tag下的商品数量
GET /ecommerce/product/_search
{
"query": {
"match": {
"name": "yagao"
}
},
"aggs": {
"all_tags": {
"terms": {
"field": "tags"
}
}
}
}
先分组,再算每组的平均值,计算每个tag下的商品的平均价格
GET /ecommerce/product/_search
{
"size": 0,
"aggs": {
"group_by_tags": {
"terms": {
"field": "tags"
},
"aggs": {
"avg_price": {
"avg": {
"field": "price"
}
}
}
}
}
}
计算每个tag下的商品的平均价格,并且按照平均价格降序排序
GET /ecommerce/product/_search
{
"size": 0,
"aggs": {
"group_by_tags": {
"terms": {
"field": "tags",
"order": {
"avg_price": "desc"
},
"size": 10
},
"aggs": {
"avg_price": {
"avg": {
"field": "price"
}
}
}
}
}
}
按照指定的价格范围区间进行分组,然后在每组内再按照tag进行分组,最后再计算每组的平均价格
GET /ecommerce/product/_search
{
"size": 0,
"aggs": {
"group_by_price": {
"range": {
"field": "price",
"ranges": [
{
"from": 0,
"to": 20
},
{
"from": 20,
"to": 40
},
{
"from": 40,
"to": 50
}
]
},
"aggs": {
"group_by_tags": {
"terms": {
"field": "tags"
},
"aggs": {
"average_price": {
"avg": {
"field": "price"
}
}
}
}
}
}
}
}
es自动生成id,使用的是GUID的算法,可以避免同一时间,不同节点,同时创建索引id的时候造成id相同的情况,语法如下:
POST /test_index/my_test
{
"test":"mytest2"
}
结果如下:
定制返回结果
_source元数据:就是说,我们在创建一个document的时候,使用的那个放在request body中的json串,默认情况下,在get的时候,会原封不动的给我们返回回来
PUT /test_index/my_test/1
{
"test1":"test1",
"test2":"test2"
}
GET /test_index/my_test/1?_source=test1
结果如下:
document的全量替换
1) 语法与创建文档是一样的,如果document id不存在,那么就创建;如果document id已经存在,那么就是全量替换操作,替换document的json串内容
2) document是不可变的,如果要修改document的内容,第一种方式就是全量替换,直接对document重新建立索引,替换里面所有的内容
3) es会将老的document标记为deleted,然后新增我们给定的一个document,当我们创建的越来越多的document的时候,es会在适当的实际在后台自动删除标记为deleted的document
document的强制创建
1) 创建文档与圈梁替换的语法一样,有时我们只是想新建文档,不想替换文档,如果强制进行创建呢?
2) PUT /index/type/id?op_type=create 或者 PUT /index/type/id/_create
最终结果:
document的删除
DELETE /index/type/id
不会理解为为例删除,只会将其标记为deleted,当数据越来越多的时候,在后台自动删除
上机演练基于_version进行乐观锁的并发控制
开两个kibana客户端
PUT /test_index/my_test/7
{
"test_str":"test001"
}
PUT /test_index/my_test/7?version=1
{
"test_str":"test002"
}
另外一个客户端,尝试基于version=1的版本进行修改,同样带上version版本号,进行乐观锁的并发控制:
PUT /test_index/my_test/7?version=1
{
"test_str":"test001"
}
商机动手实战演练基于external version进行乐观锁并发控制
es提供了一个feature,就是说,你可以不用它提供的内部的_version版本号来进行并发控制,可以基于自己维护的一个版本号进行并发控制。举个例子,假如你的数据在mysql中也有一份,然后你的应用系统本身就维护了一个版本号,无论是什么自己生成的,程序控制的。这个时候,你进行乐观锁并发控制的时候,可能并不是想要用es内部的_version来进行控制,而是用你自己维护的那个version来进行控制。
原先的语法:url?version=1
现在的语法:url?version=1&version_type=external
version_type=external,唯一的区别在于,_version,只有当你提供的version与es中的_version一模一样的时候,才可以进行修改,只要不一样,就报错;当version_type=external的时候,只有当你提供的version比es中的_version大的时候,才能完成修改
es,_version=1,?version=1,才能更新成功
es,_version=1,?version>1&version_type=external,才能成功,比如说?version=2&version_type=external
partial update实现原理、手动实践
1、什么是partial update?
PUT /index/type/id,创建文档&替换文档,就是一样的语法
一般对应到应用程序中,每次的执行流程基本是这样的:
(1)应用程序先发起一个get请求,获取到document,展示到前台界面,供用户查看和修改
(2)用户在前台界面修改数据,发送到后台
(3)后台代码,会将用户修改的数据在内存中进行执行,然后封装好修改后的全量数据
(4)然后发送PUT请求,到es中,进行全量替换
(5)es将老的document标记为deleted,然后重新创建一个新的document
partial update
post /index/type/id/_update
{
"doc": {
"要修改的少数几个field即可,不需要全量的数据"
}
}
看起来,好像就比较方便了,每次就传递少数几个发生修改的field即可,不需要将全量的document数据发送过去
2、图解partial update实现原理以及其优点
es,其实是有个内置的脚本支持的,可以基于groovy脚本实现各种各样的复杂操作
基于groovy脚本,如何执行partial update
PUT /test_index/test_type/11
{
"num": 0,
"tags": []
}
(1)内置脚本
POST /test_index/test_type/11/_update
{
"script" : "ctx._source.num+=1"
}
{
"_index": "test_index",
"_type": "test_type",
"_id": "11",
"_version": 2,
"found": true,
"_source": {
"num": 1,
"tags": []
}
}
(2)外部脚本
//注意,下面一行为脚本内容,脚本的存放位置为:
![image](https://upload-images.jianshu.io/upload_images/14757514-fa9602865ee4cd48.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
ctx._source.tags+=new_tag
POST /test_index/test_type/11/_update
{
"script": {
"lang": "groovy",
"file": "test-add-tags",
"params": {
"new_tag": "tag1"
}
}
}
(3)用脚本删除文档
···
ctx.op = ctx._source.num == count ? 'delete' : 'none'
POST /test_index/test_type/11/_update
{
"script": {
"lang": "groovy",
"file": "test-delete-document",
"params": {
"count": 1
}
}
}
···
(4)upsert操作,如果指定的document不存在,就执行upsert中的初始化操作;如果指定的document存在,就执行doc或者script指定的partial update操作
···
POST /test_index/test_type/11/_update
{
"script" : "ctx._source.num+=1",
"upsert": {
"num": 0,
"tags": []
}
}
···
mget批量查询
GET /test_index/_mget
{
"docs":[
{
"_type":"my_test",
"_id":"1"
},
{
"_type":"my_test",
"_id":"2"
}
]
}
//结果:
{
"docs": [
{
"_index": "test_index",
"_type": "my_test",
"_id": "1",
"_version": 2,
"found": true,
"_source": {
"test3": "test3"
}
},
{
"_index": "test_index",
"_type": "my_test",
"_id": "2",
"found": false
}
]
}
如果查询的document是一个index下的不同type种的话
···
GET /test_index/_mget
{
"docs":[
{
"_type":"my_test",
"_id":"1"
},
{
"_type":"other_test",
"_id":"1"
}
]
}
//结果
{
"docs": [
{
"_index": "test_index",
"_type": "my_test",
"_id": "1",
"_version": 2,
"found": true,
"_source": {
"test3": "test3"
}
},
{
"_index": "test_index",
"_type": "other_test",
"_id": "1",
"_version": 1,
"found": true,
"_source": {
"name": "li ming",
"age": 12
}
}
]
}
···