@@ -50,37 +50,35 @@ public Object evaluate(List arguments, Object data) throws JsonLogicEvaluationEx
50
50
}
51
51
52
52
final List <FractionProperty > propertyList = new ArrayList <>();
53
+ int totalWeight = 0 ;
53
54
54
- double distribution = 0 ;
55
55
try {
56
56
for (Object dist : distibutions ) {
57
57
FractionProperty fractionProperty = new FractionProperty (dist );
58
58
propertyList .add (fractionProperty );
59
- distribution += fractionProperty .getPercentage ();
59
+ totalWeight += fractionProperty .getWeight ();
60
60
}
61
61
} catch (JsonLogicException e ) {
62
62
log .debug ("Error parsing fractional targeting rule" , e );
63
63
return null ;
64
64
}
65
65
66
- if (distribution != 100 ) {
67
- log .debug ("Fractional properties do not sum to 100" );
68
- return null ;
69
- }
70
-
71
66
// find distribution
72
- return distributeValue (bucketBy , propertyList );
67
+ return distributeValue (bucketBy , propertyList , totalWeight );
73
68
}
74
69
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 {
77
75
byte [] bytes = hashKey .getBytes (StandardCharsets .UTF_8 );
78
76
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 ;
80
78
81
- int bucketSum = 0 ;
79
+ float bucketSum = 0 ;
82
80
for (FractionProperty p : propertyList ) {
83
- bucketSum += p .getPercentage ();
81
+ bucketSum += p .getPercentage (totalWeight );
84
82
85
83
if (bucket < bucketSum ) {
86
84
return p .getVariant ();
@@ -95,7 +93,7 @@ private static String distributeValue(final String hashKey, final List<FractionP
95
93
@ SuppressWarnings ({"checkstyle:NoFinalizer" })
96
94
private static class FractionProperty {
97
95
private final String variant ;
98
- private final int percentage ;
96
+ private final int weight ;
99
97
100
98
protected final void finalize () {
101
99
// DO NOT REMOVE, spotbugs: CT_CONSTRUCTOR_THROW
@@ -108,23 +106,32 @@ protected final void finalize() {
108
106
109
107
final List <?> array = (List ) from ;
110
108
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 " );
113
111
}
114
112
115
113
// first must be a string
116
114
if (!(array .get (0 ) instanceof String )) {
117
115
throw new JsonLogicException ("First element of the fraction property is not a string variant" );
118
116
}
119
117
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
-
125
118
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
+ }
127
128
}
128
129
130
+ float getPercentage (int totalWeight ) {
131
+ if (weight == 0 ) {
132
+ return 0 ;
133
+ }
134
+ return (float ) (weight * 100 ) / totalWeight ;
135
+ }
129
136
}
130
137
}
0 commit comments