druid.io实践3---sql形式查询接口plyql


druid提供http rest形式的查询接口,但是默认是json形式的,给没使用过druid的人用还是不太友好。这里介绍几种工具:

  • plyql(推荐):imply.io自家产品,持续更新中。
  • Sql4D:java客户端,yahoo的,很久都没跟新了,不支持druid新增功能,例如lookup等。
  • pydruid: python客户端,airbnb/superset使用pydruid。

http rest接口

使用方式:

1
curl -X POST '<queryable_host>:<port>/druid/v2/?pretty' -H 'Content-Type:application/json' -d @<query_json_file>

json内容,例如:

1
2
3
4
5
6
7
8
9
10
11
12
{
"queryType": "timeseries",
"dataSource": "sample_datasource",
"granularity": "day",
"aggregations": [
{ "type": "longSum", "name": "sample_name1", "fieldName": "sample_fieldName1" }
],
"intervals": [ "2012-01-01T00:00:00.000/2012-01-04T00:00:00.000" ],
"context" : {
"skipEmptyBuckets": "true"
}
}

plyql

部署

需要先行安装安装node+npm环境,node版本>= 4.x.x。这里plyql用的当时最新的0.8.13版本。

1
2
3
npm install -g plyql@0.8.13
//添加环境变量
export PATH=/disk2/node-v4.2.2-linux-x64/bin:$PATH

执行以下操作之后,在本地相当于开起了一个druid-mysql形式的接口,端口为3307。后续操作就跟操作mysql几乎一样了。

1
plyql -h druid-broker:port -c 8 --experimental-mysql-gateway 3307

一些可供配置的参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
--help print this help message
--version display the version number
-v, --verbose display the queries that are being made
展示查询和转换之后的json
-h, --host the host to connect to
-s, --source use this source for the query (supersedes FROM clause)
-i, --interval add (AND) a __time filter between NOW-INTERVAL and NOW
-i P2Y 会不查询近6个小时的数据。
-tz, --timezone the default timezone
-tz Asia/Shanghai 为东八区,加不加一样,应该是默认时区
-q, --query the query to run
-o, --output specify the output format. Possible values: json (default), csv, tsv, flat
-a, --allow enable a behaviour that is turned off by default eternity allow queries not filtered on time select allow select queries
-t, --timeout the time before a query is timed out in ms (default: 60000)
超时时间,默认60s
-r, --retry the number of tries a query should be attempted on error, 0 = unlimited, (default: 2)
-c, --concurrent the limit of concurrent queries that could be made simultaneously, 0 = unlimited, (default: 2)
并发查询数,默认2
--rollup use rollup mode [COUNT() -> SUM(count)]

监控

这里进行简单的启动、监控。使用linux-crontab执行定时任务,启动并且监听plyql服务。后续可以接入graphite或者其他监控报警系统中。

1
* * * * * /disk1/fangyq/start-plyql-cron.sh online >> /disk1/fangyq/log/cron.log

监听3307端口,当没有监听时,启动plyql服务。

1
2
3
4
5
6
7
8
9
10
11
#!/bin/sh
logPath=$(cd `dirname $0`; cd ../log ; pwd)
listen=$(netstat -nlp|grep 3307)
#start plyql
if [ "$listen" == "" ]
then
echo 'INFO: start plyql service'
nohup plyql -h druid-broker:port -c 8 -v --experimental-mysql-gateway 3307 >>${logPath}/plyql.log &
fi

使用

客户端

与普通的mysql客户端一样,druid的一个datasource相当于一个table

1
2
mysql -h 127.0.0.1 -P 3307 --default-character-set=utf8
show tables;

举例:datasource_a如下

  • 维度为:id
  • 度量为:impr(展示),click(点击)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    desc datasource_a;
    +----------------------------------+--------------+------+------+---------+-------+
    | Field | Type | Null | Key | Default | Extra |
    +----------------------------------+--------------+------+------+---------+-------+
    | __time | timestamp | YES | | NULL | |
    | id | varchar(255) | YES | | NULL | |
    | impr | double | YES | | NULL | |
    | click | double | YES | | NULL | |
    +----------------------------------+--------------+------+------+---------+-------+

查询一天内所有的展示和点击。

1
SELECT SUM(impr) AS impr,SUM(click) AS click FROM datasource_a WHERE __time BETWEEN '2016-05-19 00:00:00' AND '2016-05-20 00:00:00';

查询10天内,id为1的展示和点击,按天聚合。

1
SELECT id,SUM(impr) AS impr,SUM(click) AS click FROM datasource_a WHERE __time BETWEEN '2016-05-10 00:00:00' AND '2016-05-20 00:00:00' AND id='1' GROUP BY id,TIME_BUCKET(__time,P1D,'Asia/Shanghai') HAVING impr>0 OR click>0;

