@@ -50,37 +50,32 @@ 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 )
70
+ private static String distributeValue (final String hashKey , final List <FractionProperty > propertyList , int totalWeight )
76
71
throws JsonLogicEvaluationException {
77
72
byte [] bytes = hashKey .getBytes (StandardCharsets .UTF_8 );
78
73
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 ;
80
75
81
- int bucketSum = 0 ;
76
+ float bucketSum = 0 ;
82
77
for (FractionProperty p : propertyList ) {
83
- bucketSum += p .getPercentage ();
78
+ bucketSum += p .getPercentage (totalWeight );
84
79
85
80
if (bucket < bucketSum ) {
86
81
return p .getVariant ();
@@ -95,7 +90,7 @@ private static String distributeValue(final String hashKey, final List<FractionP
95
90
@ SuppressWarnings ({"checkstyle:NoFinalizer" })
96
91
private static class FractionProperty {
97
92
private final String variant ;
98
- private final int percentage ;
93
+ private final int weight ;
99
94
100
95
protected final void finalize () {
101
96
// DO NOT REMOVE, spotbugs: CT_CONSTRUCTOR_THROW
@@ -108,23 +103,32 @@ protected final void finalize() {
108
103
109
104
final List <?> array = (List ) from ;
110
105
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 " );
113
108
}
114
109
115
110
// first must be a string
116
111
if (!(array .get (0 ) instanceof String )) {
117
112
throw new JsonLogicException ("First element of the fraction property is not a string variant" );
118
113
}
119
114
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
115
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
+ }
127
125
}
128
126
127
+ float getPercentage (int totalWeight ) {
128
+ if (weight == 0 ) {
129
+ return 0 ;
130
+ }
131
+ return (float ) (weight * 100 ) / totalWeight ;
132
+ }
129
133
}
130
134
}
0 commit comments