使用 antlr 解析树将 sql 查询解析为 mongo bson 文档 Java
Parse sql query using antlr parsetree to mongo bson document in Java
我有一个 SQL 类似的查询示例:
Select id,name from employee where age > 30 and department = 'IT' limit 200
SQL 查询语法在 ANTLR4 语法文件中定义。是否有任何实现可以将此查询的解析树转换为 bson 文档?
然后将使用 bson 文档查询 mongo 数据库。
在我之前的一份工作中,我做了类似的事情:得到一个查询(不是 sql,但非常相似)并用 antlr 将其翻译成 mongo 查询。
我没有代码可以分享,但是我可以分享我的想法:
Mongo 不符合 SQL,因此您不能只采用 sql 语法。 JOIN 和所有关系代数呢?在 mongo 中使用它们的聚合框架非常棘手的聚合呢?在相反的方向,你如何生成 SQL 并被翻译成 mongo 中的 "exists" 子句。有很多这样的东西,有些很小,有些很大,但最重要的是你必须谈论 sql 的某种子集,一些允许用作查询语言并且看起来 "like" 和 sql 因为人们习惯于 SQL.
考虑到这一点,您应该创建自己的语法,Antlr 会为您生成一个 lexer/parser。您还将理所当然地在运行时对查询进行语法检查。如果格式不正确,Antlr 将无法解析查询,某些语法规则将失败。这是不使用 SQL "as is" 的另一个原因。
到目前为止一切顺利,您已经创建了自己的侦听器/访问者。在我的例子中,我选择创建一个包含内部状态和所有内容的查询对象表示。
所以查询
Select id,name
from employee
where age > 30
and department = 'IT'
limit 200
被翻译成以下类型的对象:
class Query {
private SelectClause select;
private FromClause from;
private WhereClause where;
private Limit limit;
}
class SelectClause {
private List<String> fields;
}
...
class WhereClause {
Condition root;
}
interface Condition {
...
}
class AndCondition implements Condition { // the same for Not, Or
}
对于这个特定的查询,它类似于:
Query q = new Query(new SelectClause(["id", "name"]), new FromClause("employee"), new WhereClause(new AndCondition(new SimpleLeafCondition("age", Operators.GT, 30), new SimpleLeafCondition("department", Operators.EQ, "IT" )), new Limit(30));
然后可以在查询中进行一些优化(例如,如果需要,可以嵌入 where 子句,或者,例如,如果您在多租户环境中工作并且有不同的集合,则可以操作 "For" 部分针对不同的租户)。
毕竟,您可以使用设计模式 "interpreter" 并递归解析查询对象,并 "translate" 将它们解析为有效的 mongo 查询。
我记得这一步花了我大约 1 天的时间来完成(我猜是 7 年前 mongo 2,但仍然如此),考虑到表示查询的对象的正确结构,所以这不应该那么复杂.我提出这个问题,因为它看起来像是您在问题中最关心的问题。
我有一个 SQL 类似的查询示例:
Select id,name from employee where age > 30 and department = 'IT' limit 200
SQL 查询语法在 ANTLR4 语法文件中定义。是否有任何实现可以将此查询的解析树转换为 bson 文档?
然后将使用 bson 文档查询 mongo 数据库。
在我之前的一份工作中,我做了类似的事情:得到一个查询(不是 sql,但非常相似)并用 antlr 将其翻译成 mongo 查询。
我没有代码可以分享,但是我可以分享我的想法:
Mongo 不符合 SQL,因此您不能只采用 sql 语法。 JOIN 和所有关系代数呢?在 mongo 中使用它们的聚合框架非常棘手的聚合呢?在相反的方向,你如何生成 SQL 并被翻译成 mongo 中的 "exists" 子句。有很多这样的东西,有些很小,有些很大,但最重要的是你必须谈论 sql 的某种子集,一些允许用作查询语言并且看起来 "like" 和 sql 因为人们习惯于 SQL.
考虑到这一点,您应该创建自己的语法,Antlr 会为您生成一个 lexer/parser。您还将理所当然地在运行时对查询进行语法检查。如果格式不正确,Antlr 将无法解析查询,某些语法规则将失败。这是不使用 SQL "as is" 的另一个原因。
到目前为止一切顺利,您已经创建了自己的侦听器/访问者。在我的例子中,我选择创建一个包含内部状态和所有内容的查询对象表示。 所以查询
Select id,name
from employee
where age > 30
and department = 'IT'
limit 200
被翻译成以下类型的对象:
class Query {
private SelectClause select;
private FromClause from;
private WhereClause where;
private Limit limit;
}
class SelectClause {
private List<String> fields;
}
...
class WhereClause {
Condition root;
}
interface Condition {
...
}
class AndCondition implements Condition { // the same for Not, Or
}
对于这个特定的查询,它类似于:
Query q = new Query(new SelectClause(["id", "name"]), new FromClause("employee"), new WhereClause(new AndCondition(new SimpleLeafCondition("age", Operators.GT, 30), new SimpleLeafCondition("department", Operators.EQ, "IT" )), new Limit(30));
然后可以在查询中进行一些优化(例如,如果需要,可以嵌入 where 子句,或者,例如,如果您在多租户环境中工作并且有不同的集合,则可以操作 "For" 部分针对不同的租户)。
毕竟,您可以使用设计模式 "interpreter" 并递归解析查询对象,并 "translate" 将它们解析为有效的 mongo 查询。 我记得这一步花了我大约 1 天的时间来完成(我猜是 7 年前 mongo 2,但仍然如此),考虑到表示查询的对象的正确结构,所以这不应该那么复杂.我提出这个问题,因为它看起来像是您在问题中最关心的问题。