20
20
21
21
import org .elasticsearch .ElasticsearchParseException ;
22
22
import org .elasticsearch .common .ParseField ;
23
+ import org .elasticsearch .common .Strings ;
23
24
import org .elasticsearch .common .io .stream .StreamInput ;
24
25
import org .elasticsearch .common .io .stream .StreamOutput ;
25
26
import org .elasticsearch .common .io .stream .Writeable ;
38
39
*/
39
40
public final class Fuzziness implements ToXContentFragment , Writeable {
40
41
41
- public static final String X_FIELD_NAME = "fuzziness" ;
42
- public static final Fuzziness ZERO = new Fuzziness (0 );
43
- public static final Fuzziness ONE = new Fuzziness (1 );
44
- public static final Fuzziness TWO = new Fuzziness (2 );
45
- public static final Fuzziness AUTO = new Fuzziness ("AUTO" );
42
+ static final String X_FIELD_NAME = "fuzziness" ;
46
43
public static final ParseField FIELD = new ParseField (X_FIELD_NAME );
47
- private static final int DEFAULT_LOW_DISTANCE = 3 ;
48
- private static final int DEFAULT_HIGH_DISTANCE = 6 ;
44
+
45
+ public static final Fuzziness ZERO = new Fuzziness ("0" );
46
+ public static final Fuzziness ONE = new Fuzziness ("1" );
47
+ public static final Fuzziness TWO = new Fuzziness ("2" );
48
+ public static final Fuzziness AUTO = new Fuzziness ("AUTO" );
49
+
50
+ static final int DEFAULT_LOW_DISTANCE = 3 ;
51
+ static final int DEFAULT_HIGH_DISTANCE = 6 ;
49
52
50
53
private final String fuzziness ;
51
54
private int lowDistance = DEFAULT_LOW_DISTANCE ;
52
55
private int highDistance = DEFAULT_HIGH_DISTANCE ;
53
56
54
- private Fuzziness (int fuzziness ) {
55
- if (fuzziness != 0 && fuzziness != 1 && fuzziness != 2 ) {
56
- throw new IllegalArgumentException ("Valid edit distances are [0, 1, 2] but was [" + fuzziness + "]" );
57
- }
58
- this .fuzziness = Integer .toString (fuzziness );
57
+ private Fuzziness (String fuzziness ) {
58
+ this .fuzziness = fuzziness ;
59
59
}
60
60
61
- private Fuzziness (String fuzziness ) {
62
- if (fuzziness == null || fuzziness .isEmpty ()) {
63
- throw new IllegalArgumentException ("fuzziness can't be null!" );
61
+ /**
62
+ * Creates a {@link Fuzziness} instance from an edit distance. The value must be one of {@code [0, 1, 2]}
63
+ * Note: Using this method only makes sense if the field you are applying Fuzziness to is some sort of string.
64
+ * @throws IllegalArgumentException if the edit distance is not in [0, 1, 2]
65
+ */
66
+ public static Fuzziness fromEdits (int edits ) {
67
+ switch (edits ) {
68
+ case 0 : return Fuzziness .ZERO ;
69
+ case 1 : return Fuzziness .ONE ;
70
+ case 2 : return Fuzziness .TWO ;
71
+ default :
72
+ throw new IllegalArgumentException ("Valid edit distances are [0, 1, 2] but was [" + edits + "]" );
64
73
}
65
- this .fuzziness = fuzziness .toUpperCase (Locale .ROOT );
66
74
}
67
75
68
- private Fuzziness (String fuzziness , int lowDistance , int highDistance ) {
69
- this (fuzziness );
70
- if (lowDistance < 0 || highDistance < 0 || lowDistance > highDistance ) {
71
- throw new IllegalArgumentException ("fuzziness wrongly configured, must be: lowDistance > 0, highDistance" +
72
- " > 0 and lowDistance <= highDistance " );
76
+ /**
77
+ * Creates a {@link Fuzziness} instance from a String representation. This can
78
+ * either be an edit distance where the value must be one of
79
+ * {@code ["0", "1", "2"]} or "AUTO" for a fuzziness that depends on the term
80
+ * length. Using the "AUTO" fuzziness, you can optionally supply low and high
81
+ * distance arguments in the format {@code "AUTO:[low],[high]"}. See the query
82
+ * DSL documentation for more information about how these values affect the
83
+ * fuzziness value.
84
+ * Note: Using this method only makes sense if the field you
85
+ * are applying Fuzziness to is some sort of string.
86
+ */
87
+ public static Fuzziness fromString (String fuzzinessString ) {
88
+ if (Strings .isEmpty (fuzzinessString )) {
89
+ throw new IllegalArgumentException ("fuzziness cannot be null or empty." );
90
+ }
91
+ String upperCase = fuzzinessString .toUpperCase (Locale .ROOT );
92
+ // check if it is one of the "AUTO" variants
93
+ if (upperCase .equals ("AUTO" )) {
94
+ return Fuzziness .AUTO ;
95
+ } else if (upperCase .startsWith ("AUTO:" )) {
96
+ return parseCustomAuto (upperCase );
97
+ } else {
98
+ // should be a float or int representing a valid edit distance, otherwise throw error
99
+ try {
100
+ float parsedFloat = Float .parseFloat (upperCase );
101
+ if (parsedFloat % 1 > 0 ) {
102
+ throw new IllegalArgumentException ("fuzziness needs to be one of 0.0, 1.0 or 2.0 but was " + parsedFloat );
103
+ }
104
+ return fromEdits ((int ) parsedFloat );
105
+ } catch (NumberFormatException e ) {
106
+ throw new IllegalArgumentException ("fuzziness cannot be [" + fuzzinessString + "]." , e );
107
+ }
73
108
}
74
- this .lowDistance = lowDistance ;
75
- this .highDistance = highDistance ;
76
109
}
77
110
78
111
/**
@@ -101,39 +134,23 @@ public void writeTo(StreamOutput out) throws IOException {
101
134
}
102
135
}
103
136
104
- /**
105
- * Creates a {@link Fuzziness} instance from an edit distance. The value must be one of {@code [0, 1, 2]}
106
- *
107
- * Note: Using this method only makes sense if the field you are applying Fuzziness to is some sort of string.
108
- */
109
- public static Fuzziness fromEdits (int edits ) {
110
- return new Fuzziness (edits );
111
- }
112
-
113
- public static Fuzziness build (Object fuzziness ) {
114
- if (fuzziness instanceof Fuzziness ) {
115
- return (Fuzziness ) fuzziness ;
116
- }
117
- String string = fuzziness .toString ();
118
- if (AUTO .asString ().equalsIgnoreCase (string )) {
119
- return AUTO ;
120
- } else if (string .toUpperCase (Locale .ROOT ).startsWith (AUTO .asString () + ":" )) {
121
- return parseCustomAuto (string );
122
- }
123
- return new Fuzziness (string );
124
- }
125
-
126
- private static Fuzziness parseCustomAuto ( final String string ) {
127
- assert string .toUpperCase (Locale .ROOT ).startsWith (AUTO .asString () + ":" );
128
- String [] fuzzinessLimit = string .substring (AUTO .asString ().length () + 1 ).split ("," );
137
+ private static Fuzziness parseCustomAuto (final String fuzzinessString ) {
138
+ assert fuzzinessString .toUpperCase (Locale .ROOT ).startsWith (AUTO .asString () + ":" );
139
+ String [] fuzzinessLimit = fuzzinessString .substring (AUTO .asString ().length () + 1 ).split ("," );
129
140
if (fuzzinessLimit .length == 2 ) {
130
141
try {
131
142
int lowerLimit = Integer .parseInt (fuzzinessLimit [0 ]);
132
143
int highLimit = Integer .parseInt (fuzzinessLimit [1 ]);
133
- return new Fuzziness ("AUTO" , lowerLimit , highLimit );
144
+ if (lowerLimit < 0 || highLimit < 0 || lowerLimit > highLimit ) {
145
+ throw new ElasticsearchParseException ("fuzziness wrongly configured [{}]. Must be 0 < lower value <= higher value." ,
146
+ fuzzinessString );
147
+ }
148
+ Fuzziness fuzziness = new Fuzziness ("AUTO" );
149
+ fuzziness .lowDistance = lowerLimit ;
150
+ fuzziness .highDistance = highLimit ;
151
+ return fuzziness ;
134
152
} catch (NumberFormatException e ) {
135
- throw new ElasticsearchParseException ("failed to parse [{}] as a \" auto:int,int\" " , e ,
136
- string );
153
+ throw new ElasticsearchParseException ("failed to parse [{}] as a \" auto:int,int\" " , e , fuzzinessString );
137
154
}
138
155
} else {
139
156
throw new ElasticsearchParseException ("failed to find low and high distance values" );
@@ -144,29 +161,9 @@ public static Fuzziness parse(XContentParser parser) throws IOException {
144
161
XContentParser .Token token = parser .currentToken ();
145
162
switch (token ) {
146
163
case VALUE_STRING :
164
+ return fromString (parser .text ());
147
165
case VALUE_NUMBER :
148
- final String fuzziness = parser .text ();
149
- if (AUTO .asString ().equalsIgnoreCase (fuzziness )) {
150
- return AUTO ;
151
- } else if (fuzziness .toUpperCase (Locale .ROOT ).startsWith (AUTO .asString () + ":" )) {
152
- return parseCustomAuto (fuzziness );
153
- }
154
- try {
155
- final int minimumSimilarity = Integer .parseInt (fuzziness );
156
- switch (minimumSimilarity ) {
157
- case 0 :
158
- return ZERO ;
159
- case 1 :
160
- return ONE ;
161
- case 2 :
162
- return TWO ;
163
- default :
164
- return build (fuzziness );
165
- }
166
- } catch (NumberFormatException ex ) {
167
- return build (fuzziness );
168
- }
169
-
166
+ return fromEdits (parser .intValue ());
170
167
default :
171
168
throw new IllegalArgumentException ("Can't parse fuzziness on token: [" + token + "]" );
172
169
}
@@ -200,7 +197,7 @@ public float asFloat() {
200
197
if (this .equals (AUTO ) || isAutoWithCustomValues ()) {
201
198
return 1f ;
202
199
}
203
- return Float .parseFloat (fuzziness . toString () );
200
+ return Float .parseFloat (fuzziness );
204
201
}
205
202
206
203
private int termLen (String text ) {
@@ -209,13 +206,13 @@ private int termLen(String text) {
209
206
210
207
public String asString () {
211
208
if (isAutoWithCustomValues ()) {
212
- return fuzziness . toString () + ":" + lowDistance + "," + highDistance ;
209
+ return fuzziness + ":" + lowDistance + "," + highDistance ;
213
210
}
214
- return fuzziness . toString () ;
211
+ return fuzziness ;
215
212
}
216
213
217
214
private boolean isAutoWithCustomValues () {
218
- return fuzziness .startsWith ("AUTO" ) && (lowDistance != DEFAULT_LOW_DISTANCE ||
215
+ return fuzziness .equals ("AUTO" ) && (lowDistance != DEFAULT_LOW_DISTANCE ||
219
216
highDistance != DEFAULT_HIGH_DISTANCE );
220
217
}
221
218
0 commit comments