[jboss-jira] [JBoss JIRA] (DROOLS-1422) Make AccumulateFunction interface simpler and more powerful

Geoffrey De Smet (JIRA) issues at jboss.org
Tue Jan 31 09:09:00 EST 2017


     [ https://issues.jboss.org/browse/DROOLS-1422?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Geoffrey De Smet updated DROOLS-1422:
-------------------------------------
    Description: 
* Replace the AccumulateFunction interface with the AccumulateFunction2 interface:
** All core runtime code uses the AccumulateFunction2 interface.
**  Deprecate AccumulateFunction and use a bridge class at DRL compilation time so old implementations still work because they are bridged into the new interface
* Changes of the AccumulateFunction2:
** Methods no longer throw checked exceptions (no "throws Exception"), so drools doesn't have to catch them. This might improve performance.
** Remove "Serializable context". The class itself contains the state.
*** Remove method createContext()
*** Replace method init(Serializeble) with constructor call (no-args normally)
*** Remove parameter Serializable from accumulate(value), reserve(value) and getResult() methods
*** This might improve performance.
** It should Serializable, but doesn't have to Externalizable. Removes methods writeExternal() and readExternal() in the user implementation.
* Interface ReversableAccumulateFunction2 extends AccumulateFunction2
** Only ReversableAccumulateFunction2 has method reverse(value)
** Remove method supportsReverse(): the custom accumulate is reverseable if it also implements this interface
* Opportunities
** construction parameters. For example: fixed average for standard deviation (very useful for OptaPlanner)
** Multi-argument accumulates, for example in DRL: `$total : standardDeviation($groupBy, $weight)`

Notice how clean the user implementation would become.
{code}
// NEW
public class SumAccumulateFunction
        implements ReversableAccumulateFunction2<Integer, Integer> {

    public int total;

    public SumAccumulateFunction() {
        total = 0;
    }

    public void accumulate(Integer value) {
        total += value;
    }

    public void reverse(Integer value) {
        total -= value;
    }

    public Integer getResult() {
        return total;
    }

}
{code}

*Compare that with the old way:*

{code}
// OLD
public class SumAccumulateFunction implements AccumulateFunction {

    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { }

    public void writeExternal(ObjectOutput out) throws IOException { }

    protected static class SumData implements Externalizable {
        public double total = 0;

        public SumData() {}

        public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
            total   = in.readDouble();
        }

        public void writeExternal(ObjectOutput out) throws IOException {
            out.writeDouble(total);
        }

    }

    public Serializable createContext() {
        return new SumData();
    }

    public void init(Serializable context) {
        SumData data = (SumData) context;
        data.total = 0;
    }

    public void accumulate(Serializable context,
                           Object value) {
        SumData data = (SumData) context;
        data.total += ((Number) value).doubleValue();
    }

    public void reverse(Serializable context,
                        Object value) {
        SumData data = (SumData) context;
        data.total -= ((Number) value).doubleValue();
    }

    public Object getResult(Serializable context) {
        return ((SumData) context).total;
    }

    public boolean supportsReverse() {
        return true;
    }

    public Class<?> getResultType() {
        return Double.class;
    }
}
{code}

Some other cases:

Different result type than value type:

{code}
public class AverageAccumulateFunction
        implements ReversableAccumulateFunction2<Integer, Double> {

    public int total;
    public int count;

    public AverageAccumulateFunction() {
        total = 0;
        count = 0;
    }

    public void accumulate(Integer value) {
        total += value;
        count++;
    }

    public void reverse(Integer value) {
        total -= value;
        count--;
    }

    public Double getResult() {
        return (double) total / count;
    }

}
{code}

Construction parameter:

{code}
public class StdDeviationAccumulateFunction
        implements ReversableAccumulateFunction2<Integer, Double> {

    public final double average;
    public double variance;

    public StdDeviationAccumulateFunction(double average) {
        this.average = average;
        variance = 0;
    }

    public void accumulate(double value) {
        variance += (value - average)²; // TODO
    }

    public void reverse(double value) {
        variance -= (value - average)²; // TODO
    }

    public Double getResult() {
        return Math.sqrt(variance);
    }

}
{code}

TODO multi-argument accumulate:

...

  was:
* Replace the AccumulateFunction interface with the AccumulateFunction2 interface:
** All core runtime code uses the AccumulateFunction2 interface.
**  Deprecate AccumulateFunction and use a bridge class at DRL compilation time so old implementations still work because they are bridged into the new interface
* Changes of the AccumulateFunction2:
** Methods no longer throw checked exceptions (no "throws Exception"), so drools doesn't have to catch them. This might improve performance.
** Remove "Serializable context". The class itself contains the state.
*** Remove method createContext()
*** Replace method init(Serializeble) with constructor call (no-args normally)
*** Remove parameter Serializable from accumulate(value), reserve(value) and getResult() methods
*** This might improve performance.
** It should Serializable, but doesn't have to Externalizable. Removes methods writeExternal() and readExternal() in the user implementation.
* Interface ReversableAccumulateFunction2 extends AccumulateFunction2
** Only ReversableAccumulateFunction2 has method reverse(value)
** Remove method supportsReverse(): the custom accumulate is reverseable if it also implements this interface
* Opportunities
** construction parameters. For example: fixed average for standard deviation (very useful for OptaPlanner)
** Multi-argument accumulates, for example in DRL: `$total : standardDeviation($groupBy, $weight)`


{code}
public class SumAccumulateFunction
        implements ReversableAccumulateFunction2<Integer, Integer> {

    public int total;

    public SumAccumulateFunction() {
        total = 0;
    }

    public void accumulate(Integer value) {
        total += value;
    }

    public void reverse(Integer value) {
        total -= value;
    }

    public Integer getResult() {
        return total;
    }

}
{code}


