Search code examples
droolsoptaplanner

Is there a way to improve rule performance?


I'm attempting to pair tasks (runs) and leverage a limited set of facts without instantiating all the possible combinations. While the following rule is not complete yet, performance is very slow. I'm looking for suggestions.

when
$rp : RoutePair()

accumulate( RouteRun( routePair == $rp,  $runId : runId);
            $routeRunListAm : collectList($runId),
            $count : count();
            $count == 4)
accumulate( $pr : PairableRuns( (runId1 == $routeRunListAm.toArray()[0] && runId2 == $routeRunListAm.toArray()[1])
                             || (runId1 == $routeRunListAm.toArray()[0] && runId2 == $routeRunListAm.toArray()[2])
                             || (runId1 == $routeRunListAm.toArray()[0] && runId2 == $routeRunListAm.toArray()[3])
                             || (runId1 == $routeRunListAm.toArray()[1] && runId2 == $routeRunListAm.toArray()[2])
                             || (runId1 == $routeRunListAm.toArray()[1] && runId2 == $routeRunListAm.toArray()[3])
                             || (runId1 == $routeRunListAm.toArray()[2] && runId2 == $routeRunListAm.toArray()[3]));
            $pairableRunsListPm : collectList($pr),
            $count : count();
            $count >= 2)
accumulate( RouteRun( routePair == $rp,  $returnRunId : returnRunId);
            $routeRunListPm : collectList($returnRunId))
accumulate( $pr : PairableRuns( (runId1 == $routeRunListPm.toArray()[0] && runId2 == $routeRunListPm.toArray()[1])
                             || (runId1 == $routeRunListPm.toArray()[0] && runId2 == $routeRunListPm.toArray()[2])
                             || (runId1 == $routeRunListPm.toArray()[0] && runId2 == $routeRunListPm.toArray()[3])
                             || (runId1 == $routeRunListPm.toArray()[1] && runId2 == $routeRunListPm.toArray()[2])
                             || (runId1 == $routeRunListPm.toArray()[1] && runId2 == $routeRunListPm.toArray()[3])
                             || (runId1 == $routeRunListPm.toArray()[2] && runId2 == $routeRunListPm.toArray()[3]));
            $pairableRunsListPm : collectList($pr),
            $count : count();
            $count >= 2)

then


Solution

  • I have to (ab)use an answer so that I can ask my questions to understand the problem.

    class RoutePair{...}
    class RouteRun( 
        RoutePair routePair;
        RunId runId
    }
    class PairableRuns(
        RunId runId1; // maybe String or int - doesn't matter
        RunId runId2;
    }
    

    After the first collect, $routeRunListAm is a List of 4 RouteRun objects, in any order. But the complex boolean expression will only return true if the order of runId1 and runId2 in some PairableRuns is reflected by the order in that list which has been accumulated in some indeterministic order.

    I find it also somethat irritating that this List must have exactly 4 RouteRun objects - why not >= 4? The second part of the condition contains an almost identical combinations of CEs and constraints, except that here the condition $count == 4 is missing from the third accumulate CE.

    I'm not sure what the complex boolean expression should ascertain, but I think that the much simpler

    $pr: PairableRuns( runId1 memberOf $routeRunListAm,
                       runId2 memberOf $routeRunListAm )
    

    should achieve the same thing.

    However, I'm not sure whether that is really sufficient. Consider that $routeRunListAm contains 7, 12, 14, 22 and the PairableRuns {7,12}, {7,14}, {7,22}. This would match the original constraint as well as my proposed form three times - is this what is desired?

    It's impossible to advise without a concise specification (which the rule as shown is definitely not).