前言
❤Java学习路线个人总结-博客
❤欢迎点赞👍收藏⭐留言 📝分享给需要的小伙伴
索引操作
查看集群中索引?
GET /_cat/indices?v
创建索引?
PUT /index?pretty
ES的API组成结构:使用RESTful API风格来命名API
API基本格式:http://<ip>:<port>/<索引>/<类型>/<文档id> 常用HTTP动词
常用HTTP动词:GET/PUT/POST/DELETE
PUT 执行创建或修改,如确定document的ID时
POST一般用于改变对象或查询,如不确定document的ID,可以直接POST, ES可以 自己生成不会发生碰撞的UUID
GET 一般用于查询
DELETE 用于删除
HEAD 请求获取对象的基础信息,如检查文档是否存在
我们现在有一个业务需求就是存储订单数据,需要创建订单文档,如下操作:
一个文档必须的三个元数据元素如下
_index文档在哪存放
_type文档表示的对象类别
_id文档唯一标识,id可以自己指定,也可以自动生成
是否主键 | 字段名 | 字段描述 | 数据类型 | 分词 |
---|---|---|---|---|
是 | orderId | 订单ID | long | 否 |
否 | userId | 用户ID | long | 否 |
否 | orderNo | 订单号 | string | 否 |
否 | userName | 用户名 | string | 否 |
否 | totalPrice | 价格 | float | 否 |
否 | address | 收货地址 | string | 是 |
否 | createTime | 创建时间 | data | 否 |
如果不创建mapping,ES会根据文档的字段数据自动识别类型 这里需要创建自己定义的mapping
创建自定义mapping
PUT或者POST
PUT /order_index/_mapping/order_type/
{
"order_type": {
"properties": {
"4": {
"type": "text"
},
"access_time": {
"type": "text"
},
"userName": {
"type": "text"
},
"totalPrice": {
"type": "float"
},
"address": {
"type": "text",
"analyzer": "ik_smart",
"search_analyzer": "ik_smart"
},
"createTime": {
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
}
}
}
}
删除索引
DELETE /index?pretty
文档操作
新增文档
PUT /index/type/id
{
"json数据"
}
es默认会对document每个field都建立倒排索引,让其可以被搜索
使用bulk批量写入数据
bulk api
POST _bulk
{ "index" : { "_index" : "test", "_type" : "_doc", "_id" : "1" } }
{ "field1" : "value1" }
{ "delete" : { "_index" : "test", "_type" : "_doc", "_id" : "2" } }
{ "create" : { "_index" : "test", "_type" : "_doc", "_id" : "3" } }
{ "field1" : "value3" }
{ "update" : {"_id" : "1", "_type" : "_doc", "_index" : "test"} }
{ "doc" : {"field2" : "value2"} }
批量插入,如:
POST _bulk
{"index" : { "_index" : "order_index", "_type" : "order_type", "_id" : "1" } }
{"orderId":10001,"userId":10001,"orderNo":"a10001","userName":"John","totalPrice":50.00,"address":"江苏省南京市江宁区XXX","createTime":"2018-05-16 14:08:00"}
{"index" : { "_index" : "order_index", "_type" : "order_type", "_id" : "2" } }
{"orderId":10002,"userId":10002,"orderNo":"a10002","userName":"Jane","totalPrice":80.00,"address":"江苏省南京市鼓楼区XXX","createTime":"2018-05-16 14:30:00"}
{"index" : { "_index" : "order_index", "_type" : "order_type", "_id" : "3" } }
{"orderId":10003,"userId":10003,"orderNo":"a10003","userName":"Douglas","totalPrice":100.00,"address":"江苏省南京市玄武区XXX","createTime":"2018-05-16 14:33:00"}
查询文档
GET /index/type/id
修改文档
部分修改相比全量替换的优点: 1.所有查询、修改都是在ES的一个shard中完成的,提升了网络性能 2.减少了查询和修改的时间间隔,减少了并发冲突情况,几乎是毫秒级,部分修改时es内部会自动 执行乐观锁并发控制策略
PUT /index/type/id
{
"json数据"
}
更新文档
jsonex/type/id/_update
{
"doc": {
"field":""
}
}
删除文档
删除一个文档
DELETE /order_index/order_type/1
删除索引
DELETE /order_index 删除操作本身很危险,删除索引时会删除它所有的文档数据
嵌套对象索引
PUT /test
{
"settings": {
"number_of_replicas": 1,
"number_of_shards": 5
},
"mappings": {
"properties": {
"name":{
"type": "text"
},
"age":{
"type": "integer"
},
#嵌套对象
"test1":{
"type": "nested",
"properties": {
"name1":{
"type":"text"
},
"age1":{
"type":"integer"
}
}
}
}
}
}
#创建数据1
POST /test/_doc/111
{
"age":123,
"name":"张三",
"test1":{
"age1":321,
"name1":"李四"
}
}
#创建数据2
POST /test/_doc/222
{
"age":123,
"name":"张三",
"test1":[
{
"age1":321,
"name1":"李四"
},
{
"age1":321,
"name1":"李四"
}
]
}
搜索文档
简单搜索
全文搜索
GET /order_index/order_type/_search
_id查询,pretty以易读的格式返回
GET /order_index/order_type/1
GET /order_index/order_type/1?pretty
如果只想返回文档的 _source 字段,不需要其他元数据
GET /order_index/order_type/1/_source
返回部分字段
GET /order_index/order_type/1/_source?orderId,orderNo
根据字段查询, 通过URL参数来传递查询信息
GET /order_index/order_type/_search?q=orderId:10001
传JSON体参数,POST请求
POST /order_index/order_type/_search
{
"query": {
"match": {
"orderId": 10001
}
}
}
返回从10到19的文档,注意:如果没有使用size字段, 默认为10
POST /order_index/order_type/_search
{
"query": { "match_all": {} },
"from": 10,
"size": 10
}
字段orderId降序排列
POST /order_index/order_type/_search
{
"query": {
"match_all": {}
},
"sort": {
"orderId": {
"order": "desc"
},
"userId": {
"order": "desc"
}
}
}
mget查询
POST _mget
{
"docs": [
{
"_index": "order_index",
"_type": "order_type",
"_id": 1
},
{
"_index": "order_index",
"_type": "order_type",
"_id": 2
}
]
}
使用_all字段查询
_all字段是把所有其它字段中的值,以空格为分隔符组成一个大字符串,_all能让你在不知道要查找的内容是属于哪个具体字段的情况下进行搜索 query_string 和 simple_query_string 查询默认都是查询 _all 字段
POST /order_index/order_type/_search
{
"query": {
"query_string": {
"query": "鼓楼"
}
}
}
等同于:
GET /order_index/order_type/_search?q=鼓楼
基础搜索
了解以下查询关键词: match_all match multi_match match_phrase range term和terms bool查询包含:must、must_not、should、filter wildcards regexp prefix Phrase Matching
分页查询文档
分页查询文档
GET /index/type/_search
{
"query": { "match_all": {} },
"from": 1,
"size": 1
}
highlight 高亮搜索文档
highlight 高亮搜索文档,会将搜索词高亮显示
GET /index/type/_search
{
"query" : {
"match" : {
"producer" : "producer"
}
},
"highlight": {
"fields" : {
"producer" : {}
}
}
}
match_all 查询
对所有文档查询,默认查询前10条数据,按_score降序排序
POST /order_index/order_type/_search
{
"query": {
"match_all": {}
}
}
match 查询
match查询是一个标准查询,不管你需要全文本查询还是精确查询基本上都要用到它。 但只能针对一个字段。 如果你使用 match 查询一个全文本字段,它会在真正查询之前用分析器先分析match一下查询字符
POST /order_index/order_type/_search
{
"query": {
"match": {
"address": "鼓楼区"
}
}
}
如果用match下指定了一个确切值,在遇到数字,日期,布尔值或者not_analyzed 的字符串时,它将为你搜索你给定的值: 如:
{ "match": { "totalPrice": 26 }}
{ "match": { "createTime": "2014-09-01" }}
{ "match": { "public": true }}
{ "match": { "userName": "Jane" }}
multi_match 查询
multi_match查询允许你做match查询的基础上同时多个字段搜索同一个,相当于or查询
POST /order_index/order_type/_search
{
"query": {
"multi_match": {
"query": "Jane",
"fields": [
"userName",
"address"
]
}
}
}
match_phrase查询
match_phrase 短语搜索文档 要求输入的搜索词,必须在指定的字段文本中,完全包含一模一样的,才可以作为结果返回
POST /order_index/order_type/_search
{
"query": {
"match_phrase": {
"address": "鼓楼区"
}
}
}
range 查询
range过滤允许我们按照指定范围查找一批数据 gt :: 大于 gte:: 大于等于 lt :: 小于 lte:: 小于等于
POST /order_index/order_type/_search
{
"query": {
"bool": {
"filter": {
"range": {
"totalPrice": {
"gt": 20,
"lt": 80
}
}
}
}
}
}
term 查询
term主要用于精确匹配哪些值,比如数字,日期,布尔值或 not_analyzed 的字符串(未经分词的文本数据类型)
POST /order_index/order_type/_search
{
"query": {
"bool": {
"filter": {
"term": {
"totalPrice": 100
}
}
}
}
}
terms 过滤
terms 跟 term 有点类似,但 terms 允许指定多个匹配条件。 如果某个字段指定了多个值,那么文档需要一起去做匹配
POST /order_index/order_type/_search
{
"query": {
"bool": {
"filter": {
"terms": {
"totalPrice": [
100,
80
]
}
}
}
}
}
bool 查询
Bool查询对应Lucene中的BooleanQuery,它由一个或者多个子句组成,每个子句都有特定的类型。
must 返回的文档必须满足must子句的条件,并且参与计算分值
filter 返回的文档必须满足filter子句的条件。但是不会像Must一样,参与计算分值
should 返回的文档可能满足should子句的条件。在一个Bool查询中,如果没有must或者filter,有一个或者多个should子句,那么只要满足一个就可以返回。minimum_should_match参数定义了至少满足几个子句。
must_not 返回的文档必须不满足must_not定义的条件。
POST /order_index/order_type/_search
{
"query": {
"bool": {
"must": {
"match": {
"address": "南京市"
}
},
"must_not": {
"match": {
"totalPrice": "50"
}
},
"should": [
{
"match": {
"totalPrice": "80"
}
},
{
"range": {
"createTime": {
"gte": "2018-05-15 14:31:00"
}
}
}
]
}
}
}
wildcards
使用标准的shell通配符查询
POST /order_index/order_type/_search
{
"query": {
"wildcard": {
"address": "南?市*"
}
}
}
regexp 查询
正则表达式查询
POST /order_index/order_type/_search
{
"query": {
"regexp": {
"orderNo": "a[0-9]+"
}
}
}
prefix 查询
以什么字符开头的,可以更简单地用 prefix
POST /order_index/order_type/_search
{
"query": {
"prefix": {
"address": "江"
}
}
}
聚合搜索
聚合查询需要设置size如果不设置size会查询出其他数据消耗性能
求和 Sum求和
POST /order_index/order_type/_search
{
"size": 0,
"aggs": {
"return_totalPrice": {
"sum": {
"field": "totalPrice"
}
}
}
}
平均
POST /order_index/order_type/_search
{
"size": 0,
"aggs": {
"return_avg_totalPrice": {
"avg": {
"field": "totalPrice"
}
}
}
}
最大最小 max、min
POST /order_index/order_type/_search
{
"size": 0,
"aggs": {
"return_min_totalPrice": {
"min": {
"field": "totalPrice"
}
}
}
}
POST /order_index/order_type/_search
{
"size": 0,
"aggs": {
"return_max_totalPrice": {
"max": {
"field": "totalPrice"
}
}
}
}
统计查询
POST /order_index/order_type/_search
{
"size": 0,
"aggs": {
"return_stats_totalPrice": {
"stats": {
"field": "totalPrice"
}
}
}
}
分组
POST /order_index/order_type/_search
{
"size": 0,
"aggs": {
"group_by_totalPrice": {
"terms": {
"field": "totalPrice"
}
}
}
}
多条件聚合
比如按totalPrice升序,按orderId分组
#aggs聚合 totalPrice只是一个名字 terms过滤 field 条件也可以写script脚本进行聚合查询
POST /order_index/order_type/_search
{
"size": 0,
"aggs": {
"totalPrice": {
"terms": {
"field": "totalPrice",
"order": {
"_count": "asc"
}
}
},
"group_by_totalPrice": {
"terms": {
"field": "orderId"
}
}
}
}
嵌套聚合查询
GET /event-20210514134033531/_search
{
"aggs":{
"my_name":{
"terms":{
"field":"lid",
"size":1000
},
"aggs":{
"my_name1":{
"terms":{
"field":"csip_country_name.keyword",
"size":1000
},
"aggs":{
"my_name3":{
"terms":{
"field":"csip_region_name.keyword",
"size":1000
}
}
}
}
}
}
},
"from":1,
"size":0
}
//结果
{
"my_name":{
"doc_count_error_upper_bound":0,
"sum_other_doc_count":38128,
"buckets":[
{
"key":5638138383101068,
"doc_count":1,
"my_name1":{
"doc_count_error_upper_bound":0,
"sum_other_doc_count":0,
"buckets":[
{
"key":"中国",
"doc_count":1,
"my_name3":{
"doc_count_error_upper_bound":0,
"sum_other_doc_count":0,
"buckets":[
{
"key":"江苏省",
"doc_count":1
}
]
}
}
]
}
}
]
}
}
高级搜索
查询DSL有2种:查询DSL(query DSL)和过滤DSL(filter DSL) 为什么filter会快?
查询在Query查询上下文和Filter过滤器上下文中,执行的操作是不一样的:
Query查询上下文:
在查询上下文中,查询会回答这个问题——“这个文档匹不匹配这个查询,它的相关度高么?” 如何验证匹配很好理解,如何计算相关度呢?之前说过,ES中索引的数据都会存储一个_score分值,分值越高就代表越匹配。另外关于某个搜索的分值计算还是很复杂的,因此也需要一定的时间。 查询上下文 是在 使用query进行查询时的执行环境,比如使用search的时候。
Filter过滤器上下文: 在过滤器上下文中,查询会回答这个问题——“这个文档匹不匹配?” 答案很简单,是或者不是。它不会去计算任何分值,也不会关心返回的排序问题,因此效率会高一点。 过滤上下文 是在使用filter参数时候的执行环境,比如在bool查询中使用Must_not或者filter。
另外,经常使用过滤器,ES会自动的缓存过滤器的内容,这对于查询来说,会提高很多性能。
嵌套对象查询
- 查询条件
{
"query": {
"bool": {
"must": [
{
"match": {
"tags.name": "VPN"
}
}
]
}
}
}
- 查询结果
{
"_index": "asset",
"_type": "_doc",
"_id": "501",
"_score": 1.0,
"_source": {
"tags": [
{
"color": "#33d780",
"name": "VPN"
}
],
"grade": 0,
"name": "VPN设备",
"interfaceInfo": [
{
"ip": "10.67.7.67",
"mac": ""
}
],
"status": 1
}
}
关联查询
给order表添加关联字段
如果有多个集合
{
"doc": {
"user": [
{
"userId": "2",
"userName": "bbb",
"mobile": "138******13",
"age": "28",
"sex": "M"
},
{
"userId": "1",
"userName": "aaa",
"mobile": "138******12",
"age": "27",
"sex": "F"
}
]
}
}
查询结果
POST /order_index/order_type/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"orderNo": "a10001"
}
},
{
"match": {
"user.userId": 1
}
},
{
"match": {
"user.age": 27
}
}
]
}
}
}
大于1W条数据
track_total_hits
返回大于10000条数据