#drools
#пускает слюни
Вопрос:
Я новичок в Drools и использую Drools 7.12.0, чтобы попытаться проверить набор показаний счетчика, которые выглядят как
public class MeterReading() {
private long id;
private LocalDate readDate;
private int value;
private String meterId
private boolean valid;
/* Getters amp; Setters omitted */
}
В рамках проверки мне нужно сравнить значения каждого параметра чтения с его непосредственным предшественником по дате чтения.
Сначала я попробовал использовать ‘accumulate’
when $mr: MeterReading()
$previousDate: LocalDate() from accumulate(MeterReading($pdate: readDate < $mr.readDate ), max($pdate))
then
System.out.println($mr.getId() ":" $previousDate);
end
но затем обнаружил, что это возвращает только дату предыдущего считывания счетчика, а не объект, который ее содержит. Затем я попробовал пользовательский накопитель с
when
$mr: MeterReading()
$previous: MeterReading() from accumulate(
$p: MeterReading(id != $mr.id),
init( MeterReading prev = null; ),
action( if( prev == null || $p.readDate < prev.readDate) {
prev = $p;
}),
result(prev))
then
System.out.println($mr.getId() ":" $previous.getId() ":" $previous.getReadDate());
end
но при этом выбирается самое раннее показание в наборе показаний счетчика, а не непосредственный предшественник. Может кто-нибудь указать мне правильное направление относительно того, что я должен делать или читать, чтобы иметь возможность выбирать непосредственного предшественника для каждого отдельного показания счетчика.
С уважением
Ответ №1:
После дальнейших исследований я нашел эту статью http://planet.jboss.org/post/how_to_implement_accumulate_functions который я использовал для написания своей собственной функции накопления;
public class PreviousReadFinder implements AccumulateFunction {
@Override
public Serializable createContext() {
return new PreviousReadFinderContext();
}
@Override
public void init(Serializable context) throws Exception {
PreviousReadFinderContext prfc = (PreviousReadFinderContext) context;
prfc.list.clear();
}
@Override
public void accumulate(Serializable context, Object value) {
PreviousReadFinderContext prfc = (PreviousReadFinderContext) context;
prfc.list.add((MeterReading) value);
}
@Override
public void reverse(Serializable context, Object value) throws Exception {
PreviousReadFinderContext prfc = (PreviousReadFinderContext) context;
prfc.list.remove((MeterReading) value);
}
@Override
public Object getResult(Serializable context) throws Exception {
PreviousReadFinderContext prfc = (PreviousReadFinderContext) context;
return prfc.findLatestReadDate();
}
@Override
public boolean supportsReverse() {
return true;
}
@Override
public Class<?> getResultType() {
return MeterReading.class;
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
}
private static class PreviousReadFinderContext implements Serializable {
List<MeterReading> list = new ArrayList<>();
public Object findLatestReadDate() {
Optional<MeterReading> optional = list.stream().max(Comparator.comparing(MeterReading::getReadDate));
if (optional.isPresent()) {
MeterReading to = optional.get();
return to;
}
return null;
}
}
}
и мое правило теперь
rule "Opening Read With Previous"
dialect "mvel"
when $mr: MeterReading()
$pmr: MeterReading() from accumulate($p: MeterReading(readDate < $mr.readDate ), previousReading($p))
then
System.out.println($mr.getId() ":" $pmr.getMeterReadDate());
end
Как мне написать правило для выбора самого быстрого показания счетчика в наборе, у которого нет предыдущего значения?