在Neo4j中建模关于数学计算的元数据

7
我是论坛的新手,刚开始接触Neo4J。抱歉我的问题有些冗长,但我认为背景信息可以帮助解释我想要理解的内容。
我经常为公司开展业务智能和数据仓库项目工作。当我们创建业务智能需求时,通常需要创建我们感兴趣的业务指标列表(例如销售收入、利润率、总支出等),并记录如何使用底层系统的数据属性计算这些业务指标。通常我们会在 Excel 中以数据需求电子表格的形式记录大部分工作。我们会创建一个业务指标列表,然后是一堆列,包括描述、源数据属性、计算等。作为个人的副业项目,我正在尝试开发一个应用程序来代替记录此类元数据信息。我已经阅读了一些 Neo4j 书籍和在线文章,我认为 Neo4j 很适合这种用例,现在我正在尝试记录一个基本的数据模型,以帮助我入门。
起初,我想到了一个相当简单的东西,如下图所示,从以下点开始:
销售收入 = 单价 * 销售数量

First Attempt at Modelling Metrics & Attributes

然而我很快意识到计算本身对我非常重要,日后我可能想获取更多关于它的信息,例如添加不同版本的计算或添加注释以进一步描述它。如上图左侧所示,我修改了模型,使“计算本身”成为单独的节点。
但是,当我开始查看更复杂的指标时,我仍然不确定如何最好地表示计算的细节。如果我以以下示例为例,则应将其建模如下:Salary = Salary_Amount + Overtime_Amount - Tax Amount。

More Complex Example

现在,这明确表示了用于计算的数据属性(其中有3个),但我不知道如何表示计算本身。例如,定义计算是通过首先将Salary_Amount加上Overtime_Amount,然后减去Tax_Amount来完成的。当我有更复杂的计算,涉及除法和乘法需要按特定顺序执行时,这将变得更加复杂。 基本上,我希望能够从模型中推断出计算如下所示: 薪水=工资金额+加班费用-税金 而不是: 薪水=工资金额*税金/加班费用 或者: 薪水=税金*加班费用-工资金额 我正在寻找一种定义计算节点的方法,可以对使用数据属性的方式进行排序。也许我应该将计算作为文本字符串存储在计算的属性中,但我不能帮助自己认为,这可能会给我带来痛苦,并限制我从图形中获取有用信息的能力,当多个数据属性用于不同的计算时。
注意:我看到论坛上有一个与该主题相似的 this question,但没有得到很多回复,因此即使我的问题类似,我认为提供更多背景信息可能会带来一些进一步的见解。
非常感谢, 迈克尔
我在查看@ChristopheWillemsen和@stdob--的答案后编辑了这个问题。首先非常感谢两位贡献者。答案和参考资料真的很有帮助,都涵盖了我的需求。最初,我倾向于使用逆波兰表示法,因为@stdob的答案提供了一种处理分组操作(例如我的数学公式中的括号)的简洁方法。但是,在尝试用两种方式建模我的数据之后,我发现我有额外的要求,这些要求在我的第一篇文章中没有涵盖,即捕获诸如“If、Where、Having”之类的逻辑表达式。基本上,我想能够捕获超出纯数学表达式范围的ETL类型转换规则,我认为@ChristopheWillemsen的解决方案将支持此功能。以下是我使用此方法建模基本公式的方式:

Basic Calc following Method 1

然而,我还有更复杂的逻辑需要建模。这些是 ETL 类型的规则,通常会以伪代码或 SQL 的形式捕获,用于定义数据仓库或 BI 项目的业务需求。以下是一个示例,其中我正在定义如何计算保险公司新索赔计数指标的 ETL 逻辑。

New Claims Count Calculation

这是我基于@ChristopheWillemsen在下面第一个答案中提供的解决方案进行扩展建模的方式。

New Claims Count Modelled

您能看一下这个,看看这是否是建模的适当方式。从需求角度来看,我希望能够:

  • 重新构建逻辑,以便将其呈现给最终用户
  • 回答诸如需要此属性用于哪些指标之类的问题。
  • 进行假设分析(例如,如果属性值更改,对使用该属性的指标有何影响)。

这是否看起来像是建模此类信息的适当方法?欢迎任何建议或改进?


我刚刚也发现了这篇有趣的文章:https://blog.socratic.org/stepping-into-math-open-sourcing-our-step-by-step-solver-9b5da066ae36#.sn0owu2yb - Christophe Willemsen
2个回答

6

这是一个非常有趣的用例,与我们所谓的规则引擎非常接近。

我在neo4j博客上发布了一个有关此的用例:https://neo4j.com/blog/uncommon-use-cases-graph-databases/

当然,实现您想要的有多种方法,我将分享一种我考虑过的方法。

我会将计算处理为有序列表Operations,它们的不同性质由它们的标签定义。例如,你可以有一个具有附加标签AdditionOperation节点,它的下一个操作可以是具有标签SubstractionOperation节点。

一个简单的模型可以表示为:

enter image description here

然后,您的Operation节点将引用它们正在使用的输入值。

在更复杂的情况下,您希望表示操作组,其可以在括号之间定义数学分组,同样可以像这样完成模型:

enter image description here

可能性几乎无限。

请注意,在计算机科学中,这种技术也被称为规范模式:https://www.martinfowler.com/apsupp/spec.pdf


非常感谢您的解决方案@ChristopheWillemsen。我已经按照这种方式对我的数据进行了建模,但后来发现我有额外的要求需要捕获更多关于计算的逻辑。我已经编辑了我的问题,展示了如何扩展您的解决方案以涵盖这一点。您能否看一下并告诉我您是否认为这是一个合适的方法?谢谢。 - n4nite
@n4nite 听起来不错。现在我为一个客户在neo4j之上构建了这样的规则引擎,采用完整的cypher解决方案绝对不是正确的方法,因此我们构建了一个应用程序层规则引擎来处理“评估”类型,这非常强大。此外,我选择了简单的答案,但缺点是规则与数据紧密相连,因此您可以在节点内添加解析器属性。您可以发送电子邮件至christophe@graphaware.com,我可以分享有关此实现的迷你说明。 - Christophe Willemsen

4
第一种选择是将表达式写成逆波兰表示法,并将其存储在一个有序树中:
Salary_Amount * Tax_Amount / Overtime_Amount
=>
Salary_Amount Tax_Amount * Overtime_Amount /

enter image description here


我想到的第二个选项是:将公式保留为文本形式,并将公式和参数值发送到任何脚本语言中运行。例如 - 在javascript中使用eval

我建议您也阅读这篇文章:电子表格也是图表


< p >< em >更新:如何使用密码和apoc-library计算公式的想法:
WITH "{Salary_Amount} * {Tax_Amount} / {Overtime_Amount}" as Formula
CALL apoc.cypher.run("return " + Formula + " as value", {
  Salary_Amount: 1000,
  Tax_Amount: 0.49,
  Overtime_Amount: 100
}) yield value as result
RETURN result.value

逆波兰表达式看起来很有趣,可以玩一下。@stob--,谢谢分享。 - Christophe Willemsen
非常感谢您抽出时间来回答。使用逆波兰表示法是一种独特的处理分组操作的方式,我从未想过。我已经编辑了上面的问题,包括一些额外的要求。我认为这些额外的要求意味着上面的第一个提议可能更合适。如果您有时间阅读我更新的问题,我很想知道您的想法? - n4nite

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接