1. 序言
-
作为Presto的客户端之一,Presto CLI是一个基于终端的交互式shell,对应presto源码中的presto-cli模块
-
Presto CLI的本质是一个self-executing jar ——
presto-cli-version-executable.jar
,就像一个普通的UNIX可执行文件 -
因此,可以像下面这样使用presto cli
./presto --server localhost:8080 --user adhoc_user --catalog hive
-
Presto CLI依赖Presto client向Presto server提交查询,获取查询执行进度、执行结果等。
-
Presto使用Master-Slave架构,对外提供服务的接口都在coordinator中,上面的描述可以改写为:Pressto client向coordinator提交查询
-
笔者认为,在学习Presto CLI前,了解Presto client与coordinator之间如何进行HTTP通信是极有必要的
-
官网有Presto Client的相关文档:Presto Client REST API,本文对Presto client的介绍也会参考该文档,并辅以Presto 0.279的源码
1.1 StatementClientV1.advance()
方法,获取下一批查询结果(简称response)
- 成功创建StatementClientV1后,上层调用者将根据StatementClientV1的状态,决定是否发起更多的请求以获取查询结果
- 注意: 查询结果是广义的,它包括查询执行进度和执行结果。
response为查询执行进度
- response中的QueryResults.data为
null
,只有查询的状态信息(QueryResults.stats)client.currentData().getData() != null
- 此时,上层调用会打印执行进度,并继续调用
StatementClientV1.advance()
方法获取下一批查询结果 - 例如,非交互式查询下的
presto.cli.Query.processInitialStatusUpdates()
方法,则负责获取并打印执行进度private void processInitialStatusUpdates(WarningsPrinter warningsPrinter) { while (client.isRunning() && (client.currentData().getData() == null)) { warningsPrinter.print(client.currentStatusInfo().getWarnings(), true, false); client.advance(); } ... // 其他代码省略 }
response为查询执行结果
-
response中的QueryResults.data不为
null
,这时可以进入执行结果打印阶段 -
presto.cli.Query.renderResults()
方法负责查询结果的打印,该方法最终将调用OutputHandler.processRows()
方法构建并打印行数据 -
由于QueryResults.data中可能只是部分执行结果,可能还需要多次调用advance()方法获取剩余的执行结果
public void processRows(StatementClient client) throws IOException { while (client.isRunning()) { Iterable<List<Object>> data = client.currentData().getData(); if (data != null) { for (List<Object> row : data) { processRow(unmodifiableList(row)); // 超过MAX_BUFFERED_ROWS(10_000)则刷新输出 } } // 超过MAX_BUFFER_TIME,也会刷新输出 if (nanosSince(bufferStart).compareTo(MAX_BUFFER_TIME) >= 0) { flush(false); } // 访问nextUri,获取新的执行结果 client.advance(); } }
1.2 关于nextUri
- new StatementClientV1()时,以POST方式向
/v1/statement
接口发送查询请求,这时只是提交一个查询 - 因为查询具有lazy execution特征,需要以GET方式、多次访问response中的nextUri,才能触发查询的执行、获取查询执行进度以及查询结果
- advance()方法就是访问nextUri的关键方法,每次访问nexrUri都将返回一个response;若response中的nexrUri为
null
,说明查询结束 - nextUri不停变化,意味着查询处于不同的阶段,如
/v1/statement/queued/
、/v1/statement/executing/
等 - 具体的nextUri的变化,可以参考之前的博客《结合Presto CLI,Presto Client学习》的4.3小节