Выберите непосредственного предшественника по дате

#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
  

Как мне написать правило для выбора самого быстрого показания счетчика в наборе, у которого нет предыдущего значения?