{code}
public class AverageAccumulateFunction
        implements ReversableAccumulateFunction2<Integer, Double> {

    public int total;
    public int count;

    public AverageAccumulateFunction() {
        total = 0;
        count = 0;
    }

    public void accumulate(Integer value) {
        total += value;
        count++;
    }

    public void reverse(Integer value) {
        total -= value;
        count--;
    }

    public Double getResult() {
        return (double) total / count;
    }

}
{code}



{code}
public class StdDeviationAccumulateFunction
        implements ReversableAccumulateFunction2<Integer, Double> {

    public final double average;
    public double variance;

    public StdDeviationAccumulateFunction(double average) {
        this.average = average;
        variance = 0;
    }

    public void accumulate(double value) {
        variance += (value - average)²; // TODO
    }

    public void reverse(double value) {
        variance -= (value - average)²; // TODO
    }

    public Double getResult() {
        return Math.sqrt(variance);
    }

}
{code}



> Make AccumulateFunction interface simpler and more powerful
> -----------------------------------------------------------
>
>                 Key: DROOLS-1422
>                 URL: https://issues.jboss.org/browse/DROOLS-1422
>             Project: Drools
>          Issue Type: Feature Request
>          Components: core engine
>            Reporter: Geoffrey De Smet
>            Assignee: Mario Fusco
>
> * Replace the AccumulateFunction interface with the AccumulateFunction2 interface:
> ** All core runtime code uses the AccumulateFunction2 interface.
> **  Deprecate AccumulateFunction and use a bridge class at DRL compilation time so old implementations still work because they are bridged into the new interface
> * Changes of the AccumulateFunction2:
> ** Methods no longer throw checked exceptions (no "throws Exception"), so drools doesn't have to catch them. This might improve performance.
> ** Remove "Serializable context". The class itself contains the state.
> *** Remove method createContext()
> *** Replace method init(Serializeble) with constructor call (no-args normally)
> *** Remove parameter Serializable from accumulate(value), reserve(value) and getResult() methods
> *** This might improve performance.
> ** It should Serializable, but doesn't have to Externalizable. Removes methods writeExternal() and readExternal() in the user implementation.
> * Interface ReversableAccumulateFunction2 extends AccumulateFunction2
> ** Only ReversableAccumulateFunction2 has method reverse(value)
> ** Remove method supportsReverse(): the custom accumulate is reverseable if it also implements this interface
> * Opportunities
> ** construction parameters. For example: fixed average for standard deviation (very useful for OptaPlanner)
> ** Multi-argument accumulates, for example in DRL: `$total : standardDeviation($groupBy, $weight)`
> Notice how clean the user implementation would become.
> {code}
> // NEW
> public class SumAccumulateFunction
>         implements ReversableAccumulateFunction2<Integer, Integer> {
>     public int total;
>     public SumAccumulateFunction() {
>         total = 0;
>     }
>     public void accumulate(Integer value) {
>         total += value;
>     }
>     public void reverse(Integer value) {
>         total -= value;
>     }
>     public Integer getResult() {
>         return total;
>     }
> }
> {code}
> *Compare that with the old way:*
> {code}
> // OLD
> public class SumAccumulateFunction implements AccumulateFunction {
>     public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { }
>     public void writeExternal(ObjectOutput out) throws IOException { }
>     protected static class SumData implements Externalizable {
>         public double total = 0;
>         public SumData() {}
>         public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
>             total   = in.readDouble();
>         }
>         public void writeExternal(ObjectOutput out) throws IOException {
>             out.writeDouble(total);
>         }
>     }
>     public Serializable createContext() {
>         return new SumData();
>     }
>     public void init(Serializable context) {
>         SumData data = (SumData) context;
>         data.total = 0;
>     }
>     public void accumulate(Serializable context,
>                            Object value) {
>         SumData data = (SumData) context;
>         data.total += ((Number) value).doubleValue();
>     }
>     public void reverse(Serializable context,
>                         Object value) {
>         SumData data = (SumData) context;
>         data.total -= ((Number) value).doubleValue();
>     }
>     public Object getResult(Serializable context) {
>         return ((SumData) context).total;
>     }
>     public boolean supportsReverse() {
>         return true;
>     }
>     public Class<?> getResultType() {
>         return Double.class;
>     }
> }
> {code}
> Some other cases:
> Different result type than value type:
> {code}
> public class AverageAccumulateFunction
>         implements ReversableAccumulateFunction2<Integer, Double> {
>     public int total;
>     public int count;
>     public AverageAccumulateFunction() {
>         total = 0;
>         count = 0;
>     }
>     public void accumulate(Integer value) {
>         total += value;
>         count++;
>     }
>     public void reverse(Integer value) {
>         total -= value;
>         count--;
>     }
>     public Double getResult() {
>         return (double) total / count;
>     }
> }
> {code}
> Construction parameter:
> {code}
> public class StdDeviationAccumulateFunction
>         implements ReversableAccumulateFunction2<Integer, Double> {
>     public final double average;
>     public double variance;
>     public StdDeviationAccumulateFunction(double average) {
>         this.average = average;
>         variance = 0;
>     }
>     public void accumulate(double value) {
>         variance += (value - average)²; // TODO
>     }
>     public void reverse(double value) {
>         variance -= (value - average)²; // TODO
>     }
>     public Double getResult() {
>         return Math.sqrt(variance);
>     }
> }
> {code}
> TODO multi-argument accumulate:
> ...



--
This message was sent by Atlassian JIRA
(v7.2.3#72005)



More information about the jboss-jira mailing list