程序

跟普通的访问mysql一样。

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
import lombok.Cleanup;
import org.junit.Test;
import java.sql.*;
public class PlyqlTest {
@Test
public void plyql(){
String plyql_url="jdbc:mysql://plyql-host:3307/plyql1?useUnicode=true&amp;characterEncoding=utf8";
try {
Class.forName("com.mysql.jdbc.Driver");
@Cleanup Connection con = DriverManager.getConnection(plyql_url);
@Cleanup Statement stmt = con.createStatement();
@Cleanup ResultSet rs = stmt.executeQuery(
"SELECT id,SUM(impr) AS impr,SUM(click) AS click FROM datasource_a WHERE __time BETWEEN '2016-05-10 00:00:00' AND '2016-05-20 00:00:00' GROUP BY id"
);
while (rs.next()) {
String id = rs.getString("id");
double impr = rs.getDouble("impr");
System.out.println(id+" "+impr);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

语法说明

1)聚合字段

1
2
LONG_SUM ==> SUM
cardinality(hyperLogLog uniques) ==> COUNT_DISTINCT

例如,uv字段,COUNT_DISTINCT(uv)算出来为double类型,结果需要取整
2)where必须先写__time,再AND其他的。

1
2
WHERE __time >='2016-05-19T00:00:00.000+08:00' AND __time<='2016-05-19T23:59:59.999+08:00'
WHERE __time >='2016-05-19 00:00:00' AND __time<='2016-05-19 23:59:59'

3)时间颗粒度:
按天和按小时:

1
2
group by day ==> GROUP BY TIME_BUCKET(__time,P1D,'Asia/Shanghai')
group by hour ==> GROUP BY TIME_BUCKET(__time,PT1H,'Asia/Shanghai')

4)limit只有一个参数,因为在druid中只有topN查询。分页查询只能在程序中先查出总数,再取子集。

1
2
limit offset,max ==> limit offset+max
lrs.subList(offset,max);

Sql4D

客户端

安装

1
2
3
4
5
6
git clone https://github.com/fangyeqing/Sql4D.git
cd Sql4D/Sql4DClient
mvn clean install
vi dsql #修改如下:
java -jar target/Sql4DClient-4.1.0.jar -bh broker-host -bp broker-port -ch coordinator-host -cp 8050 -oh broker-host -op broker-port -i 100
./dsql #启动client

连接上druid之后,操作如下:

1
2
3
4
5
6
7
show tables (显示datasources)
describe TableName (显示数据源的schema)
trace=[true|false] (打印转换后的json,默认false)
querymode=[sql|json] (查询模式,默认sql)
quit (退出)
select queries (GroupBy, TimeSeries, TopN, Select, Search). See wiki for examples: https://github.com/srikalyc/Sql4D/wiki/Sql4DCompiler
generatebean=BeanName (This command must be preceding a SQL, it generates a java source file BeanName.java which extends DruidBaseBean.

程序

maven依赖,可以直接用如下的,不过有一些bug。最好是用修改后的版本重新打包或者发布再添加依赖。https://github.com/fangyeqing/Sql4D

1
2
3
4
5
<dependency>
<groupId>com.yahoo.sql4d</groupId>
<artifactId>Sql4Ddriver</artifactId>
<version>4.1.0</version>
</dependency>

使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@CommonsLog
@Data
public class DruidDataSource {
private String bHost;
private int bPort;
private String cHost;
private int cPort;
private int maxConnsInPool;
private int maxBrokerConns;
private int maxCoordConns;
private int maxOverLordConns;
public static DDataSource driver;
@PostConstruct
public void init(){
DDataSource.adjustPoolSettings(maxConnsInPool,maxBrokerConns,maxCoordConns,maxOverLordConns);
driver = new DDataSource(bHost, bPort, cHost, cPort);
}
public List<DruidBaseBean> query(String sql, Class type) {
Either<String, Either<List<DruidBaseBean>, Map<Object, DruidBaseBean>>> response = driver.query(sql, null, type, null, false);
return response.right().get().left().get();
}
}

pydruid

null

参考

http://plywood.imply.io/plyql#examples
http://imply.io/post/2016/05/04/programmatic-plyql.html
https://github.com/implydata/plyql
https://github.com/srikalyc/Sql4D

文章目录
  1. 1. http rest接口
  2. 2. plyql
    1. 2.1. 部署
    2. 2.2. 监控
    3. 2.3. 使用
      1. 2.3.1. 客户端
      2. 2.3.2. 程序
    4. 2.4. 语法说明
  3. 3. Sql4D
    1. 3.1. 客户端
    2. 3.2. 程序
  4. 4. pydruid
  5. 5. 参考
|