Drools技术疑问:为何规则LHS中无法使用indexOf()方法?
这个问题我之前也碰到过!Drools的LHS(规则条件部分)对集合方法的调用确实有一些容易踩的坑,咱们一步步来解决它。
问题根源分析
你在doSeq规则的LHS里用list.indexOf($o) > 0没生效,主要有两个核心原因:
- Drools匹配机制限制:LHS的匹配是基于事实的属性状态和依赖追踪的,直接在Seq的约束里调用
indexOf这种动态方法,而且涉及到另一个匹配到的事实$o,Drools无法很好地追踪这种跨事实的方法调用依赖,导致匹配逻辑没有按预期触发。 - 对象相等判断问题:
indexOf完全依赖equals()方法来查找对象,如果你的ObjectWrapper类没有正确重写equals()和hashCode()方法(比如用默认的引用比较而非属性比较),indexOf会直接返回-1,约束自然不生效。
解决方案
下面给你几个实用的解决思路,按推荐程度排序:
方案一:提前维护索引映射(最推荐)
在初始化Seq的时候,把列表里每个ObjectWrapper对应的索引存入一个Map,这样在LHS里直接用Map的属性匹配,既高效又符合Drools的匹配逻辑:
首先修改initSeq规则:
rule "initSeq" when $p: ObjectWrapper ( ... ) $list: List () from collect (ObjectWrapper (...)) not initSeq (....) then Seq w = new Seq(); w.setList($list); // 新增索引映射,绑定每个元素与它的索引 Map<ObjectWrapper, Integer> indexMap = new HashMap<>(); for (int i = 0; i < $list.size(); i++) { indexMap.put((ObjectWrapper) $list.get(i), i); } w.setIndexMap(indexMap); // 记得给Seq类添加indexMap属性和对应的get/set方法 insert(w); end
然后修改doSeq规则的LHS:
rule "doSeq" when $o: ObjectWrapper ( ... ) $rr: Seq ( indexMap[$o] > 0 ) // 直接通过Map键值对判断索引 then DroolsLogger.debug ("index: " + $rr.getIndexMap().get($o)); end
方案二:通过匹配逻辑判断(无需额外属性)
如果不想给Seq加新属性,可以通过两次匹配来判断$o不是列表的第一个元素(即索引>0):
rule "doSeq" when $o: ObjectWrapper ( ... ) $rr: Seq ( $list: list ) // 先确认$o确实存在于列表中 exists(ObjectWrapper(this == $o) from $list) // 再确认列表的第一个元素不是$o not ObjectWrapper(this == $o) from $list.get(0) then DroolsLogger.debug ("index: " + $rr.getList().indexOf($o)); end
方案三:用Accumulate计算索引(适合复杂场景)
如果需要在LHS中直接计算索引,可以用Drools的accumulate函数实现:
rule "doSeq" when $o: ObjectWrapper ( ... ) $rr: Seq ( $list: list ) // 遍历列表,定位$o对应的索引 accumulate( $item: ObjectWrapper() from $list, $currentIndex: count(), $targetIndex: collectList(if $item.equals($o) then $currentIndex - 1 else null) ) // 确保索引有效且大于0 $targetIndex != null && $targetIndex.size() > 0 && $targetIndex.get(0) > 0 then DroolsLogger.debug ("index: " + $targetIndex.get(0)); end
关键提醒
不管用哪种方案,一定要先检查ObjectWrapper的equals()和hashCode()方法是否正确实现——比如是否比较了对象的核心业务属性,而不是默认的引用比较。如果这两个方法有问题,所有依赖对象相等判断的逻辑都会失效。
内容的提问来源于stack exchange,提问作者Alyaksandr Stzhalkouski
相关产品推荐
相关产品推荐

