2020
2121import org .elasticsearch .ElasticsearchParseException ;
2222import org .elasticsearch .common .ParseField ;
23+ import org .elasticsearch .common .Strings ;
2324import org .elasticsearch .common .io .stream .StreamInput ;
2425import org .elasticsearch .common .io .stream .StreamOutput ;
2526import org .elasticsearch .common .io .stream .Writeable ;
3839 */
3940public final class Fuzziness implements ToXContentFragment , Writeable {
4041
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" ;
4643 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 ;
4952
5053 private final String fuzziness ;
5154 private int lowDistance = DEFAULT_LOW_DISTANCE ;
5255 private int highDistance = DEFAULT_HIGH_DISTANCE ;
5356
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 ;
5959 }
6060
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 + "]" );
6473 }
65- this .fuzziness = fuzziness .toUpperCase (Locale .ROOT );
6674 }
6775
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+ }
73108 }
74- this .lowDistance = lowDistance ;
75- this .highDistance = highDistance ;
76109 }
77110
78111 /**
@@ -101,39 +134,23 @@ public void writeTo(StreamOutput out) throws IOException {
101134 }
102135 }
103136
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 ("," );
129140 if (fuzzinessLimit .length == 2 ) {
130141 try {
131142 int lowerLimit = Integer .parseInt (fuzzinessLimit [0 ]);
132143 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 ;
134152 } 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 );
137154 }
138155 } else {
139156 throw new ElasticsearchParseException ("failed to find low and high distance values" );
@@ -144,29 +161,9 @@ public static Fuzziness parse(XContentParser parser) throws IOException {
144161 XContentParser .Token token = parser .currentToken ();
145162 switch (token ) {
146163 case VALUE_STRING :
164+ return fromString (parser .text ());
147165 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 ());
170167 default :
171168 throw new IllegalArgumentException ("Can't parse fuzziness on token: [" + token + "]" );
172169 }
@@ -200,7 +197,7 @@ public float asFloat() {
200197 if (this .equals (AUTO ) || isAutoWithCustomValues ()) {
201198 return 1f ;
202199 }
203- return Float .parseFloat (fuzziness . toString () );
200+ return Float .parseFloat (fuzziness );
204201 }
205202
206203 private int termLen (String text ) {
@@ -209,13 +206,13 @@ private int termLen(String text) {
209206
210207 public String asString () {
211208 if (isAutoWithCustomValues ()) {
212- return fuzziness . toString () + ":" + lowDistance + "," + highDistance ;
209+ return fuzziness + ":" + lowDistance + "," + highDistance ;
213210 }
214- return fuzziness . toString () ;
211+ return fuzziness ;
215212 }
216213
217214 private boolean isAutoWithCustomValues () {
218- return fuzziness .startsWith ("AUTO" ) && (lowDistance != DEFAULT_LOW_DISTANCE ||
215+ return fuzziness .equals ("AUTO" ) && (lowDistance != DEFAULT_LOW_DISTANCE ||
219216 highDistance != DEFAULT_HIGH_DISTANCE );
220217 }
221218
0 commit comments