2019-06-26

注意点:现在kibana/elasticsearch最新版本为7.0,与5.2.0的语法有出入,需要注意

语法,自己查询

kibana为操作elasticserch的界面,地址可以在启动日志中看到:

image

界面展示:

image

一下为一些操作练习:

写入

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"

}

结果如下:

image

定制返回结果

_source元数据:就是说,我们在创建一个document的时候,使用的那个放在request body中的json串,默认情况下,在get的时候,会原封不动的给我们返回回来

PUT /test_index/my_test/1

{

"test1":"test1",

"test2":"test2"

}

GET /test_index/my_test/1?_source=test1

结果如下:

image

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

最终结果:

image

document的删除

  1. DELETE /index/type/id

  2. 不会理解为为例删除,只会将其标记为deleted,当数据越来越多的时候,在后台自动删除


上机演练基于_version进行乐观锁的并发控制

开两个kibana客户端

PUT /test_index/my_test/7

{

"test_str":"test001"

}

image

PUT /test_index/my_test/7?version=1

{

"test_str":"test002"

}

image

另外一个客户端,尝试基于version=1的版本进行修改,同样带上version版本号,进行乐观锁的并发控制:

PUT /test_index/my_test/7?version=1

{

"test_str":"test001"

}

image

商机动手实战演练基于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实现原理以及其优点

image

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

  }

}

]

}

···

你可能感兴趣的:(2019-06-26)