ES 语句
>d当前语句均为在Kibana中使用的语句
>iDate:06-04-2021
所有演示语句,均以'i_iot_run'索引(表)为例
>d**除查询外,索引操作若要执行,请自建测试索引,测试完后,请删除所建索引。**
>iES查询用到的包,当前用到的,并不是所有。
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.index.query.TermsQueryBuilder;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.PipelineAggregatorBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.AvgAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.SumAggregationBuilder;
import org.elasticsearch.search.aggregations.pipeline.BucketSortPipelineAggregationBuilder;
import org.elasticsearch.search.aggregations.pipeline.ParsedSimpleValue;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
### 添加索引
添加数据前,不提前创建索引,数据也可以插入,但是格式不受控制。
```
只添加索引
PUT i_iot_run
添加索引,并设置shard和mapping
PUT i_iot_run
{
"setting":{
"number_of_replicas": 0
},
"mapping":{
"properties": {
"endTime": {
"type": "date",
"format": "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
},
"id": {
"type":"long"
},
"imei": {
"type":"keyword"
},
"intervals": {
"type":"long"
},
"startTime": {
"type":"date",
"format":"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
},
"memberId": {
"type":"long"
},
"projectId": {
"type":"long"
},
"partnerId": {
"type":"long"
},
"memberTypeName": {
"type":"keyword"
},
"dataAuthority": {
"role":{
"type":"text",
"keyword":{
"type": "keyword",
"ignore_above": 256
}
},
"depart":{
"type": "long"
},
},
"regionId": {
"type":"long"
},
"workUnit": {
"type":"keyword"
},
"workAmount": {
"type":"float"
}
}
}
}
```
---
### 修改索引所在shard
```
POST _reindex
{
"source": {
"index": "i_iot_run"
},
"dest": {
"index": "i_iot_run_0"
}
}
```
---
### 查看索引mapping
```
GET i_iot_run/_mapping
```
---
### 查询有多少索引
```
GET _cat/indices?v
```
---
### 查询索引中所有数据
```
GET i_iot_run/_search
OR
GET i_iot_run/_search{
"query": {
"match_all": {}
}
}
#默认返回10条记录。
```
---
### in & is
```
GET i_iot_run/_search
{
"query": {
"terms": {
"memberId": [
333,
933
]
}
}
}
{
"query": {
"term": {
"memberId": 333
}
}
}
terms : 匹配一个字段的多个值。 可理解为 => in
term:匹配一个字典的一个值。 可理解为 => is
```
---
### in & is 对应的JAVA代码
```
in
TermsQueryBuilder matchIotCodes = new TermsQueryBuilder("dataAuthority.depart", String.valueOf(memberId));
is
MatchQueryBuilder matchMemberId = new MatchQueryBuilder("memberId", memberId);
TermQueryBuilder matchIotCodes = new TermQueryBuilder("dataAuthority.depart", String.valueOf(memberId));
完整代码请查看相关项目。
```
Match:会对查询的关键词进行分词,然后根据分词后的结果,进行匹配。
Term:直接使用关键词查询,不会分词。
---
### or查询
```
GET p_electron_card/_search
{
"query": {
"bool": {
"must": [
{
"terms": {
"dataAuthority.depart": [
585
]
}
},
{
"bool": {
"should": [
{
"match": {
"nickName": "测试"
}
},
{
"match": {
"imei": "测试"
}
},
{
"match": {
"personalPhone": "测试"
}
}
]
}
}
],
"must_not": [
{
"term": {
"validState": 0
}
}
]
}
}
}
@modify 03/30/2022
```
以上代码片段中,重要的一点是,第二层'bool'块。第二层'bool'中的'should'中的must,是or查询的子项。如果直接使用第二层'bool'块,则无法达到or查询的效果。
---
### Or查询对应Java代码
```
// 构建or查询容器
BoolQueryBuilder orBool = new BoolQueryBuilder();
// 构建or查询子项
MatchQueryBuilder matchMemberId = new MatchQueryBuilder("memberId", memberId); // 匹配顶级机构ID
MatchQueryBuilder matchRegionId = new MatchQueryBuilder("regionId", memberId); // 匹配大区ID
MatchQueryBuilder matchProjectId = new MatchQueryBuilder("projectId", memberId); // 匹配项目ID
orBool.should(matchMemberId);
orBool.should(matchRegionId);
orBool.should(matchProjectId);
or查询,需要放入到bool.must中。
完整代码,请查看相关项目
```
---
### 范围查询
```
GET i_iot_run/_search
{
"query": {
"range": {
"startTime": {
"gte":"2021-06-01T00:00:00.000Z",
"lte":"2021-06-01T23:59:59.999Z"
}
}
}
}
```
### 范围查询对应Java代码
```
// 时间范围查询
RangeQueryBuilder datetimeRange = new RangeQueryBuilder("startTime") // 查询条件,范围
.gte(begin)
.lte(end)
.format(Constant.UTC_DATE_FORMAT);
// 将范围查询,放入外层bool.filter中。
boolQueryBuilder.filter(datetimeRange);
完整上下文代码,请查看相关项目。
```
---
### 多条件查询
```
#查询时间在6.1号,并且物联网编码为"868120237173650","868120237174138","868120246402850","868120246397340"的设备信息
GET i_iot_run/_search
{
"query":{
"bool":{
"must":[
{
"terms":{
"imei":[
"868120237173650",
"868120237174138",
"868120246402850",
"868120246397340"
]
}
}
],
"filter":[
{
"range": {
"startTime": {
"gte":"2021-06-01T00:00:00.000Z",
"lte":"2021-06-01T23:59:59.999Z"
}
}
}
]
}
}
"size": 200
}
#size: 返回数据集合大小。默认10条。
```
---
### 索引中添加字段
```
POST i_iot_run/_mapping
{
"properties": {
"workUnit2": {
"type": "keyword"
}
}
}
```
---
### 批量插入数据
```
POST i_iot_run/_bulk
{"index":{"_id":1}}
{"data":{"imei":"....","memberId":1,"projectId":1.....}}
{"index":{"_id":2}}
{"data":{"imei":"....","memberId":2,"projectId":2.....}}
{"index":{"_id":3}}
{"data":{"imei":"....","memberId":3,"projectId":3.....}}
_bulk:_bulk是批量操作API,不仅可以执行批量插入。
```
>d 尝试批量操作,请自建测试索引。
---
### 模糊查询
```
GET i_iot_run
{
"query": {
"wildcard": {
"memberTypeName": "J*"
}
}
}
```
>i1:J* => 以'J'开头
2:*J:=> 以'J'结尾
3:\*J\* => 包含'J'
>d**模糊查询数据量越大效率越低,当查询内容较多,数据量较大时建议将该字段设置成text进行分词,然后通过match进行匹配。**
---
### 模糊查询对应Java代码
```
**.must(QueryBuilders.termsQuery(fieldName, value));
```
>i当前项目中并没有使用到模糊查询,若用到模糊查询,请自行在项目中尝试。
---
### 聚合查询-分组
```
GET i_iot_run/_search
{
"query": {
"bool": {
"must": [
{
"terms": {
"imei": ["...","..."]
}
}
],
"filter": {
"range": {
"startTime": {
"gte":"..",
"lte":".."
}
}
}
}
},
"size": 0,
"aggs": {
"group_by_***": {
"terms": {
"field": "workUnit"
},
"aggs": {
"group_by_***": {
"terms": {
"field": "projectId"
}
}
}
}
}
}
```
>d**由于不能出现重复的标签。(一个语句块中,不能出现两个'aggs'),所以分组都是包含的关系。若有多个,继续往下嵌套追加即可。但一定要想清楚其中的关系。**
在Java中,要使用嵌套循环,来获取分组后的数据。这里嵌套了几层'aggs',Java中就嵌套循环几层。
---
### 聚合查询-求和
```
GET i_iot_run/_search
{
"query": {
"bool": {
"must": [
{
"terms": {
"imei": ["...","..."]
}
}
],
"filter": {
"range": {
"startTime": {
"gte":"..",
"lte":".."
}
}
}
}
},
"size": 0,
"aggs": {
"group_by_***": {
"terms": {
"field": "workUnit"
},
"aggs": {
"group_by_***": {
"terms": {
"field": "projectId"
}
},
"aggs": {
"runTime": {
"sum": "intervals"
}
}
}
}
}
}
# 最后一个'aggs'中,runTime为别名,同SQL中的as('runTime'),'sum'是使用'sum'API进行计算。'intervals'是要进行计算的字段。
```
---
### 聚合查询-计算
```
GET i_iot_run/_search
{
"query": {
"bool": {
"must": [
{
"terms": {
"imei": ["...","..."]
}
}
],
"filter": {
"range": {
"startTime": {
"gte":"..",
"lte":".."
}
}
}
}
},
"size": 0,
"aggs": {
"group_by_***": {
"terms": {
"field": "workUnit"
},
"aggs": {
"group_by_***": {
"terms": {
"field": "projectId"
}
},
"aggs": {
"runTime": {
"sum": "intervals"
},
"hours": {
"bucket_script": {
"bucket_path": {
"_runTime": "runTime"
},
"script": "(float) (params._runTime / 3600000)"
}
}
}
}
}
}
}
```
>i最后一个'aggs'中,hours为别名,同SQL中的as('hours'),'bucket_script'是使用'script'脚本进行计算,'bucket_path' 是使用字段的路径,_runTime是别名,runTime是上面聚合的别名,_runTime 指向 runTime。
script 中的语句,使用路径中的变量时,切记一定要加前缀'params.',否则找不到。
---
### 执行查询
```
SearchHits<IotRunData> iotRunDataSearchHits = elasticsearchRestTemplate.search(queryBuilder.build(), IotRunData.class);
```
---
### 修改
```
POST i_iot_run/_update_by_query
{
"query": {
"bool": {
"must": [
{
"terms": {
"imei": [
"868120272193621"
]
}
},
{
"terms": {
"regionName": [
"融创南京大区"
]
}
}
]
}
},
"script": {
"source": "ctx._source.regionName = params['regionName']",
"params": {
"regionName":"融创华北大区"
},
"lang": "painless"
}
}
```
根据查询条件修改。
上面代码片段中,是根据物联网编码和大区查找数据,然后修改大区名称。
'ctx._source' 是固定格式
'.regionName' 是字段名
'params' 对应下面的参数列表
---
#### 数组中追加元素
```
POST test_cross/_update_by_query
{
"query": {
"bool": {
"must": [
{
"terms": {
"imei": [
"345345345"
]
}
}
]
}
},
"script": {
"source": "ctx._source.dataAuthority.depart.add(params.depart)",
"params": {
"depart":3
},
"lang": "painless"
}
}
```
追加元素时,使用add()添加。
---
#### 数组中删除某个值
```
POST test_cross/_update_by_query
{
"query": {
"bool": {
"must": [
{
"terms": {
"imei": [
"345345345"
]
}
}
]
}
},
"script": {
"source": "ctx._source.dataAuthority.depart.remove(ctx._source.dataAuthority.depart.indexOf(params.depart))",
"params": {
"depart":3
},
"lang": "painless"
}
}
```
删除时需要用indexOf找到元素,然后使用remove移除,直接remove会报错。
```
{
"script": {
"source": "ctx._source.comments.add(params.new_comment)",
"params": {
"new_comment": {
"name": "xiang",
"age": 25,
"rating": 18,
"comment": "very very good article...",
"commented_on": "3 Nov 2018"
}
}
}
}
```
添加对象
```
{
"script": {
"lang": "painless",
"source": "ctx._source.comments.removeIf(it -> it.name == 'John');"
}
}
```
移除数组中的一个对象
---
### 夸字段搜索
```
GET b_equipment_entity/_search
{
"query": {
"bool": {
"must": [
{
"terms": {
"dataAuthority": [
989
]
}
},
{
"multi_match": {
"query": "战神530 53000285 401530",
"fields": ["memberTypeName","equipmentNo","imei"]
}
}
]
}
}
}
```
### 根据聚合后字段进行排序
应该可以多字段排序,没有进行测试,有兴趣的可以测试一下。猜测排序的顺序应该跟添加到list中的顺序有一定关系。
```
...
/* 聚合内排序 step:1 */
List<FieldSortBuilder> sorts = new ArrayList<>();
/* 聚合内排序 step:2 */
sorts.add(SortBuilders.fieldSort("hours").order(SortOrder.DESC));
sourceBuilder.aggregation(
group_by_iotCode
.subAggregation(runTime)
.subAggregation(PipelineAggregatorBuilders.bucketScript("hours", hoursMap, hoursScript))
.subAggregation(project)
/* 聚合内排序 step:3 */
.subAggregation(PipelineAggregatorBuilders.bucketSort("hourSort",sorts))
);
...
```
### 删除索引
```
DELETE i_iot_run
```
---