我正在研究POC,看看我们是否可以从ODM迁移到Drools,但我无法确定Drools中我们在ODM应用程序中使用的某些功能。
示例:
- 在ODM中,我们使用一个具有输入和输出的决策操作,该操作是从Spring应用程序调用的。这个ODM操作调用一个复杂的规则流(父流/子流),它根据不同级别的元数据组织规则执行。如果满足条件,这些规则将构建一组输出数据,Spring应用程序将使用这些数据根据结果进行不同的行为。请记住,决策操作等待规则流完成,然后用该输出返回spring应用程序
在Drools中,我知道我可以构建一个spring-boot应用程序并调用规则流,但规则流是异步的。Drools的行为与ODM不同,所以看起来不一样。我可以使用规则流。可以选择等待并获取规则流的状态,但我们每天都会收到数百万个请求,无法证明等待是合理的。我曾想过利用议程组/激活组来执行规则,以控制我们的执行,但我们正在评估的数据很复杂,需要大量的交叉数据验证,我们正在验证的数据(POJO)可能有10个级别。是的,我们的结构非常庞大,最多可以有500多条规则。由于我们的复杂性,我看不出利用议程组/激活组来实现我们所需要的。
有人会对实现这种行为有任何想法吗?欢迎任何输入:)
我对ODM一无所知,所以我不能评论它们的异同。但从用例问题中描述的内容来看,我认为问题在于您使用Drools错误。:)
一般来说,我们会调用这样的规则:
KieContainer kieContainer = ...
KieBase rules = this.kieContainer.getKieBase("validation"); // call the validation rules
KieSession session = rules.newKieSession();
try {
session.insert( ... ); // add facts into working memory
session.fireAllRules();
} finally {
session.dispose();
}
fireAllRules
是一种同步的阻塞方法。
或者,如果你想进行批量处理,你可以这样做(示例取自文档):
StatelessKieSession ksession = kbase.newStatelessKieSession();
List cmds = new ArrayList();
cmds.add( CommandFactory.newInsertObject( new Cheese( "stilton", 1), "stilton") );
cmds.add( CommandFactory.newStartProcess( "process cheeses" ) );
cmds.add( CommandFactory.newQuery( "cheeses" ) );
ExecutionResults bresults = ksession.execute( CommandFactory.newBatchExecution( cmds ) );
Cheese stilton = ( Cheese ) bresults.getValue( "stilton" );
QueryResults qresults = ( QueryResults ) bresults.getValue( "cheeses" );
请注意,我们在命令列表中调用startProcess
,但不是直接调用。此外,我们仍在等待execute
调用的结果,因此,尽管startProcess
确实异步进行,但在继续execute
之前,我们仍会阻止所有执行完成。
您声明的用例是:
如果满足条件,规则将构建一组输出数据,Spring应用程序将使用这些数据根据结果进行不同的行为。
这里没有任何东西可以阻止您使用Drools。在我以前的公司,我们有一套规则,可以根据请求中的数据状态在服务之间路由请求,包括在飞行中修改请求。我们也有可以进行正常处理的规则,比如验证、计算等等
您的模型深度也不是真正的障碍——无论模型的结构如何,您都可以针对模型编写规则。有一些类型天生就较差(请不要将Map
s传递到规则中),但通常情况下,如果它在工作内存中,你可以使用它。
最后,处理时间主要是决定规则编写得有多好的一个因素。Drools中有一些结构允许您修改工作内存并重新运行规则——这将导致它们固有地花费更多的时间,因为(duh)您正在第二次运行规则!但一个简单的突破规则——触发任何人触发并继续移动的规则——这些可能非常快。在我的上一份工作中,我有一项服务,有140万条规则,SLA低于秒;它之所以如此之快,是因为没有"更新"调用,而且没有一个规则关心其他规则中的哪一个也被触发。这些规则实际上是无状态的,最坏的性能是300毫秒(平均为30毫秒;这是整个春季启动应用程序的往返,而不仅仅是实际的规则评估。)
对于依赖于POJO中许多级别的复杂数据对象的规则,您将如何派生该数据而不让规则关心其他规则?假设我的对象结构类似于Person->车辆->制作->型号->选项。如果我正在运行专门针对";"选项";,如何到达";型号";选项规则中的数据?如果model或make为空/null以阻止Options运行,该怎么办?
分析这个例子,我们有以下模型(假设所有字段上都有getter和setter):
class Options {}
class Model {
private Options options;
}
class Make {
private Model model;
}
class Vehicle {
private Make make;
}
class Person {
private Vehicle vehicle;
}
为了获得"选项",我们只需将它们从中间模型中提取出来。假设您将Person
实例放入工作内存:
rule "Options"
when
// this is the Person in working memory; get the vehicle out.
Person( $v: vehicle )
// then drill down to Options by repeating the process
Vehicle( $make: make ) from $v
Make( $model: model ) from $make
Model( $opts: options ) from $model
// now we can do stuff with $opts
then
// $opts is available for use here too
end
Drools通常非常擅长防守"获得",但你可以通过添加空复选框来进行防守。例如:
rule "Options with explicit null checks"
when
Person( $v: vehicle != null )
Vehicle( $make: make != null ) from $v
Make( $model: model != null ) from $make
Model( $opts: options != null ) from $model
then
// ...
end
或者,如果你想快速失败并丢弃任何有坏数据的输入,你可以从工作内存中retract
它们。这是潜在的危险,因为这是过早退出工作流,如果你没有意识到它的存在,可能会在下游引发潜在的错误。(这在某种程度上类似于在Java代码中有多个"return"语句;如果你在接近方法底部的地方进行调试,却没有意识到在更远的地方有早期返回,这可能会导致你浪费时间或引入意外行为。)
rule "Retract incomplete date"
salience 100
when
$person: Person ($v: vehicle != null)
// as an example, this rule is going to trap for missing Make
Vehicle( make == null ) from $v
then
retract($person);
end
注意:一旦调用retract
,该项将从工作内存中消失,因此如果任何后续规则依赖于它,它们将不再激发。
这种显著性是没有必要的,但从历史上看,我发现当像这样的早期撤回被明确称为比常规规则更早发生时,更容易在心理上跟踪它们。一般来说,简单地编写互斥规则是更好的做法,但使用早期收回可能会发现性能稍好。
在Drools中,我知道我可以构建一个spring-boot应用程序并调用规则流,但规则流是异步的。Drools的行为与ODM不同,所以看起来不一样。我可以使用规则流。
Drools中有相同类型的ODM规则流功能。它不那么复杂,但你可以获得相同的结果,那就是:
- 将您的决策组织成更小的规则集
- 按流程排列这些不同的任务/集合,以执行决策编排
请参阅Drools doc 7.67 中的规则流示例
就像在ODM中一样,您可以称之为规则流:
- 在JSON/XML中直接作为Kieserver中的web服务(规则执行服务器/HTDS的drools概念)(您需要首先安装Kieserver)
- 从调用kieserver的Java客户端
关于规则中的对象导航,规则编写是相同的,主要区别是DRL语言。
最佳Emmanuel