我使用语法建立了一个Antlr 4过滤器(在这里的上下文中不重要),过滤器看起来像 "年龄> 30 AND身高< 6.1"。
然而,问题是,我将建立一次这个过滤器,并使用它来评估大概一千个文档。每个文档都会有一个 "年龄 "和 "身高 "属性。
然而我不确定的是,如何重用parser或lexer,以便我可以加快评估速度。每次都建立一个lexer &&解析器似乎真的很浪费时间。
java代码是这样的
public Boolean createFilterVisitor(String input, DocFieldAccessor docFieldAccessor) {
FilterLexer lexer = new FilterLexer(CharStreams.fromString(input));
lexer.removeErrorListener(ConsoleErrorListener.INSTANCE);
CommonTokenStream tokens = new CommonTokenStream(lexer);
FilterParser parser = new FilterParser(tokens);
parser.addErrorListener(new FilterErrorListener());
parser.removeErrorListener(ConsoleErrorListener.INSTANCE);
FilterVisitorImpl filterVisitor = new FilterVisitorImpl(docFieldAccessor);
return filterVisitor.visit(parser.filter());
}
然后
for doc in docs:
createFilterVisitor(doc, someAccessor);
我试着构建一次lexer和parser,然后在循环的开始处做lexer.reset()和parser.reset()。这似乎是可行的(它能过滤合理的文档),但我真的不确定我的做法是否正确。我不知道reset是什么意思,也不知道什么时候应该使用它。
所以我的问题是。
我有这样的代码。这能用吗?
public class KalaFilter {
private final String filterClause;
private FilterLexer lexer;
private FilterParser parser;
@Getter
private final FilterAnalyzer filterAnalyzer;
public KalaFilter(String filterClause) {
this.filterClause = filterClause;
lexer = new FilterLexer(CharStreams.fromString(filterClause));
lexer.removeErrorListener(ConsoleErrorListener.INSTANCE);
CommonTokenStream tokens = new CommonTokenStream(lexer);
parser = new FilterParser(tokens);
parser.addErrorListener(new FilterErrorListener());
parser.removeErrorListener(ConsoleErrorListener.INSTANCE);
ParseTree parseTree = parser.filter();
filterAnalyzer = new FilterAnalyzer();
ParseTreeWalker walker = new ParseTreeWalker(); // create standard walker
walker.walk(filterAnalyzer, parseTree);
}
// return filter result by visit parser
public Boolean visitFitlerResult(DocFieldAccessor docFieldAccessor) {
//lexer.reset();
//FilterLexer lexer = new FilterLexer(CharStreams.fromString(filterClause));
/*
CommonTokenStream tokens = new CommonTokenStream(lexer);
FilterParser parser = new FilterParser(tokens);
parser.addErrorListener(new FilterErrorListener());
parser.removeErrorListener(ConsoleErrorListener.INSTANCE);
*/
parser.reset();
FilterVisitorImpl filterVisitor = new FilterVisitorImpl(docFieldAccessor);
return filterVisitor.visit(parser.filter());
}
}
你的代码的布局方式,你传递了一个字符串到构造函数,在构造函数中解析这个字符串,然后每次都再次解析那个完全相同的字符串。visitFilterResult
的调用。除非你在你的语法操作中做了一些非常不寻常的事情,否则每次解析同一个字符串都应该产生完全相同的结果,所以没有理由重复解析同一个字符串,而不是仅仅重复使用结果。
因此,我们不应该将字符串、词法器和解析器作为实例变量来存储,而应该将调用 parser.filter();
. 然后不调用 visitFilterResult
你可以使用现有的解析树并在其上调用访问者。这样就不需要重置任何东西,因为解析器只被调用一次(在构造函数中)。