处理与流口水的转发 1:n 关系

Handling forward 1:n relationships with drools

我正在尝试编写一个适用于基于另一个事实内容的一组事实的规则。我已将问题简化为带房间的房子。假设我们有类似的东西:

House(id);
Room(id, houseId, floor, side, paint);

现在,如果我想在左侧所有房间都涂成绿色的所有房屋上触发规则,我会这样写:

rule "Left side 1st floor green"
when
   $h: House()
   forall($r: Room(houseId=$h.id, floor==1, side=="left")
       Room(id == $r.id, paint == "green"))
then
   //Do whatever on rule triggering
end

但是如果工作记忆中的对象是这样组织的呢:

House(id, List<> roomIds);
Room(id, floor, side, paint);

如何编写 foreach 条件(或任何其他方法)以对给定房屋的房间进行相同的考虑?这是否有意义,或者我是否应该更好地尝试提前重组我的对象以使关系以相反的方式表达?

谢谢

按照你的规定,你没有带房间的房子。根据你的定义,你的工作记忆中有房子,你的工作记忆中有房间,你尝试匹配这些。

你为什么没有房子的房间列表?那会更有意义:

House(houseId, List<Room> rooms)
Room(roomId, floor, side, paint)

那么你的规则是:

rule "Left side 1st floor green"
  when
   $houses : House ($rooms : rooms, $houseId : houseId)
   $room : Room ($roomId : roomId, floor==1 && side=="left" && paint == "green") from $rooms
  then
   //Rule would trigger for each room left side 1st floor green rooms
   System.out.println("House "+$houseId+" has following left side 1st floor green room: "+$roomId);
end

假设 House 中的 List<> roomIdsRoom.id(s) 的列表,那么您可以执行以下操作:

rule "Left side 1st floor green"
when
   $h: House(/* .. conditions for specific house? .. */)
   $r : Room($h.roomIds contains id, floor==1, side=="left", paint == "green")
then
   //Do whatever on rule triggering
end

然而,这有点低效,我同意其他人的回答,稍微改变 business/data 模型将使编写这种规则更加地道和高效。例如,如果房子确实有房间列表,您还可以使用 OOPath 来根据需要导航结构。