@@ -50,37 +50,32 @@ public Object evaluate(List arguments, Object data) throws JsonLogicEvaluationEx
5050 }
5151
5252 final List <FractionProperty > propertyList = new ArrayList <>();
53+ int totalWeight = 0 ;
5354
54- double distribution = 0 ;
5555 try {
5656 for (Object dist : distibutions ) {
5757 FractionProperty fractionProperty = new FractionProperty (dist );
5858 propertyList .add (fractionProperty );
59- distribution += fractionProperty .getPercentage ();
59+ totalWeight += fractionProperty .getWeight ();
6060 }
6161 } catch (JsonLogicException e ) {
6262 log .debug ("Error parsing fractional targeting rule" , e );
6363 return null ;
6464 }
6565
66- if (distribution != 100 ) {
67- log .debug ("Fractional properties do not sum to 100" );
68- return null ;
69- }
70-
7166 // find distribution
72- return distributeValue (bucketBy , propertyList );
67+ return distributeValue (bucketBy , propertyList , totalWeight );
7368 }
7469
75- private static String distributeValue (final String hashKey , final List <FractionProperty > propertyList )
70+ private static String distributeValue (final String hashKey , final List <FractionProperty > propertyList , int totalWeight )
7671 throws JsonLogicEvaluationException {
7772 byte [] bytes = hashKey .getBytes (StandardCharsets .UTF_8 );
7873 int mmrHash = MurmurHash3 .hash32x86 (bytes , 0 , bytes .length , 0 );
79- int bucket = (int ) (( Math .abs (mmrHash ) * 1.0f / Integer .MAX_VALUE ) * 100 ) ;
74+ float bucket = (Math .abs (mmrHash ) * 1.0f / Integer .MAX_VALUE ) * 100 ;
8075
81- int bucketSum = 0 ;
76+ float bucketSum = 0 ;
8277 for (FractionProperty p : propertyList ) {
83- bucketSum += p .getPercentage ();
78+ bucketSum += p .getPercentage (totalWeight );
8479
8580 if (bucket < bucketSum ) {
8681 return p .getVariant ();
@@ -95,7 +90,7 @@ private static String distributeValue(final String hashKey, final List<FractionP
9590 @ SuppressWarnings ({"checkstyle:NoFinalizer" })
9691 private static class FractionProperty {
9792 private final String variant ;
98- private final int percentage ;
93+ private final int weight ;
9994
10095 protected final void finalize () {
10196 // DO NOT REMOVE, spotbugs: CT_CONSTRUCTOR_THROW
@@ -108,23 +103,32 @@ protected final void finalize() {
108103
109104 final List <?> array = (List ) from ;
110105
111- if (array .size () != 2 ) {
112- throw new JsonLogicException ("Fraction property does not have two elements " );
106+ if (array .isEmpty () ) {
107+ throw new JsonLogicException ("Fraction property needs at least one element " );
113108 }
114109
115110 // first must be a string
116111 if (!(array .get (0 ) instanceof String )) {
117112 throw new JsonLogicException ("First element of the fraction property is not a string variant" );
118113 }
119114
120- // second element must be a number
121- if (!(array .get (1 ) instanceof Number )) {
122- throw new JsonLogicException ("Second element of the fraction property is not a number" );
123- }
124-
125115 variant = (String ) array .get (0 );
126- percentage = ((Number ) array .get (1 )).intValue ();
116+ if (array .size () >= 2 ) {
117+ // second element must be a number
118+ if (!(array .get (1 ) instanceof Number )) {
119+ throw new JsonLogicException ("Second element of the fraction property is not a number" );
120+ }
121+ weight = ((Number ) array .get (1 )).intValue ();
122+ } else {
123+ weight = 1 ;
124+ }
127125 }
128126
127+ double getPercentage (int totalWeight ) {
128+ if (weight == 0 ) {
129+ return 0 ;
130+ }
131+ return weight * 100 / totalWeight ;
132+ }
129133 }
130134}
0 commit comments