文档 https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html
1. 基本操作 1.1 索引 1.1.1 查看索引相关信息 request 1 2 3 4 // 查询 索引的 mapping和setting信息 GET /{index} // 查询索引order的信息 GET /order
1.1.2 创建索引 request 1 2 3 4 5 6 7 8 9 // 创建索引 PUT /{index} // 创建索引order PUT /order { "mappings": { ....... } }
1.1.3 删除索引 request 1 2 3 4 // 删除索引 DELETE /{index} // 删除索引order DELETE /order
1.1.4 修改Mapping request 1 2 3 4 5 6 7 8 9 10 11 // 修改mapping PUT /{index}/{type}/_mapping // order索引新增字段age PUT /order/table/_mapping { "properties": { "age": { "type": "long" } } }
1.1.5 设置别名 request 1 2 3 4 5 6 7 8 9 10 11 12 // 索引order_v4设置别名 order PUT _aliases { "actions": [ { "add": { "index": "order_v4", "alias": "order" } } ] }
1.1.6 查询别名 request 1 2 3 4 // 查询所有索引的别名 GET _alias // 根据索引名或别名是order的别名信息 GET order/_alias
1.2 文档 1.2.1 新增文档 request 1 2 3 4 5 6 // 新增 POST /{index}/{type}/{_id} { "id":1, "name":"test" }
1.2.2 修改文档 request 1 2 3 4 5 6 // 修改 POST /{index}/{type}/{_id} { "id":1, "name":"test2" }
1.2.3 局部修改文档 request 1 2 3 4 5 // 将ID为1的文档的name字段改成test2 POST /{index}/{type}/{_id}/_update { "doc": { "name":"test2" } }
1.2.4 删除文档 request 1 2 3 4 5 // 根据id删除 DELETE /{index}/{type}/{_id} // 删除订单1681323982163296643 DELETE order/table/1681323982163296643
1.2.5 根据id查找文档 request 1 2 3 4 5 // 根据id查找 GET /{index}/{type}/{_id} // 查询订单1681323982163296643 GET order/table/1681323982163296643
1.2.6 查找返回文档一部分 request 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 // 只返回order的 id和name POST order/_search { "_source": ["id","name"] } // 只返回order的 id和name POST order/_search { "_source": { "includes": [ "id", "name" ] } } // 不返回order的 name POST order/_search { "_source": { "excludes": ["name"] } }
2. 结构化查询 Query DSL 2.1 查询 2.1.1 term 精确查询
term:精确查询, 主要用于精确匹配,比如数字,日期,布尔值或 not_analyzed 的字符串
trems : 跟 term 有点类似,但 terms 允许指定多个匹配条件
request 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 // 根据手机号精确查询 POST /order/_search { "query": { "term": { "userMobile": "13126820209" } } } // 查询多个手机号 POST /order/_search { "query": { "terms": { "userMobile": [ "13126820209", "15232181101" ] } } }
2.1.2 match 模糊查询
request 1 2 3 4 5 6 7 8 9 10 11 12 // 查询 createTime 大于等于 1523111285000 ,小于等于 1523111286000 的订单 POST /order/_search { "query": { "range": { "createTime": { "gte": 1523111285000, "lte": 1523111286000 } } } }
2.1.4 exists 空值查询 exists 用于查找文档中是否包含指定字段 对应sql中的 not nullrequest 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 // vendorId1701cityId有值的订单 POST /order/_search { "query": { "exists":{ "field":"vendorId1701cityId" } } } // vendorId1701cityId 没有值的订单 POST /order/_search { "query": { "bool": { "must_not": [ { "exists": { "field":"vendorId1701cityId" } } ] } } }
2.1.5 nested 集合查询 request 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 // 查找 members.vendorName是张云天的订单 POST /order/_search { "query": { "nested": { "path": "members", "query": { "match": { "members.vendorName" : "张云天" } } } } } // 查找 members.vendorName 是张云天 并且 members.createVendorTime 是1651381826000 的订单 POST /order/_search { "query": { "nested": { "path": "members", "query": { "bool": { "must": [ { "match": { "members.vendorName": "张云天" } }, { "match": { "members.createVendorTime": 1651381826000 } } ] } } } } }
2.1.5 bool 多条件查询
must 多个查询条件的完全匹配,相当于 and 。
must_not 多个查询条件的相反匹配,相当于 not 。
should 至少有一个查询条件匹配, 相当于 or 。
filter 过滤 必须匹配,不贡献算分2.2 排序 2.2.1 sort 排序 request 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 // 结果集会先用第一排序字段来排序,当用用作第一字段排序的值相同的时候, 然后再用第二字段对第一排序值相同的文档进行排序 POST /order/_search { "query": { "term": { "cityName": "北京" } }, "sort": [ { "createTime": { "order": "desc" }, "updateTime": { "order": "desc" } } ] }
2.2.2 from size 分页 request 1 2 3 4 5 6 7 8 9 10 POST /order/_search { "query": { "term": { "cityName": "北京" } }, "from": 0, "size": 20 }
2.2.3 count 数量 request 1 2 // 查询数量 GET order/_count
2.3 聚合 aggs 类似sql的group by 2.3.1 主要概念
2.3.2 语法结构 request 1 2 3 4 5 6 7 8 9 10 11 { "aggregations" : { "<aggregation_name>" : { "<aggregation_type>" : { <aggregation_body> } [,"aggregations" : { [<sub_aggregation>]+ } ]? // 嵌套聚合查询,支持多层嵌套 } [,"<aggregation_name_2>" : { ... } ]* // 多个聚合查询,每个聚合查询取不同的名字 } }
aggregations - 代表聚合查询语句,可以简写为aggs
<aggregation_name> - 代表一个聚合计算的名字,可以随意命名,因为ES支持一次进行多次统计分析查询,后面需要通过这个名字在查询结果中找到我们想要的计算结果。
<aggregation_type> - 聚合类型,代表我们想要怎么统计数据,主要有两大类聚合类型,桶聚合和指标聚合,这两类聚合又包括多种聚合类型,例如:指标聚合:sum、avg, 桶聚合:terms、Date histogram等等。
<aggregation_body> - 聚合类型的参数,选择不同的聚合类型,有不同的参数。
aggregation_name_2 - 代表其他聚合计算的名字,意思就是可以一次进行多种类型的统计。
2.3.3 例子 2.3.3.1 terms 按字段聚合 request 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 // 对应sql select cityName,count(cityName) from table group by cityName POST /order/_search { "aggs": { "cityGroup": { "terms": { // 按cityName聚合 "field": "cityName" } } } } // 查询结果 { 。。。。 "aggregations": { "cityGroup": { "doc_count_error_upper_bound": 1029, "sum_other_doc_count": 118083, "buckets": [ { "key": "北京", "doc_count": 320859 }, { "key": "上海", "doc_count": 132995 }, 。。。 ] } } }
2.3.3.2 filter 自定义分组聚合 request 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 // 按filter聚合 POST /order/_search { "aggs": { "testAggs": { "filters": { "filters": { "北京统计": {"match":{"cityName":"北京"}}, "上海统计": {"match":{"cityName":"上海"}} } } } } } //查询结果 { 。。。。 "aggregations": { "testAggs": { "buckets": { "上海": { "doc_count": 132995 }, "北京": { "doc_count": 320862 } } } } }
2.3.3.3 range 按范围聚合 request 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 // 按范围聚合 POST /order/_search { "aggs": { "testRange":{ "range": { "field": "mlPrice", "ranges": [ { "to" : 50 }, { "from" : 50, "to" : 100 }, { "from" : 100 } ] } } } } //查询结果 { 。。。。 "aggregations": { "testRange": { "buckets": [ { "key": "*-50.0", "to": 50, "doc_count": 873767 }, { "key": "50.0-100.0", "from": 50, "to": 100, "doc_count": 0 }, { "key": "100.0-*", "from": 100, "doc_count": 15820 } ] } } }
2.3.3.4 子聚合 求平均值 request 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 // 对应sql select cityName,count(cityName),avg(mlPrice) from table group by cityName POST /order/_search { "aggs": { "cityGroup": { "terms": { // 按cityName聚合 "field": "cityName" }, "aggs": { // 嵌套聚合 "avg_score": { "avg": { // 求平均数 "field": "mlPrice" } } } } } } //查询结果 { 。。。。 "aggregations": { "cityGroup": { "doc_count_error_upper_bound": 1029, "sum_other_doc_count": 118086, "buckets": [ { "key": "北京", "doc_count": 320861, "avg_score": { "value": 54198.74264556926 } }, { "key": "上海", "doc_count": 132995, "avg_score": { "value": 53444.499958645065 } }, 。。。。 ] } } }
2.3.3.5 多个filed聚合 request 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 // 对应sql select cityName,community,count(1),avg(mlPrice) from table group by cityName,community POST /order/_search { "aggs": { "cityGroup": { "terms": { "script": "doc['cityName'].values+'-'+doc['community'].values", "size": 20 //返回条数 }, "aggs": { "avg_score": { "avg": { "field": "mlPrice" } } } } } } //查询结果 { 。。。。 "aggregations": { "cityGroup": { "doc_count_error_upper_bound": 1479, "sum_other_doc_count": 445778, "buckets": [ { "key": "[]-[]", "doc_count": 730484, "avg_score": { "value": -2503.5909282827674 } }, { "key": "[北京]-[]", "doc_count": 161802, "avg_score": { "value": -39.28776529338327 } }, { "key": "[北京]-[朝阳区]", "doc_count": 7962, "avg_score": { "value": -2849.4228836975635 } }, { "key": "[上海]-[浦东新区]", "doc_count": 4646, "avg_score": { "value": 42442.208136031 } } 。。。。 ] } } }
3. 子索引 3.1 子索引和nested的区别
nested
parent/child
插入、更新
更新时需要更新整个文档
父子文档可以独立更新
查询
文档存储在一起,读取性能高
父子文档单独存储,互不影响。但是为了维护join的关系,需要占用额外的内容,读取性能略差。
适用场景
子文档偶尔更新、查询为主
适用于更新频繁的情况,且子文档的数量远远超过父文档的数量
3.2 父子索引的创建 3.2.1 创建Mapping request 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 // 修改mapping,定义父文档 order_v1 定义三个子文档分别是 order_log order_dg_info order_zy_info PUT /{index}/{type}/_mapping { "properties": { "order_join_relation": { // 定义一个字段名称 "type": "join", // 类型为join "relations": { "order_v1": [ // 父文档值 "order_log", // 子文档值 "order_dg_info", "order_zy_info" ] } } } }
3.2.2 插入父文档 request 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 // 两种写法都可以 POST /{index}/{type}/{_id} { "id":1, "name":"test2", "order_join_relation":{ "name" : "order_v1" } } POST /{index}/{type}/{_id} { "id":1, "name":"test2", "order_join_relation": "order_v1" }
3.2.3 插入子文档 request 1 2 3 4 5 6 7 8 9 POST /{index}/{type}/{_id}?routing={parentID} { "id":1, "name":"test2", "order_join_relation":{ "name" : "order_log", "parent":{parentID} } }
3.3 查询 3.3.1 parent_id 基于父文档ID查询所有子文档 request 1 2 3 4 5 6 7 8 9 POST order/_search { "query":{ "parent_id": { // 关键字 "type":"order_log", // 要查询的子文档类型 "id":"5" // 父文档id } } }
3.3.2 has_parent 查询符合条件的父文档的所有子文档 request 1 2 3 4 5 6 7 8 9 10 11 12 13 POST order/_search { "query": { "has_parent": { // 关键字 "parent_type": "order_v1", // 父文档类型 "query": { // 父文档查询条件 "match": { "name": "test2" } } } } }
3.3.3 has_child 查询符合条件的子文档的所有父文档 request 1 2 3 4 5 6 7 8 9 10 11 12 13 14 POST order/_search { "query": { "has_child": { // 关键字 "type": "order_log", // 子文档类型 "min_children": 1, // 符合条件的子文档必须要1个以上,才返回父文档 "query": { // 子文档查询条件 "match": { "name": "test2" } } } } }
4. Painless Scripting 4.1 语法 官方文档 https://www.elastic.co/guide/en/elasticsearch/painless/master/painless-guide.html
1 2 3 4 5 "script" : { "lang" : "..." , "source" | "id" : "..." , "params" : { ... } }
lang: 定义脚本使用的语言, 默认painless
source, id: 脚本的主体, source后面跟着内联的脚本代码, id后面跟着脚本的id, 具体代码存在于脚本id对应的代码中
params: 定义一些变量的值, 使用params可以减少脚本的编译次数. 因为如果变量的值硬编码到代码中, 每次进行变量值得更改都会对脚本进行重新编译. 使用params则不会重新编译脚本.
4.1.1 访问某个field
4.2.1.2 修改文档时自定义参数 request 1 2 3 4 5 6 7 8 9 // 对应sql update order set age = concat(age,"4") where id = 1 POST order/table/1/_update { "script":{ "source":"ctx._source.age+= params.count", "lang":"painless", "params":{"count":4} } }
4.2.1.3 增加query条件、脚本判断 修改文档 request 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 // 对应sql update order set age = '123' where age = '34' POST order/table/_update_by_query { "script":{ "lang":"painless", "source":"ctx._source.age=123" }, "query":{ "term":{ "age":"34" } } } // 对应sql update order set age = '456' where age = '123' POST order/table/_update_by_query { "script":{ "lang":"painless", "source":"if (ctx._source.age == '123') {ctx._source.age = '456'}" } }
4.2.1.4 集合增加、删除元素 request 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 // 增加tags的元素 // 注意:tags元素需要已经存在,并且类型是array。否则会异常 POST order/table/1/_update { "script": { "source": "ctx._source.tags.add(params.tag)", "lang": "painless", "params": { "tag": "blue" } } } // 删除tags的元素 POST order/table/1/_update { "script": { "source": "if (ctx._source.tags.contains(params.tag)) { ctx._source.tags.remove(ctx._source.tags.indexOf(params.tag)) }", "lang": "painless", "params": { "tag": "blue" } } }
4.2.1.5 nested 增加、删除、修改 request 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 // 样例数据 { "detail": [ { "name": "美团", "nid": 1200 } ], "id": 1 } // 增加 POST /order/table/1/_update { "script": { "lang": "painless", "source": "ctx._source.detail.add(params.data);", "params": { "data": { "name": "百度", "nid": 1300 } } } } // 修改 POST /order/table/1/_update { "script": { "lang": "painless", "source": "for(e in ctx._source.detail){if (e.name == params.name) {e.nid = params.nid;}}", "params": { "name": "百度", "nid": 1500 } } } // 删除 POST /order/table/1/_update { "script": { "lang": "painless", "source": "ctx._source.detail.removeIf(it -> it.nid ==params.nid);if(ctx._source.detail.length == 0){ctx.op='delete'}", "params":{ "nid": 1200 } } }
4.2.2查询文档 4.2.2.1 使用脚本增加筛选条件 request 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 // 查询userMobile是135开头的订单 POST order/_search { "query": { "bool": { "filter": { "script": { "script": { "source":"doc['userMobile'] != null && doc['userMobile'].value!= null && doc['userMobile'].value.startsWith('135')" } } } } } }
4.2.2.2 使用脚本自定义返回字段 request 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 // 自定义字段 POST order/_search { "script_fields": { "shortOrderId-test": { "script": { "lang":"painless", "source":"doc['shortOrderId'].value * params.num", "params": { "num":100 } } } } }
4.2.2.3 使用脚本排序 request 1 2 3 4 5 6 7 8 9 10 11 12 13 14 // 查询userMobile是135开头的订单 POST order/_search { "sort": { "_script":{ "type":"number", "order":"desc", "script":{ "lang":"painless", "source":"doc['sgSrAllPrice'].value + doc['onlyDgFormMlPrice'].value" } } } }
4.2.2.4 使用脚本聚合 request 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 // 对应sql select cityName,community,count(1),avg(mlPrice) from table group by cityName,community POST order/_search { "aggs": { "cityGroup": { "terms": { "script": "doc['cityName'].values+'-'+doc['community'].values", "size": 20 //返回条数 }, "aggs": { "avg_score": { "avg": { "field": "mlPrice" } } } } } } //查询结果 { 。。。。 "aggregations": { "cityGroup": { "doc_count_error_upper_bound": 1479, "sum_other_doc_count": 445778, "buckets": [ { "key": "[]-[]", "doc_count": 730484, "avg_score": { "value": -2503.5909282827674 } }, { "key": "[北京]-[]", "doc_count": 161802, "avg_score": { "value": -39.28776529338327 } }, { "key": "[北京]-[朝阳区]", "doc_count": 7962, "avg_score": { "value": -2849.4228836975635 } }, { "key": "[上海]-[浦东新区]", "doc_count": 4646, "avg_score": { "value": 42442.208136031 } } 。。。。 ] } } }
5. Ingest pipelines 文档 https://www.elastic.co/guide/en/elasticsearch/reference/master/ingest.html