2021SC@SDUSC
总览
本篇为对QueryParserDriver类进行分析的第一篇,主要是对PigServer的parseQuery方法会进入QueryParserDriver的parse(query)方法,本次主要针对生成逻辑数据模型的过程进行分析。
代码分析
初始化
初始化读取pigserver所处环境,范围,将接口fileNameMap的key-value值设为importseen和macroseen,初始化pigserver为空,延迟寄存器语句实例化。
public QueryParserDriver(PigContext pigContext, String scope, Map<String, String> fileNameMap) {
this.pigContext = pigContext;
this.pigServer = null; // lazily instantiated for register statements
this.scope = scope;
this.fileNameMap = fileNameMap;
importSeen = new HashSet<String>();
macroSeen = new HashSet<String>();
}
parseSchema()
根据返回值的类型不同,共有两种parseSchema()方法,一种返回抽象逻辑树,一种返回逻辑数据模型。
- 本方法生成的是抽象语法树,抽象语法树(abstract syntax code,AST)是源代码的抽象语法结构的树状表示,树上的每个节点都表示源代码中的一种结构,这所以说是抽象的,是因为抽象语法树并不会表示出真实语法出现的每一个细节,比如说,嵌套括号被隐含在树的结构中,并没有以节点的形式呈现。抽象语法树并不依赖于源语言的语法。
private static Tree parseSchema(CommonTokenStream tokens) throws ParserException {
QueryParser parser = QueryParserUtils.createParser(tokens);
schema_return result = null;
try {
result = parser.schema();
} catch (RecognitionException e) {
String msg = parser.getErrorHeader(e) + " "
+ parser.getErrorMessage(e, parser.getTokenNames());
throw new ParserException(msg);
} catch(RuntimeException ex) {
throw new ParserException( ex.getMessage() );
}
Tree ast = (Tree)result.getTree();
checkError( parser );
return ast;
}
- 本逻辑数据模型应该基于前面概念数据模型中标识的结构,因为这描述了信息上下文的语义,逻辑模型也应该反映信息上下文的语义。尽管如此,由于逻辑数据模型预期在特定的计算系统上实现,因此对逻辑数据模型的内容进行调整以达到一定的效率。术语“逻辑数据模型”有时用作“域模型”的同义词或域模型的替代词。虽然这两个概念密切相关,并且有重叠的目标,但域模型更侧重于捕获问题域中的概念,而不是与该域相关联的数据的结构。
public LogicalSchema parseSchema(String input) throws ParserException {
CommonTokenStream tokenStream = tokenize( input, null );
LogicalSchema schema = null;
Tree ast = parseSchema( tokenStream );
try{
CommonTreeNodeStream nodes = new CommonTreeNodeStream( ast );
AstValidator walker = new AstValidator( nodes );
ast = (Tree)walker.field_def_list().getTree();
checkError( walker );
LogicalPlanGenerator planGenerator =
new LogicalPlanGenerator( new CommonTreeNodeStream( ast ), pigContext, scope, fileNameMap );
schema = planGenerator.field_def_list().schema;
checkError( planGenerator );
} catch(RecognitionException ex) {
throw new ParserException( ex );
} catch(Exception ex) {
throw new ParserException( ex.getMessage(), ex );
}
return schema;
}
parseConstant()
Parser根据lexer生成的tokens尝试解析。tokens每一个成员都会生成一个函数,其先后执行逻辑按照用户输入的1+1+2的顺序执行。注意像1和2这类constants为true的token,parser会通过constant生成需要的函数parseConstant,也就是说1+1+2中的两个1和一个2都是返回parseConstant函数.
private static Tree parseConstant(CommonTokenStream tokens) throws ParserException {
QueryParser parser = QueryParserUtils.createParser(tokens);
literal_return result = null;
try {
result = parser.literal();
} catch (RecognitionException e) {
String msg = parser.getErrorHeader(e) + " "
+ parser.getErrorMessage(e, parser.getTokenNames());
throw new ParserException(msg);
} catch(RuntimeException ex) {
throw new ParserException( ex.getMessage() );
}
Tree ast = (Tree)result.getTree();
checkError( parser );
return ast;
}
public Object parseConstant(String input) throws ParserException {
CommonTokenStream tokenStream = tokenize( input, null );
Object value = null;
Tree ast = parseConstant( tokenStream );
try{
CommonTreeNodeStream nodes = new CommonTreeNodeStream( ast );
AstValidator walker = new AstValidator( nodes );
ast = (Tree)walker.literal().getTree();
checkError( walker );
LogicalPlanGenerator planGenerator =
new LogicalPlanGenerator( new CommonTreeNodeStream( ast ), pigContext, scope, fileNameMap );
value = planGenerator.literal().value;
checkError( planGenerator );
} catch(RecognitionException ex) {
throw new ParserException( ex );
} catch(Exception ex) {
throw new ParserException( ex.getMessage(), ex );
}
return value;
}
总结
本次分析主要针对的是QueryParserDriver类的一些方法进行分析,对其中一些模型进行理解。