传统上,要使用OptaPlanner进行扩展,您必须学习DRL。 不再。 借助受Java 8 Streams和SQL启发的新Constraints Streams API,您现在可以用Java (或Kotlin或Scala) 编写约束,并且仍然可以从增量计算中受益。
在下面,约束流(CS)仍使用强大的Drools引擎。 我们也仍然完全支持得分DRL。 它们不被弃用。
 让我们从一个例子开始。 在护士排班中,为了避免将班次分配给员工Ann ,您可以在DRL中编写以下约束: 
 rule "Don't assign Ann" when Shift(getEmployee().getName() == "Ann" ) then scoreHolder.addSoftConstraintMatch(kcontext, - 1 );  end 这在使用约束流的Java中是相同的约束:
 Constraint constraint = constraintFactory .from(Shift. class ) .filter(shift -> shift.getEmployee().getName().equals( "Ann" )) .penalize( "Don't assign Ann" , HardSoftScore.ONE_SOFT);  如果您熟悉SQL或Java 8流,则应该看起来很熟悉。 给定一个有四个班次的潜在解决方案(其中两个分配给Ann ),这些班次将通过约束流流动,如下所示: 
这种写约束的新方法有几个好处:
增量计算
 首先,与EasyScoreCalculator不同,约束流仍然像DRL一样应用增量分数计算来进行横向扩展。 例如,当一个移动将雇员换两班时,仅计算增量。 这是巨大的可扩展性收益: 
索引编制
 当JOIN多个类型时,就像SQL JOIN运算符一样,约束流在索引上应用哈希查找以更好地扩展: 
IDE支持
因为ConstraintsStreams是用Java语言编写的,所以它们背负了非常强大的工具支持。
代码突出显示,代码完成和调试工作正常:
代码突出显示
IntelliJ IDEA Ultimate中的DRL代码:
对于相同的约束,在IntelliJ IDEA Ultimate中使用约束流的Java代码:
代码完成
约束流的代码完成:
当然,所有API方法都具有Javadocs。
调试
 在ConstraintStream的filter()添加一个断点: 
在调试时诊断问题:
Java语法
用约束流用Java编写的约束,无论好坏,都遵循Java语言规范(JLS)。 当使用来自Kotlin或Scala的约束流时,适用类似的逻辑。
在DRL和约束流之间迁移时,请注意DRL和Java之间的一些区别:
-  DRL的==运算符在Java中转换为equals()。
- 除了getter,DRL还允许MVEL表达式转换为Java中的getter。
 例如,此DRL具有name和== : 
 rule "Don't assign Ann" when Employee(name == "Ann" ) then ...  end  但是,对于完全相同的约束,Java变量具有getName()和equals() : 
 constraintFactory.from(Employee. class ) .filter(employee -> employee.getName().equals( "Ann" )) .penalize( "Don't assign Ann" , ...); 进阶功能
Constraint Streams API使我们可以添加语法糖和强大的新概念,这些概念专门为帮助您构建复杂的约束而量身定制。
 为了突出其中之一,让我们看一下功能强大的groupBy方法: 
 与SQL GROUP BY运算符或Java 8 Stream Collector相似,它支持sum() , count() , countDistinct() , min() , max() , toList()甚至自定义函数,同样也不会损失增量分数计算。 
约束流的未来工作
首先,非常感谢LukášPetrovický在Constraints Streams上所做的所有工作!
但这仅仅是开始。 我们设想了更高级的功能,例如负载平衡/公平方法,以使此类约束更易于实现。
目前,我们的首要任务是简化对隔离的单元测试的单元。 考虑测试驱动设计。 敬请关注!
翻译自: https://www.javacodegeeks.com/2020/04/constraint-streams-modern-java-constraints-without-the-drools-rule-language.html