Java 使用Facebook presto解析器
我正在尝试使用。我需要知道的是如何分析和提取我们创建的Java 使用Facebook presto解析器,java,facebook,parsing,Java,Facebook,Parsing,我正在尝试使用。我需要知道的是如何分析和提取我们创建的语句的查询体: SqlParser SQL_PARSER = new SqlParser(); Statement statement = SQL_PARSER.createStatement(query); 从语句getter/setters中似乎没有任何方法可以得到这一点。我调试了Statement对象,从debug视图中可以看到需要获取的值 见: 我需要获取由SqlParser提取的select、from、where、groupBy
语句的查询体
:
SqlParser SQL_PARSER = new SqlParser();
Statement statement = SQL_PARSER.createStatement(query);
从语句
getter/setters中似乎没有任何方法可以得到这一点。我调试了Statement对象,从debug视图中可以看到需要获取的值
见:
我需要获取由SqlParser提取的select、from、where、groupBy、orderBy和limit值 从sql字符串中,您可以通过向下转换
语句
来获得查询
(它扩展了语句)Query.getQueryBody
返回一个QueryBody
,您可以将其转换为QuerySpecification
(扩展了QueryBody
)。从QuerySpecification
,您现在可以获得所需的内容。下面是一个简单的例子:
public class PrestoParserTest {
public static void main(String[] args) {
SqlParser parser = new SqlParser();
String sql = "select * from xyz where x=y group by x order by y limit 10";
Query query = (Query)parser.createStatement(sql);
QuerySpecification body = (QuerySpecification)query.getQueryBody();
Select select = body.getSelect();
System.out.println("Columns = " + select.getSelectItems());
System.out.println("From = " + body.getFrom().get());
Optional<Expression> where = body.getWhere();
System.out.println("Where = " + where.get());
System.out.println("Group by = " + body.getGroupBy());
System.out.println("Order by = " + body.getOrderBy());
System.out.println("Limit = " + body.getLimit().get());
}
}
虽然给出的答案有效,但它需要在运行时进行大量类型检查和强制转换,这非常容易出错。(特别是当您有一个包含许多联接和子表达式的高度嵌套查询时) 相反,Presto的查询解析器提供了一个基本的
AstVisitor
抽象类,您可以对其进行子类化,它将为您处理所有的强制转换和分派
例如,要获取查询中使用的所有表的列表(在scala中,但同样适用于java):
下面是一个示例访问者,它不做任何有用的事情,但正确地遍历查询树。我发现弄清楚如何编写自己的:
问题有两部分
class DepthFirstVisitor<R, C> extends AstVisitor<Stream<R>, C> {
private final AstVisitor<R, C> visitor;
public DepthFirstVisitor(AstVisitor<R, C> visitor) {
this.visitor = visitor;
}
public static <R, C> DepthFirstVisitor<R, C> by(AstVisitor<R, C> visitor) {
return new DepthFirstVisitor<>(visitor);
}
@Override
public final Stream<R> visitNode(Node node, C context) {
Stream<R> nodeResult = Stream.of(visitor.process(node, context));
Stream<R> childrenResult = node.getChildren().stream()
.flatMap(child -> process(child, context));
return Stream.concat(nodeResult, childrenResult)
.filter(Objects::nonNull);
}
}
class Extractors {
public static AstVisitor<Table, Object> extractTables() {
return new AstVisitor<Table, Object>() {
@Override
protected Table visitTable(Table node, Object context) {
return node;
}
};
}
}
// Thats it folks
DepthFirstVisitor<Table, ?> depthFirstVisitor = DepthFirstVisitor.by(Extractors.extractTables());
String sql = "select * from foo tablesample system (10) join bar tablesample bernoulli (30) on not(a.id > b.id)";
Statement statement = new SqlParser().createStatement(sql, new ParsingOptions());
List<Table> tables = statement.accept(depthFirstVisitor, null)
.collect(Collectors.toList());
System.out.println(tables);
class DepthFirstVisitor扩展了AstVisitor{
私人最终访客;
公共部门第一访客(AST访客){
this.visitor=访客;
}
公共静态深度第一访问者(AstVisitor){
返回新的DepthFirstVisitor(访客);
}
@凌驾
公共最终流visitNode(节点,C上下文){
Stream nodeResult=Stream.of(visitor.process(节点,上下文));
Stream childrenResult=node.getChildren().Stream()
.flatMap(子->进程(子,上下文));
返回Stream.concat(nodeResult、childrenResult)
.filter(对象::非空);
}
}
类提取器{
公共静态表{
返回新的AstVisitor(){
@凌驾
受保护的表可访问(表节点、对象上下文){
返回节点;
}
};
}
}
//就是这样,伙计们
DepthFirstVisitor DepthFirstVisitor=DepthFirstVisitor.by(提取器.extractTables());
String sql=“select*from foo tablesample system(10)join bar tablesample bernoulli(30)on not(a.id>b.id)”;
语句Statement=newsqlparser().createStatement(sql,newparsingoptions());
List tables=statement.accept(depthFirstVisitor,null)
.collect(Collectors.toList());
系统输出打印LN(表格);
这可以在不进行难看的类型检查的情况下完成
打印
[Table{foo},Table{bar}]
关于“UPDATE”语句如何,presto解析器似乎不支持这一点?粗略地看一下代码库,它似乎不受支持。这是可能的,因为引擎并不是真正用于此目的的,但如果是这样的话,仅仅从完整性的角度来看,我仍然会感到惊讶。UPDATE
是不受支持的。
class VisitSourceTables extends AstVisitor[List[String], List[String]]{
override def visitTable(node: Table, context: List[String]): List[String] = {
List[String](
node.getName.toString
)
}
override def visitJoin(node: Join, context: List[String]): List[String] = {
process(node.getLeft, context) ++ process(node.getRight, context)
}
(one method per type of thing to visit)
...
}
class DepthFirstVisitor<R, C> extends AstVisitor<Stream<R>, C> {
private final AstVisitor<R, C> visitor;
public DepthFirstVisitor(AstVisitor<R, C> visitor) {
this.visitor = visitor;
}
public static <R, C> DepthFirstVisitor<R, C> by(AstVisitor<R, C> visitor) {
return new DepthFirstVisitor<>(visitor);
}
@Override
public final Stream<R> visitNode(Node node, C context) {
Stream<R> nodeResult = Stream.of(visitor.process(node, context));
Stream<R> childrenResult = node.getChildren().stream()
.flatMap(child -> process(child, context));
return Stream.concat(nodeResult, childrenResult)
.filter(Objects::nonNull);
}
}
class Extractors {
public static AstVisitor<Table, Object> extractTables() {
return new AstVisitor<Table, Object>() {
@Override
protected Table visitTable(Table node, Object context) {
return node;
}
};
}
}
// Thats it folks
DepthFirstVisitor<Table, ?> depthFirstVisitor = DepthFirstVisitor.by(Extractors.extractTables());
String sql = "select * from foo tablesample system (10) join bar tablesample bernoulli (30) on not(a.id > b.id)";
Statement statement = new SqlParser().createStatement(sql, new ParsingOptions());
List<Table> tables = statement.accept(depthFirstVisitor, null)
.collect(Collectors.toList());
System.out.println(tables);