ES SQL使用说明文档
一、Elasticsearch术语介绍
l 接近实时(NRT):
Elasticsearch 是一个接近实时的搜索平台。这意味着,从索引一个文档直到这个文档能够被搜索到有一个很小的延迟,包括如果做了集群的话,集群中的各个节点数据同步也是接近实时的。
l 集群(cluster):
一组拥有共同的 cluster name 的节点。
l 节点(node):
集群中的一个 Elasticearch 实例。
l 索引(index):
ElasticSearch将它的数据存储在一个或多个索引(index)中。用SQL领域的术语来类比,索引就像数据库,可以向索引写入文档或者从索引中读取文档。
l 文档类型(type):
文档类型(type)是用来规定文档的各个字段内容的数据类型和其他的一些约束,相当于关系型数据库中的表,一个索引(index)可以有多个文档类型(type)。
l 文档(document):
一个文档(document)相当于关系型数据库中的一行数据。
l 字段(Field):
相当于数据库中的column。
l 映射(Mapping):
相当于数据库中的schema,用来约束字段的类型,映射可以被明确地定义,或者在一个文档被索引的时候自动生成。
l 分片(Shard):
索引的子集,索引可以切分成多个分片,分布到不同的集群节点上。分片对应的是 Lucene 中的索引。分片分为主分片(Primary shard)和副本分片(Replica shard)每个主分片可以有0个或者多个副本。
Elasticsearch与关系数据的类比对应关系如下:
Relational DB -> Databases -> Tables -> Rows -> Columns
关系型数据库 数据库 表 行 列
Elasticsearch -> Indices -> Types -> Documents -> Fields
Elasticsearch 索引 类型 文档 域(字段)
由于Elasticsearch的查询语言(DSL)比较复杂,学习成本高。因此推荐使用第三方插件Elasticsearch-SQL,可用sql查询Elasticsearch,语法跟关系型数据库的sql有一些不同。
注意:使用Elasticsearch-SQL查询时:
1、在hue中查询时,select前不能有空格或者空行;
2、查询中字段名大小写敏感;
3、求个数时,不能用 count(1), 必须是count(*);
4、select 字段名,* from….时 后面的*不起作用;
5、目前支持中文字段查询,但不支持带特殊符号的字段作为where条件,例如不支持where 总订单数(条)>20;
6、两个整数类型字段相除时,得到的结果也是整数,此时至少一个字段需要化为小数(例如乘除1.0、加减0.0):
SELECT 慢充终端数,快充终端数,1.0*慢充终端数/快充终端数 as a
from etlddcharging
where 快充终端数>0 and 慢充终端数>0 limit 10
二、快速入门:
ES查询默认查询200条,最大查询10000条,可通过max_result_window修改。
1、查询index下的type:
SELECT fields from indexName WHERE conditions
SELECT fields from indexName/type WHERE conditions
SELECT fields from indexName/type1,indexName/type2 WHERE conditions
SELECT fields from indexName1,indexName2 WHERE conditions
--其中,fields前面不能使用别名或者table.:
select color,doubleValue from cars,test_wj limit 10 (正确)
select cars.color,test_wj.doubleValue from cars,test_wj limit 10 (错误)
2、使用别名:
ES-Sql字段支持使用别名,当select后面只有一个别名列,查询结果会列出所有的字段以及别名列,例如:
SELECT CityName as acity FROM mrp_userlabel LIMIT 10 ;
此时,若只想显示别名列,有两种解决方案:
l 使用exclude(*)排除其他列:
SELECT CityName as acity ,exclude(*) FROM mrp_userlabel LIMIT 10 ;
l select后面添加一个非别名列,这相当于自动加了include,使结果只包含选择的列名:
SELECT CityCode,CityName as acity FROM mrp_userlabel LIMIT 10 ;
3、分页查询:
SELECT * from mrp_userlabel limit 10,20
其中limit后面第一个参数是from,表示目标数据的偏移值,第二个参数是size,表示数据条数。以上查询第10到第30条数据[l1] 。但是ES最大查询默认max_result_window =10000条,当 from + size > max_result_window 时,es 将返回错误。
4、计算列--可以加减乘除固定数值,也可以两个字段之间进行加减乘除:
SELECT CharPower,CharMoneyEC,CharMoneySC,
CharPower + 2 as a,
CharPower - 2 as b,
CharPower * 2 as c,
CharPower / 2 as d,
CharPower % 2 as e,
CharMoneyEC + CharMoneySC as f,
CharMoneyEC - CharMoneySC as g,
CharMoneyEC * CharMoneySC as h,
CharMoneyEC / CharMoneySC as i,
CharMoneyEC % CharMoneySC as j
from mrp_userlabel where CityCode<>'11' limit 10
注意:两个整数类型字段相除时,得到的结果也是整数,此时至少一个字段需要化为小数(例如乘除1.0、加减0.0):
SELECT 慢充终端数,快充终端数,
1.0*慢充终端数/快充终端数 as a,慢充终端数/快充终端数 as b
from etlddcharging
where 快充终端数>0 and 慢充终端数>0 limit 10
5、数字范围过滤--大于等于小于运算:
l 字段跟固定数值之间的运算:
SELECT *
from mrp_userlabel
where CharPower > 0.9 and CharPower < 2.1 and CityName='北京市'
limit 10;
l 字段之间的运算1:【此时where后面只能跟一个条件,多了会报错】
解决方案:
SELECT CharMoney,CharMoneySC,CharPower FROM mrp_userlabel where script('doc["CharMoney"].value>doc["CharMoneySC"].value && doc["CharPower"].value>0.9')
limit 10;
或者
SELECT CharMoney,CharMoneySC,CharPower FROM mrp_userlabel where script('doc["CharMoney"].value>doc["CharMoneySC"].value') and CharPower > 0.9
limit 10;
-- script语法详见【6.1 Script基本用法:】
l 字段之间的运算2:【以下不支持】
解决方案:
SELECT CharMoney,CharMoneySC FROM mrp_userlabel where script('doc["CharMoney"].value+doc["CharMoneySC"].value>20')
limit 10 -- script语法详见【6.1 Script基本用法:】
6、查询日期字段:
见【3.2 函数支持】,使用date_format函数,支持传递时区。
7、group by分组,详情见【3.3 聚合】:
l group by 一个字段:
SELECT COUNT(*) FROM mrp_userlabel GROUP BY CityName;
l group by多个字段且使用limit时,需要使用terms(原因见【3.3.2.1 terms聚合】):
SELECT COUNT(*) FROM mrp_userlabel
GROUP BY terms(field='CityName',size='10000',alias='CityName'),
terms(field='MarketName',size='10000',alias='MarketName')
limit 10000;
l 按照日期分组,使用date_histogram聚合,可以指定日期格式以及时区(具体用法见【3.3.2.3 日期直方图(date histogram)聚合】):
SELECT count(*) FROM ChargeBillWideTable GROUP BY date_histogram(field='BeginTime','interval'='1d','alias'='yourAlias', 'format'='yyyy-MM-dd', 'time_zone'='+08:00', 'min_doc_count'=1,order='desc')
8、in或者not in用法:
某字段in一组值内时,in后面只能跟1024个值,超过会报错,可用IN_TERMS[l2] 代替in:
SELECT MarketName,CityName,DataTime, CustID
FROM mrp_userlabel
WHERE DataTime='2018-10-31T16:00:00.000Z'
and MarketName ='青岛特来电汽车充电有限公司'
and LabelLevel3 ='高价值用户'
and not CustID = IN_TERMS(
SELECT distinct CustID FROM mrp_userlabel
WHERE DataTime='2018-09-30T16:00:00.000Z'
and MarketName ='青岛特来电汽车充电有限公司'
and LabelLevel3 ='高价值用户'
limit 2000)
ORDER BY MarketName asc,CityName asc,DataTime asc
LIMIT 10000;
三、基本用法
3.1. 基本查询以及条件
l 基本查询语法为:
SELECT fields from indexName WHERE conditions
l 查询一个index下的type:
SELECT fields from indexName/type WHERE conditions
l 也可以一次性查询一个index下的多个type:
SELECT fields from indexName/type1,indexName/type2 WHERE conditions
l 也可以一次性查询多个index:
SELECT fields from indexName1,indexName2 WHERE conditions
--其中,fields前面不能使用别名或者table.:
select color,doubleValue from cars,test_wj limit 10 (正确)
select cars.color,test_wj.doubleValue from cars,test_wj limit 10 (错误)
3.1.1 SQL支持语句
SQL Select
SQL Delete(尚未开放)
SQL Where
SQL Order By
SQL Group By
SQL Limit (default is 200)
SELECT * FROM abnormalsoc_201801 WHERE PowerPerSoc > 0.9 LIMIT 10 ;
SELECT * FROM abnormalsoc_201801/abnormalsoc WHERE PowerPerSoc > 0.9 ORDER BY CanIndex DESC LIMIT 10 ;
SELECT * FROM abnormalsoc_201801 WHERE PowerPerSoc > 0.9 AND CtrlAddress = '42011700143' LIMIT 10 ;
3.1.2 SQL支持条件
SQL Like -(针对keyword类型字段,text类型字段不能使用like)
SQL AND & OR
SQL COUNT distinct
SQL In
SQL Between and
SQL Aliases
SQL NOT
SELECT count(distinct RelatedBillCode) FROM abnormalsoc_201801 where (CanIndex like '18%' or CanIndex like '19%') and CtrlAddress in ('42011700143','33011000371') limit 10;
SELECT * FROM test_wj where floatValue not Between 1.1 and 3.1 limit 10
--其中(Between 1.1 and 3.1)语法包括1.1、3.1。
3.1.3 SQL字段
字段可以按精确字段名称列出,也可以用通配符(*)[l3] 使用include/exclude语法。
include('d ') - 包括以“d”开头的所有字段
exclude('age') - 包括除“age”之外的所有字段
include(' Name'),exclude('lastName') - 包括以“name”结尾的所有字段,“lastName”除外。
SELECT CanIndex,include('Flink'),exclude('FlinkPorcessTimeTag') FROM abnormalsoc_201801 LIMIT 10 ;
字段使用别名时:
ES-Sql字段支持使用别名,当select后面只有一个别名列,查询结果会列出所有的字段以及别名列,例如:
SELECT CityName as acity FROM mrp_userlabel LIMIT 10 ;
此时,若只想显示别名列,有两种解决方案:
1)使用exclude(*)排除其他列:
SELECT CityName as acity ,exclude(*) FROM mrp_userlabel LIMIT 10 ;
2)select后面添加一个非别名列,这相当于自动加了include,使结果只包含选择的列名:
SELECT CityCode,CityName as acity FROM mrp_userlabel LIMIT 10 ;
3.2 函数支持
支持以下函数:
l Floor,向下取整;
l Trim,删除字符串首尾的空格;
l Log,数学上的对数函数,计算一个数字的自然对数;
l log10,数学上的对数函数;计算以10为基数的对数;
l substring,截取字符串;
l round,四舍五入为整数;
l sqrt,一个非负实数的平方根;
l concat_ws,根据分隔符连接字符串;
l + 加、- 减、* 乘、/ 除、% 取余、>大于、<小于、=等于、<> 不等于;
l case when;
l cast,支持INT, LONG, FLOAT, DOUBLE, STRING, DATETIME;
l date_format,日期格式化。
并且:
l select,groupBy支持函数和字段使用别名;
l 支持嵌套函数,例如,Trim(substring('newtype',0,3));
l 支持二元操作,例如,floor(substring(newtype,0,14)/100)/5)*5。
date_format函数支持传入时区参数(不传时区,默认东八区),如下:
SELECT CreateTime, date_format(CreateTime,'yyyy-MM-dd HH') as aa, date_format(CreateTime,'yyyy-MM-dd HH','+0800') as bb, date_format(CreateTime,'yyyy-MM-dd HH','+0000') as cc
from datachangelog_201812 limit 10;
-- CreateTime是东八区时间,aa、bb是东八区时间,cc是UTC时间。
SELECT LastCharTime,date_format(LastCharTime,'yyyy-MM-dd HH') as aa,date_format(LastCharTime,'yyyy-MM-dd HH','+0800') as bb,date_format(LastCharTime,'yyyy-MM-dd HH','+0000') as cc from mrp_userlabel limit 10;
--LastCharTime是UTC时间,aa、bb取值是东八区时间,cc是UTC时间。
其他例子:
SELECT CityName,CharPower, trim(CityName) as a1,floor(CharPower) as a2,round(CharPower) as a3,sqrt(CharPower) as a4,log(CharPower) as a5,log10(CharPower) as a6
from mrp_userlabel;
SELECT CharPower,CharMoneyEC,CharMoneySC,
CharPower + 2 as a,
CharPower - 2 as b,
CharPower * 2 as c,
CharPower / 2 as d,
CharPower % 2 as e,
CharMoneyEC + CharMoneySC as f,
CharMoneyEC - CharMoneySC as g,
CharMoneyEC * CharMoneySC as h,
CharMoneyEC / CharMoneySC as i,
CharMoneyEC % CharMoneySC as j
from mrp_userlabel where CityCode<>'11' limit 10
SELECT MarketID,substring(MarketID,0,3) as aa,
CityCode,CityName,concat_ws(',',CityCode,CityName) as bb
from mrp_userlabel;
select CityCode,case when CityCode='11' then '北京市' when CityCode='12' then '天津市' else '其他' end as a
from mrp_userlabel
limit 10
SELECT CityCode,DataTime, CAST(DataTime AS DATETIME) AS tt,cast(CityCode as INT)+1 as aa
from mrp_userlabel
limit 10;
3.3 聚合
3.3.1 Metrics(度量)
min
max
sum
count
avg
SELECT CanIndex,CtrlAddress, count(*),avg(PowerPerSoc), max(PowerPerSoc), min(PowerPerSoc),sum(PowerPerSoc)
FROM abnormalsoc_201801 group by CanIndex,CtrlAddress limit 10
stats(统计,查询结果包含:sum、avg、max、min、count基础度量):
percentiles(百分位数):
extended_stats(扩展统计,查询结果包含:方差、平方和、标准差、标准差界限以及max、avg等基础度量,注:只在数值型字段上使用):
SELECT stats(PowerPerSoc) FROM abnormalsoc_201801
SELECT percentiles(PowerPerSoc) FROM abnormalsoc_201801
SELECT extended_stats(PowerPerSoc) FROM abnormalsoc_201801
3.3.2 Buckets(桶)
3.3.2.1 terms聚合
l group by一个字段:
SELECT COUNT(*) FROM mrp_userlabel GROUP BY CityName;
l group by多个字段:
根据多个列进行group by时, select sum(x) from Table group by col1,col2 limit y 这种写法会造成结果不正确,因为limit只会加在第一个字段上,后面的字段会按照默认值,每个桶(bucket)默认返回10条数据,例如:
SELECT COUNT(*) FROM mrp_userlabel GROUP BY CityName, MarketName limit 10000;
这样所有的CityName,因为总数<10000,会被列出来,但每个CityName下最多返回10个MarketName,因为ES的默认桶返回值是10。解决方案为使用 group by terms()语法,正确写法:
SELECT COUNT(*) FROM mrp_userlabel
GROUP BY terms(field='CityName',size='10000',alias='CityName'),
terms(field='MarketName',size='10000',alias='MarketName')
limit 10000;
3.3.2.2 范围(range)聚合
字段后面跟上范围。例如,查询PowerPerSoc在0.5-1.0、1.0-2.0、2.0-3.0之间的数据条数:
SELECT COUNT(PowerPerSoc) FROM abnormalsoc_201801 GROUP BY range(PowerPerSoc, 0.5,1,2,3)
3.3.2.3 日期直方图(date histogram)聚合
设置时间字段(field)、区间('interval')、可选是否使用别名('alias')、时间格式('format')、时区('time_zone')、桶内最大数据条数('min_doc_count')、排序(order):
SELECT count(*) FROM ChargeBillWideTable GROUP BY date_histogram(field='BeginTime','interval'='1d','alias'='yourAlias', 'format'='yyyy-MM-dd', 'time_zone'='+08:00', 'min_doc_count'=1,order='desc')
3.3.2.4 日期范围(date range)聚合
设置字段以及带格式的区间,可选是否使用别名。
SELECT count(*) FROM mrp_userlabel GROUP BY date_range('alias'='yourAlias',field='DataTime','format'='yyyy-MM-dd' ,'2018-10-21','2018-10-22','now-7d','now-6d','now')
3.4 Union and Minus
实现Union & Minus,第一个查询字段名称应该与第二个查询字段名称一致,可以使用别名。
3.4.1 Union(慎重使用)
将第一个表的查询结果(不加limit,默认200条)跟第二个表的查询结果组合在一起,发送给客户端。
例子:
SELECT CityName FROM mrp_userlabel limit 1
union all
SELECT CityCode as CityName FROM mrp_userlabel limit 1
注:不建议,和分两次取结果一样,但效率会更慢。
3.4.2 Minus
3.4.2.1 基本实现
将第一个查询结果作为一个集合(已删除重复项),然后运行第二个查询,检查第二个查询的每条数据是否已经存在于第一个查询结果集中,若存在,则从集合中移除。最后返回集合。
例子:
一个字段:移除成都市的记录:
SELECT CityName FROM mrp_userlabel WHERE CityName in ('成都市','重庆市') limit 10
minus
SELECT CityName FROM mrp_userlabel WHERE CityName in ('成都市') limit 10
2个字段(对比一整条记录):还是会查出成都市的记录:
SELECT CityName, CityCode FROM mrp_userlabel WHERE CityName in ('成都市','重庆市') limit 10
minus
SELECT CityName, CityName as CityCode FROM mrp_userlabel WHERE CityName in ('成都市') limit 10
3.4.2.2 scrolling 滚动
当第二个查询数据量很大时,可使用scrolling 以提高性能。此时需要添加如下注释:
/*! MINUS_SCROLL_FETCH_AND_RESULT_LIMITS(maxFetchOnFirstTable,maxFetchOnSecondTable,docsFetchFromShardOnEachScroll) */
例子:
SELECT /*! MINUS_SCROLL_FETCH_AND_RESULT_LIMITS(100000,10000000,5000) */
CityName, CityCode FROM mrp_userlabel WHERE CityName in ('成都市','重庆市') limit 1000
minus
SELECT CityName, CityName as CityCode FROM mrp_userlabel WHERE CityName in ('成都市') limit 1000
3.4.2.3 Scrolling and Terms 优化
当只Minus一个字段的时候,有效。当两个查询数据量都很大的时候,可使用此优化以保证较低的负载。需要添加如下注释:
/*! MINUS_SCROLL_FETCH_AND_RESULT_LIMITS(maxFetchOnFirstTable,maxFetchOnSecondTable,docsFetchFromShardOnEachScroll) */
/! MINUS_USE_TERMS_OPTIMIZATION(true)/
例子:
SELECT /! MINUS_SCROLL_FETCH_AND_RESULT_LIMITS(100000,10000000,5000) /
/! MINUS_USE_TERMS_OPTIMIZATION(true)/
CityName FROM mrp_userlabel WHERE CityName in ('成都市','重庆市') limit 5000
minus
SELECT CityName FROM mrp_userlabel WHERE CityName in ('成都市') limit 5000
四、扩展ES功能
增加了一些ES特有的扩展功能:
ES MISSING
ES STATS
ES EXTENDED_STATS
ES PERCENTILES
ES TERMS/TERM
ES IDS syntax: IDS_QUERY(type, ids..)
ES QUERY_STRING
1)查找mrp_userlabel中,字段CustName(不)为空的数据:
SELECT * FROM mrp_userlabel where CustName is not missing
SELECT * FROM mrp_userlabel where CustName is missing
--以上is missing相当于is null
2)某字段in一组值内时,in后面只能跟1024个值,超过会报错,可用IN_TERMS[l4] 代替:
查找mrp_userlabel中,字段CityName(不)属于成都市或合肥市或重庆市的数据:
SELECT * FROM mrp_userlabel where CityName = IN_TERMS('成都市','合肥市','重庆市')
SELECT * FROM mrp_userlabel where not CityName = IN_TERMS('成都市','合肥市','重庆市')
3)查找mrp_userlabel中,字段CityName等于成都市的数据:
SELECT * FROM mrp_userlabel where CityName = TERM('成都市')
SELECT * FROM mrp_userlabel where not CityName = TERM('成都市')
4)查找mrp_userlabel中,主键_id等于**的数据:
SELECT * FROM mrp_userlabel where _id = IDS_QUERY(mrp_userlabel, '66f5c013-1f10-4557-b473-e22ba7b2cc6d_20181022','2e171f39-6ea1-40b1-8494-b0141fcbcbb2_20181022')
5)查找mrp_userlabel中,字段MarketName等于*的数据:
SELECT * FROM mrp_userlabel where q = query('MarketName:济南特来电新能源有限公司')
6)查找mrp_userlabel中,字段CustCode匹配正则表达式CD008.*的数据:
SELECT * FROM mrp_userlabel where CustCode = REGEXP_QUERY('CD008.*', 'INTERSECTION|COMPLEMENT|EMPTY', 10000)
五、注意事项
查询语句末尾如果不加limit,则默认返回200条数据。Limit最大值为10000,经过特殊设置的索引除外;
聚合时,不支持字段加减运算后聚合以及聚合后加减运算:
sum(CharMoneySC+CharMoneyEC)以及sum(CharMoneySC)+sum(CharMoneyEC)。可使用script脚本实现:
select sum(script('aa','return doc["尖时电量"].value + doc["平时电量"].value;')) as Total from etlchargebills
where BillSrc='SD' and 充电日期>='20160101+08:00' and 充电日期<'20190201+08:00'
group by 充电日期 order by 充电日期 limit 100
普通排序:
1)order by默认方式为asc升序,如果order by多个字段,且每个字段都为desc排序,需要每个字段后面都加上desc;
2)有limit限制的,limit必须放在order by后面才能排序正确:
SELECT CharPower,CharMoney
FROM mrp_userlabel
order by CharPower desc, CharMoney desc
limit 10
以上sql先按照“CharPower” 降序排列,“CharPower”值相同的,再按照“CharMoney”降序排列。
聚合排序:
1)group by一个字段,order by多个字段:只能按照最后一个字段排序:
2)同样的group by一个字段,order by后面跟一个维度+一个值的时候,排序只按照最后一个字段排序:
3)group by两个字段时,由于ES聚合的分桶机制,导致排序不正确:
解决方案:可在ES索引中增加一个字段AA,值=CityCode+CityName,然后按照AA分组排序即可解决。
查询时,注意将两侧集群切换一致,否则查询出错:
- 关于TopHits:
Sql虽然支持topHits写法,但是topHits不起作用,实际返回结果并没有具体值:
SELECT topHits('size'=2,floatValue='desc') FROM test_wj group by name limit 10;
原因在于elasticsearch-sql源码中没有解析聚合后的TopHits结果集:
但是可通过DSL查询获取相关TopHits的结果集:
六、附录:
6.1 Script基本用法:
有时简单的ES Sql语句无法支持某些查询(如【二、快速入门】--【字段之间的运算1/2】),此时需要在sql语句中使用script语句。
前面已经说过,Elasticsearch的查询语言是DSL,由于比较复杂,因此第三方开发了插件Elasticsearch-SQL。因此要介绍script在ES Sql中的用法,必须先了解script在DSL中的用法。语法如下:
"script": {
"lang": "painless",
"source" | "id": "...",
"params": { ... }
}
脚本参数说明:
l lang:指定编写脚本的语言,默认为painless。
l source,id:指定脚本的来源,inline脚本是指定source,如上例所示,存储的脚本是指定的id,并从群集状态中检索(请参阅存储的脚本)。
l params:指定作为变量传递到脚本的任何命名参数。
painless是一种简单,安全的脚本语言,专为与Elasticsearch一起使用而设计,它是Elasticsearch的默认脚本语言,可以安全地用于内联和存储脚本,有关painless语法和语言功能的详细说明,请参阅:https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-scripting-painless.html
以下主要分为Script Fields、Script Query来介绍:
6.1.1 Script Fields(查询字段):
参考:
https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-script-fields.html
GET test_wj/_search
{
"from": 0,
"size": 10,
"_source": {
"includes": [],
"excludes": []
},
"script_fields": {
"aa": {
"script": {
"source": "doc[\"floatValue\"].value * 2",
"lang": "painless"
},
"ignore_failure": false
}
}
- }
以上语句中计算字段floatValue*2的值,返回新字段aa。并使用doc关键字获取字段值。Doc Values介绍如下:
在 Elasticsearch中,Doc Values就是一种列式存储结构,默认情况下每个字段的Doc Values都是激活的,Doc Values是在索引时创建的,当字段索引时,Elasticsearch 为了能够快速检索,会把字段的值加入倒排索引中,同时它也会存储该字段的“Doc Values”。
Elasticsearch 中的Doc Values常被应用到以下场景:
l 对一个字段进行排序;
l 对一个字段进行聚合;
l 某些过滤,比如地理位置过滤;
l 某些与字段相关的脚本计算。
6.1.2 Script Query(过滤条件):
参考:
https://www.elastic.co/guide/en/elasticsearch/reference/6.0/query-dsl-script-query.html
query过滤查询可以使用script,并且用在filter context中:
GET test_wj/_search
{
"from": 0,
"size": 10,
"query": {
"bool": {
"must":{
"script": {
"script": {
"source": "doc[\"floatValue\"].value > 2 && doc[\"doubleValue\"].value > doc[\"floatValue\"].value",
"lang": "painless"
}
}
}
}
}
- }
以上语句查询字段floatValue值大于2且doubleValue值大于floatValue值的数据。
6.1.3 Script 在 ES Sql中的用法:
Script在ES Sql中的用法也分为Script Fields、Script Query来介绍。
1、Script Field(查询字段):
select script('aa','doc["floatValue"].value * 2') as aa1 from test_wj limit 10
可把script看为带2个参数的函数,其中第一个参数'aa'相当于script_fields名称,第二个参数相当于DSL语句中的script的source。以上sql相当于【6.1.1 Script Fields(查询字段)】中的DSL语句。具体如下:
2、Script Query(过滤条件):
select * from test_wj where script('doc["floatValue"].value > 2 && doc["doubleValue"].value > doc["floatValue"].value') limit 10
可把script看为带1个参数的函数,其中参数相当于DSL语句中的script的source。以上sql相当于【6.1.2 Script Query(过滤条件)】中的DSL语句。具体如下:
其他例子:
SELECT PhotoTime, script('ConvertedUptime','painless','def date_format_1606432247 = new SimpleDateFormat('yyyyMMdd').format(new Date(doc['PhotoTime'].value + 8100060*60));return date_format_1606432247;') from vehiclephotopath_201812 limit 10
--注意,"script"的"source",有def定义字段或者函数时,必须有return返回值
SELECT sum(script('aa','return doc["floatValue"].value * 2;')) as aa1 from test_wj limit 10
--script也可用于sum等聚合统计
SELECT IndustryType,City, SumPower
from JZDS_StationRPT
WHERE script('def cc = ["北京市","青岛市"];doc["IndustryType"].value != "公交" && cc.contains(doc["City"].value)') and SumPower > 50
limit 100
select PileCanSN, cast(PileCanSN AS INT) as b
from chargebillwidetable
where PileCanSN <> '' and script('return Integer.parseInt(doc["PileCanSN"].value.toString()) > 180')
limit 10
--cast函数不能用在where条件后面,只能用在select后面
七、待办:
1、聚合查询,group by多字段后,必须用terms,此时无法支持分页以及排序:
SELECT 电站名称, 电站编号,电站ID,
sum(充电量) 充电电量,sum(订单数) 充电次数
FROM etldaystasum
where 1=1 AND 业务日期='20190304+08:00'
group by terms(field='电站名称',size='10000',alias='电站名称'),terms(field='电站编号',size='10000',alias='电站编号'),terms(field='StaID',size='10000',alias='电站ID')
Order by 充电电量 desc
limit 10,20
以上sql中,limit from size方式分页不起作用;order by排序也不起作用。
2、ES max聚合只能针对数值型字段,不能对string类似进行max聚合。
[l1]在Elasticsearch查询结果集中,默认按照相关性进行排序,相关性越高,排名越靠前。相关性分值会用_score字段来给出一个浮点型的数值,所以默认情况下,结果集以_score进行倒序排列。
[l2]IN_TERMS只用于keyword类型字段。
IN_TERMS也有上限,默认65536,可以修改索引级别参数index.max_terms_count设置。此参数设置过大查询会很慢而且会影响集群性能。
https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-terms-query.html
[l3]目前验证只支持*通配符,不支持?、[]、{}等其他通配符
[l4]IN_TERMS只用于keyword类型字段。