@@ -50,37 +50,35 @@ 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 )
76- throws JsonLogicEvaluationException {
70+ private static String distributeValue (
71+ final String hashKey ,
72+ final List <FractionProperty > propertyList ,
73+ int totalWeight
74+ ) throws JsonLogicEvaluationException {
7775 byte [] bytes = hashKey .getBytes (StandardCharsets .UTF_8 );
7876 int mmrHash = MurmurHash3 .hash32x86 (bytes , 0 , bytes .length , 0 );
79- int bucket = (int ) (( Math .abs (mmrHash ) * 1.0f / Integer .MAX_VALUE ) * 100 ) ;
77+ float bucket = (Math .abs (mmrHash ) * 1.0f / Integer .MAX_VALUE ) * 100 ;
8078
81- int bucketSum = 0 ;
79+ float bucketSum = 0 ;
8280 for (FractionProperty p : propertyList ) {
83- bucketSum += p .getPercentage ();
81+ bucketSum += p .getPercentage (totalWeight );
8482
8583 if (bucket < bucketSum ) {
8684 return p .getVariant ();
@@ -95,7 +93,7 @@ private static String distributeValue(final String hashKey, final List<FractionP
9593 @ SuppressWarnings ({"checkstyle:NoFinalizer" })
9694 private static class FractionProperty {
9795 private final String variant ;
98- private final int percentage ;
96+ private final int weight ;
9997
10098 protected final void finalize () {
10199 // DO NOT REMOVE, spotbugs: CT_CONSTRUCTOR_THROW
@@ -108,23 +106,32 @@ protected final void finalize() {
108106
109107 final List <?> array = (List ) from ;
110108
111- if (array .size () != 2 ) {
112- throw new JsonLogicException ("Fraction property does not have two elements " );
109+ if (array .isEmpty () ) {
110+ throw new JsonLogicException ("Fraction property needs at least one element " );
113111 }
114112
115113 // first must be a string
116114 if (!(array .get (0 ) instanceof String )) {
117115 throw new JsonLogicException ("First element of the fraction property is not a string variant" );
118116 }
119117
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-
125118 variant = (String ) array .get (0 );
126- percentage = ((Number ) array .get (1 )).intValue ();
119+ if (array .size () >= 2 ) {
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+ weight = ((Number ) array .get (1 )).intValue ();
125+ } else {
126+ weight = 1 ;
127+ }
127128 }
128129
130+ float getPercentage (int totalWeight ) {
131+ if (weight == 0 ) {
132+ return 0 ;
133+ }
134+ return (float ) (weight * 100 ) / totalWeight ;
135+ }
129136 }
130137}
0 commit comments