编写域特定语言以从表中选择行

时间:2020-03-06 14:47:21  来源:igfitidea点击:

我正在编写一个服务器,我希望该服务器可以由许多不同的人运行,而不是与我所有的人都有直接的联系。服务器将在群集中相互通信。服务器功能的一部分涉及从可能非常大的表中选择行的一小部分。准确选择要选择的行将需要进行一些调整,并且很重要的一点是,运行集群的人员(例如,我自己)可以更新选择标准,而无需让每个服务器管理员都部署服务器的新版本。

仅仅用Python编写函数实际上不是一个选择,因为没有人愿意安装一个服务器,该服务器可以在运行时下载并执行任意Python代码。

我需要的是有关实现领域特定语言以实现此目标的最简单方法的建议。该语言需要能够进行简单的表达式求值,以及查询表索引和遍历返回的行。易于编写和阅读语言是易于实施的第二要因。我也不想不必编写整个查询优化器,因此明确指定要查询的索引的内容将是理想的选择。

该接口必须针对其进行编译,其功能与App Engine数据存储区导出的接口类似:我们可以查询表上任何索引的顺序范围(例如,小于,大于,范围和相等性查询) ,然后使用任何布尔表达式过滤返回的行。我们还可以将多个独立的结果集连接在一起。

我意识到这个问题听起来很像我要的是SQL。但是,我不想要求支持此数据的数据存储区是关系数据库,也不想自己尝试重新实现SQL的开销。我还只处理具有已知模式的单个表。最后,将不需要连接。更简单的方法将是更可取的。

编辑:扩展描述以清除一些误解。

解决方案

为什么不创建一种语言,使其在"编译"时生成SQL或者数据存储所需的任何查询语言?

我们基本上将在持久层上创建一个抽象。

我们提到了Python。为什么不使用Python?如果有人可以在DSL中"输入"表达式,那么他们可以输入Python。

我们需要一些关于表达式结构的规则,但这比实现新的东西容易得多。

我们说过,没有人会想要安装在运行时下载并执行任意代码的服务器。但是,这恰恰是DSL会(最终)执行的操作,因此可能没有太大的区别。除非我们对数据进行非常特定的操作,否则我认为DSL不会给我们那么多的费用,并且不会使已经精通SQL的用户感到沮丧。不要小看将要执行的任务的大小。

但是,要回答问题,我们需要针对语言提出一种语法,一种语法来解析文本并遍历树,发出代码或者调用我们编写的API(这就是为什么我的评论是仍然需要交付一些代码)。

网上有很多关于数学表达式的教育课本,我们可以直接在网上参考。我们可能有一个像ANTLR或者Yacc这样的解析器生成器工具,可以用来生成解析器(或者使用像Lisp / Scheme这样的语言并将两者结合起来)。提出合理的SQL语法并非易事。但是谷歌" BNF SQL",看看你想出了什么。

祝你好运。

我认为我们在这里需要更多信息。让我知道以下情况是否基于错误的假设。

首先,正如我们自己指出的那样,已经存在用于从任意表中选择行的DSL,它被称为" SQL"。由于我们不想重新发明SQL,因此我假设我们只需要从具有固定格式的单个表中查询。

在这种情况下,我们可能不需要实现DSL(尽管这当然是一种方法)。如果我们习惯了对象定向,则创建一个Filter对象可能会更容易。

更具体地说,一个"过滤器"集合将保存一个或者多个SelectionCriterion对象。我们可以实现它们以从表示选择类型(Range,LessThan,ExactMatch,Like等)的一个或者多个基类中继承。一旦这些基类到位,就可以创建适合该列的特定于列的继承版本。 。最后,根据要支持的查询的复杂性,我们将需要实现某种连接胶来处理各种条件之间的AND和OR和NOT链接。

如果我们愿意,可以创建一个简单的GUI来加载集合。如果我们没有其他想法,我将把Excel中的过滤作为模型。

最后,将这个Collection的内容转换为相应的SQL并将其传递给数据库应该是微不足道的。

但是:如果我们追求的是简单性,并且用户了解SQL,则可以简单地要求他们键入WHERE子句的内容,然后以编程方式构建其余的查询。从安全角度来看,如果代码可以控制所选的列和FROM子句,并且数据库权限设置正确,并且我们对来自用户的字符串进行了完整性检查,那么这将是一个相对安全的选择。

听起来确实像SQL,但是如果我们想使其简单,也许值得尝试使用SQLite?

"实现特定领域的语言"

"没有人愿意安装在运行时下载并执行任意Python代码的服务器"

我想要一个DSL,但我不希望Python成为那个DSL。好的。我们将如何执行此DSL?如果不是Python,可以接受什么运行时?

如果我的C程序恰巧嵌入了Python解释器,该怎么办?可以接受吗?

并且-如果Python不是可接受的运行时-为什么它具有Python标记?

听起来我们想创建一个语法而不是DSL。我将研究ANTLR,它将允许我们创建一个特定的解析器,该解析器将解释文本并将其转换为特定的命令。 ANTLR提供适用于Python,SQL,Java,C ++,C,Cetc的库。

另外,这是在C#中创建的ANTLR计算引擎的一个很好的示例

构建由Python解释的DSL。

步骤1.构建运行时类和对象。这些类将所有游标循环和SQL语句以及所有算法处理隐藏在它们的方法中。我们将大量使用"命令和策略"设计模式来构建这些类。大多数事情是命令,选项和选择是插件策略。查看Apache Ant的Task API的设计-这是一个很好的例子。

步骤2.验证该对象系统是否确实有效。确保设计简单完整。我们正在测试将构造Command和Strategy对象,然后执行顶级Command对象。 Command对象将完成工作。

至此,我们已经大功告成。运行时只是从上述域创建的对象的配置。 [这听起来并不容易。需要谨慎定义一组可以实例化的类,然后"彼此交谈"来完成应用程序的工作。]

请注意,我们所拥有的将只需要声明即可。程序有什么问题?我们开始用程序元素编写DSL时,发现我们需要越来越多的功能,直到我们用不同的语法编写了Python。不好。

而且,程序语言解释器很难编写。执行状态和引用范围很难管理。

我们可以使用本机Python-不必担心"脱离沙箱"。确实,这就是使用简短的Python脚本创建对象的方式,将对所有内容进行单元测试。 Python将成为DSL。

["但请稍等,我们会说,"如果我仅使用Python作为DSL,人们就可以执行任意事情。"取决于PYTHONPATH和sys.path。查看站点模块以了解控制可用内容的方法。]

声明式DSL最简单。这完全是一种代表性的练习。仅设置一些变量值的Python块就很好。这就是Django所使用的。

我们可以将ConfigParser用作表示对象的运行时配置的语言。

我们可以将JSON或者YAML用作表示对象的运行时配置的语言。现成的解析器完全可用。

我们也可以使用XML。设计和解析起来比较困难,但是效果很好。人们喜欢它。这就是Ant和Maven(以及许多其他工具)使用声明性语法来描述过程的方式。我不建议这样做,因为这是脖子上的罗pain疼痛。我建议只使用Python。

或者,我们可以深入研究自己的语法并编写自己的解析器。