一、索引管理
1. 创建索引
PUT /index_name
{
"settings": {
"number_of_shards":2,
"number_of_replicas":1
},
"mappings": {
"properties": {
"id":{
"type": "integer"
},
"name":{
"type": "keyword"
},
"age":{
"type": "long"
},
"desc":{
"type": "text"
},
"birthday":{
"type": "date"
}
}
}
}
settings设置有好多,上面只写了分片和副本数量。
2. 修改索引字段
注:只能新增字段,不能删除字段
POST /index_name/_mapping
{
"properties": {
"title":{
"type": "text"
}
}
}
3. 删除索引
DELETE /index_name
4. 查看索引字段类型
GET /index_name/_mapping
5. 索引数据转移,旧索引数据复制到新索引
POST /_reindex
{
"source": {
"index": "index_name_old"
},
"dest": {
"index": "index_name_new",(提前创建好)
"version_type": "external"
}
}
6. 查看索引列表-健康状态
GET _cat/health
7. 查看索引列表-详细信息
GET _cat/indices?v
8. 查看ik分词情况
GET _analyze
{
"analyzer": "ik_smart",
"text": "支付就用支付宝"
}
9. 查看ik分词,最细粒度划分
GET _analyze
{
"analyzer": "ik_max_word",
"text": "支付就用支付宝"
}
二、文档管理
1. 创建文档PUT/POST
区别:put文档必须要指定文档_id;post可指定,可不指定,不指定则会随机生成一个_id
情况1:如果没有提前设定索引中字段类型而直接添加文档,es会对字段数据给自动数据类型,新字段会永久补充进去mapping。
情况2:如果添加的数据字段数量大于提前设定索引中字段数量,可成功,按情况1处理。
情况3:如果添加的数据字段数量小于提前设定索引中字段数量,更可成功。
put指定id
PUT /index_name/_doc/1
{
"id":1001,
"name":"张三",
"age":12,
"desc":"我的自我描述",
"birthday":"2020-02-02"
}
post指定id
POST /index_name/_doc/3
{
"id":1002,
"name":"张三",
"age":12,
"desc":"我的自我描述",
"birthday":"2020-02-02"
}
post不指定id,自动给_id
POST /index_name/_doc
{
"id":1003,
"name":"张三",
"age":12,
"desc":"我的自我描述",
"birthday":"2020-02-02"
}
2. 查询文档
查询所有文档
GET /index_name/_search
查询指定文档
GET /index_name/_doc/1
3. 修改文档
全修改:PUT和POST都可以,全部字段均会被修改更新
POST /index_name/_doc/1
{
"id":1005,
"name":"张三",
"age":12,
"desc":"我的自我描述",
"birthday":"2020-02-02"
}
部分修改:POST,只修改部分字段数据
POST /index_name/_doc/1/_update
{
"doc":{
"name":"李四"
}
}
4. 删除文档
根据id删除指定文档
DELETE /index_name/_doc/1
5.清空指定索引全部文档
POST index_name/_delete_by_query
{
"query": {"match_all": {}}
}
根据查询条件清理部分文档
POST index_name/_delete_by_query
{
"query":{
"bool":{
"filter":[
{
"range":{
"birthday":{
"gte":"2020-06-01 00:00:00",
"lt":"2020-07-01 00:00:00"
}
}
}
]
}
}
}
三、复杂查询
语句条件:match匹配查询、bool联合查询、term精确查询
约束条件:must、must_not、should、filter
1. match匹配查询
首先我拿match对desc查询,因为desc是text类型可以进行分词查询;name是keyword不分词,不支持分词查询。
实测,下面的查询结果会查询到desc中包含"%张%" 或 "%三%" 或 "%李%"的文档。
注:张三不是一个词,会被分词器给分开,哇。。。。这样岂不是能查很多,确实,尽量少用match查询text,不够精准。
GET /index_name/_search
{
"query":{
"match":{
"desc":"张三 李"
}
}
}
2. bool联合查询,通常搭配must,should,must_not,filter
- must、must_not 条件查询,必须满足,类似mysql中and的用法
GET /index_name/_search
{
"query":{
"bool":{
"must":[
{
"match":{
"desc":"三 四"
}
},
{
"match": {
"age": 12
}
}
]
}
}
}
- should 条件查询,需要满足,并且是或者的关系,类似mysql中or的用
GET /index_name/_search
{
"query":{
"bool":{
"should":[
{
"match":{
"desc":"三 四"
}
},
{
"match": {
"age": 12
}
}
]
}
}
}
- filter 过滤查询
GET /index_name/_search
{
"query":{
"bool":{
"must":[
{
"match":{
"desc":"三 四"
}
}
],
"filter": [
{
"range": {
"age": {
"gte": 10,
"lt": 13
}
}
}
]
}
}
}
3. term精确查询: 通过倒排索引进行精确查找,用的最多
- ·match原理是先分析文档,通过分词器进行解析,然后再去文档中查询。
- ·term直接进行精确查询,term是代表完全匹配,也就是精确查询,搜索前不会再对搜索词进行分词拆解。
- ·match_phrase短语搜索,要求所有的分词必须同时出现在文档中,同时位置必须紧邻一致。
- 简单查询
GET /index_name/_search
{
"query": {
"term": {
"desc":"三"
}
}
}
(2)多条件复合查询
注:term不会分词查询,只是精确查询!!!必须要查满足 “小三” 的文档
GET /index_name/_search
{
"query":{
"bool":{
"must": [
{
"term": {
"desc": "小三"
}
},
{
"term": {
"age": 11
}
}
]
}
}
}
terms表示多条件并列,用大括号 [ ] 涵盖所查内容,类似于MySql中in方法
GET /index_name/_search
{
"query":{
"bool":{
"must": [
{
"terms": {
"age": [
10,11,12
]
}
}
]
}
}
}
或者
GET /index_name/_search
{
"query":{
"bool":{
"must": [
{
"terms": {
"desc": [
"我","三"
]
}
}
]
}
}
}
多重混合,这个也是用到较多的
GET /index_name/_search
{
"query":{
"bool":{
"must":[
{
"term":{
"desc":"三"
}
},
{
"terms":{
"age":[
10,
11,
12
]
}
}
]
}
}
}
must和must_not混合,这里面留意区别下term 和 match条件的不同含义
GET /index_name/_search
{
"query":{
"bool":{
"must":[
{
"term":{
"name":"张三"
}
}
],
"must_not":[
{
"term":{
"age":"10"
}
},
{
"match":{
"desc":"描述"
}
}
]
}
}
}
尤其注意must和should并列的情况:must和should不可以直接并列,must和must_not可以直接并列
假如,要查姓名叫“张三”,年龄为12岁或者出生日期为2020-02-03的个人信息,一定要注意了。
就好比: name=张三 && age=15 || birthday=2020-02-03这种错误一样,这是不对的。逻辑上似乎说的过去,但在严谨的数学上可不行,并且就算在mysql中也不可以这么写,因为and优先级大于or,会先执行and并列条件,好在mysql中可以将条件括起来,改正为 where name='张三' and (age=12 or birthday='2020-02-03')。
错误的写法: 即便是把age和birthday都放在should里面,elasticsearch也不认。
GET /index_name/_search
{
"query":{
"bool":{
"must":[
{
"match":{
"name":"张三"
}
}
],
"should":[
{
"match":{
"age":"12"
}
},
{
"match":{
"birthday":"2020-02-03"
}
}
]
}
}
}
正确的逻辑是:(name=张三 && age=15) || (name=张三 &&birthday=2020-02-03),
正确的写法:先对should分出情况,再给每一种情况进行must约束
GET /index_name/_search
{
"query":{
"bool":{
"should":[
{
"bool":{
"must":[
{
"term":{
"name":"张三"
}
},
{
"term":{
"age":12
}
}
]
}
},
{
"bool":{
"must":[
{
"term":{
"name":"张三"
}
},
{
"term":{
"birthday":"2020-02-03"
}
}
]
}
}
]
}
}
}
4. 聚合查询collapse和aggs,将重复内容进行折叠(去重)
GET /index_name/_search
{
"query":{
"bool":{
"must":[
{
"term":{
"moduleAttr":6424
}
},
{
"terms":{
"sortId":[1,72,101]
}
}
],
"filter":[
{
"range":{
"pubTime":{
"gte":"2020-07-11 09:13:04"
}
}
}
]
}
},
"sort":[
{
"pubTime":{
"order":"desc"
}
}
],
"collapse":{
"field":"contentId"
},
"size":20
}
或者
GET index_name/_search
{
"query":{
"bool":{
"must":{
"terms":{
"websiteId":[
2141391797
]
}
},
"filter":{
"range":{
"pubTime":{
"gte":"2020-04-20 00:00:00",
"lte":"2020-07-31 23:59:59"
}
}
}
}
},
"aggs": {
"my_name(自定义名字)": {
"terms": {
"field": "contentId"
}
}
},
"size":10
}
4.1.初始测试数据
学习SQL中常用的案例,老师信息表
字段信息:name(姓名) | age(年龄) | job(工作岗位) | sex(性别1-男,2-女) | salary(薪资)
#老师信息
PUT /teacher_info/_bulk
{ "index" : { "_id" : "101" } }
{ "name" : "Tom","age":32,"job":"Math","sex":1,"salary": 3000 }
{ "index" : { "_id" : "102" } }
{ "name" : "Zhangsan","age":22,"job":"Java","sex":1,"salary": 5000}
{ "index" : { "_id" : "103" } }
{ "name" : "lisi","age":29,"job":"sports","sex":1,"salary": 4000 }
{ "index" : { "_id" : "104" } }
{ "name" : "wangwu","age":25,"job":"sports","sex":1,"salary": 4300}
{ "index" : { "_id" : "105" } }
{ "name" : "Mary","age":30,"job":"H5","sex":2,"salary": 4800}
{ "index" : { "_id" : "106" } }
{ "name" : "Luccy","age":33,"job":"English","sex":2,"salary": 5500 }
{ "index" : { "_id" : "107" } }
{ "name" : "Xiaomei","age":23,"job":"English","sex":2,"salary": 5800 }
{ "index" : { "_id" : "108" } }
{ "name" : "Xiaogao","age":27,"job":"Php","sex":1,"salary": 3900}
{ "index" : { "_id" : "109" } }
{ "name" : "Dabai","age":26,"job":"Chinese","sex":1,"salary": 4000 }
{ "index" : { "_id" : "110" } }
{ "name" : "Xiaowei","age":25,"job":"C++","sex":1,"salary": 4500 }
4.2.ES聚合分析查询的写法
在查询请求体中以aggregations节点语法如下:**
"aggregations" : {
"<aggregation_name>" : { <!--聚合的名字 -->
"<aggregation_type>" : { <!--聚合的类型 -->
<aggregation_body> <!--聚合体:对哪些字段进行聚合 -->
}
[,"meta" : { [<meta_data_body>] } ]? <!--元 -->
[,"aggregations" : { [<sub_aggregation>]+ } ]? <!--在聚合里面在定义子聚合 -->
}
}
注:aggregations 也可简写为 aggs
4.3.求和(Sum)
案例:求所有老师的薪资总和
注:“size”: 0 ,参数表示不用返回文档列表,只返回汇总的数据即可
GET teacher_info/_search
{
"size": 0,
"aggs": {
"sum_salary": {
"sum": {
"field":"salary"
}
}
}
}
4.4.最大值(Max)
示例:求薪资最大值
GET teacher_info/_search
{
"size": 0,
"aggs": {
"max_salary": {
"max": {
"field":"salary"
}
}
}
}
4.5.最小值(Min)
案例:求薪资最低值
GET teacher_info/_search
{
"size": 0,
"aggs": {
"min_salary": {
"min": {
"field":"salary"
}
}
}
}
4.6.平均值(Avg)
案例:求薪资平均值
GET teacher_info/_search
{
"size": 0,
"aggs": {
"avg_salary": {
"avg": {
"field":"salary"
}
}
}
}
4.7.去重数值(cardinality)
类似mysql的 count distinct
案例:老师一共教了多少学科
GET teacher_info/_search
{
"size": 0,
"aggs" : {
"job_count" : {
"cardinality" : {
"field" : "job.keyword"
}
}
}
}
由于在创建索引的时候,没有先创建Mapping, job这个字段默认是 text类型,而聚合统计不知道text类型,所以这里需要使用“job.keyword”
字符串类型的参数,在没有指定mapping的情况下,默认生成的类型如上图。
4.8.多值查询-最大最小和平均值
案例:查询最低、最高和平均工资
GET teacher_info/_search
{
"size": 0,
"aggs": {
"max_salary": {
"max": {
"field": "salary"
}
},
"min_salary": {
"min": {
"field": "salary"
}
},
"avg_salary": {
"avg": {
"field": "salary"
}
}
}
}
4.9.返回多个聚合值(Status)
stats 统计,请求后会直接显示多种聚合结果,总记录数,最大值,最小值,平均值,汇总值
GET employees_info/_search
{
"size": 0,
"aggs": {
"salary_stats": {
"stats": {
"field":"salary"
}
}
}
}
4.10.百分比(Percentiles)
对指定字段的值按从小到大累计每个值对应的文档数的占比,返回指定占比比例对应的值。**
GET teacher_info/_search
{
"size": 0,
"aggs": {
"age_percentiles": {
"percentiles": {
"field": "age"
}
}
}
}
默认按照[ 1, 5, 25, 50, 75, 95, 99 ]来统计
返回结果可以理解为:占比为25%的文档的age值 <= 25,或反过来:age<=25的文档数占总命中文档数的25%
因为是默认返回的 ,[ 1, 5, 25, 50, 75, 95, 99 ] 所以 可能存在重复值
key-value形式返回
添加参数"keyed": false
4.11.文档值占比(Percentile Ranks)
这里指定值,查占比。注意占比是小于文档值的比例
GET teacher_info/_search
{
"size": 0,
"aggs" : {
"age_percentiles" : {
"percentile_ranks" : {
"field" : "age",
"values" : [ 22, 25, 33]
}
}
}
}
下图含义
小于age<=22的占比 5%
小于age<=25的占比 30%
小于age<=33的占比 100%
4.12.中位数查询
案例:求工资中位数
POST teacher_info/_search
{
"size": 0,
"aggs": {
"load_time_outlier": {
"percentiles": {
"field": "salary",
"percents" : [ 50, 99],
"keyed": false
}
}
}
}
4.13.分组取Top N 之(Top Hits)
案例1:根据性别分组。展示工资排名top3
GET /teacher_info/_search?size=0
{
"aggs": {
"top_tags": {
"terms": {
"field": "sex"
},
"aggs": {
"top_sales_hits": {
"top_hits": {
"sort": [
{
"salary": {
"order": "desc"
}
}
],
"_source": {
"includes": [ "name", "sex","salary" ]
},
"size" : 3
}
}
}
}
}
}
4.14.分组之聚合
案例:根据性别分组求平均工资
GET /teacher_info/_search
{
"size":0,
"aggs": {
"top_tags": {
"terms": {
"field": "sex"
},
"aggs": {
"avg_salary": {
"avg": {
"field": "salary"
}
}
}
}
}
}
4.15.总记录数查询
类似mysql的count
#方式1:统计年龄 >=25 的记录数
GET teacher_info/_count
{
"query": {
"range": {
"age":{
"gte": 25
}
}
}
}
#方式2:统计年龄 >=25 的记录数
GET teacher_info/_search?size=0
{
"query": {
"range": {
"age":{
"gte": 25
}
}
}
}
5. 高亮查询
默认高亮格式查询
GET /index_name/_search
{
"query":{
"match":{
"desc":"自我描述"
}
},
"highlight": {
"fields": {
"desc": {}
}
}
}
自定义高亮代码
GET /index_name/_search
{
"query":{
"match":{
"desc":"自我描述"
}
},
"highlight": {
"pre_tags": "<p style='color:red'>" ,
"post_tags": "</p>",
"fields": {
"desc": {}
}
}
}
6. 最后说几个常用查询筛选条件:
从上到下,分别是只显示需要返回的字段、查询条件、排序规则、分页从0页开始size为2
GET /index_name/_search
{
"_source":{
"includes":[
"name",
"age",
"desc"
]
},
"query":{
"match":{
"name":"张三"
}
},
"sort":[
{
"age":{
"order":"desc"
}
}
],
"from": 0,
"size": 2
}
四、复杂条件修改/删除
1. 条件修改_update_by_query
将desc中含有“三”的数据,desc修改为“张3新的自我介绍”。
POST /index_name/_update_by_query
{
"script":{
"source":"ctx._source['desc']='张3新的自我介绍'"
},
"query":{
"bool":{
"must":[
{
"term":{
"desc":"三"
}
}
]
}
}
}
2. 条件删除_delete_by_query
将desc中含有“3”的数据删除
POST /index_name/_delete_by_query
{
"query":{
"bool":{
"must":[
{
"term":{
"desc":"3"
}
}
]
}
}
}
3.清空索引数据
POST /index_name/_delete_by_query
{
"query": {"match_all": {}}
}
六、Elasticsearch Painless Script
官网解释,自Elasticsearch 5.x 引入Painless,使得Elasticsearch拥有了安全、可靠、高性能脚本的解决方案。
简单来说就是支持通过Painless脚本语言的方式,对es进行查询、修改、删除等操作,为es提供了更强大的一种操作方式。
doc只可以在_search中访问到。如果是修改操作,使用的是ctx。
https://blog.csdn.net/u013613428/article/details/78134170#%E6%89%B9%E9%87%8F%E6%9B%B4%E6%96%B0
- 条件修改
POST /index_name/_update_by_query
{
"script":{
"lang":"painless",
"source":"ctx._source.title=params.newTitile",
"params":{
"newTitile":"修改为新的titile"
}
},
"query":{
"bool":{
"filter":[
{
"range":{
"crawlTime":{
"gte":"2020-09-01 00:00:00",
"lt":"2020-09-03 00:00:00"
}
}
}
]
}
}
}
或者修改title,在titile后面加一句“加一个后缀”
POST /index_name/_update_by_query
{
"script":{
"lang":"painless",
"source":"ctx._source.title= ctx._source.title+'加一个后缀'"
},
"query":{
"bool":{
"filter":[
{
"range":{
"crawlTime":{
"gte":"2020-09-01 00:00:00",
"lt":"2020-09-03 00:00:00"
}
}
}
]
}
}
}