Skip to content
Browse files

make type of range query explicit.

  • Loading branch information...
1 parent 8b317e7 commit bf989bc210ef6dde4a1a0fe7f7e1cd4e0ff21136 Robert Newson committed Jan 21, 2010
View
18 README.md
@@ -339,23 +339,21 @@ You can perform all types of queries using Lucene's default <a href="http://luce
<h2>Numeric range queries</h2>
-In addition to normal text-based range searches (using the "field:[lower TO upper]" syntax), couchdb-lucene all supports numeric range searches for the following types: integer, long, float, double and date. The type is automatically derived from the search terms used, as follows;
+In addition to normal text-based range searches (using the "field:[lower TO upper]" syntax), couchdb-lucene all supports numeric range searches for the following types: int, long, float, double and date. The type is specified after the field name, as follows;
<table>
-<tr><td>type</td><td>format</td><td>example</td></tr>
-<tr><td>integer</td><td>[0-9]+</td><td>[0 TO 100]</td></tr>
-<tr><td>long</td><td>[0-9]+L</td><td>[0L TO 100L]</td></tr>
-<tr><td>float</td><td>[0-9]+.[0-9]+f</td><td>[0.0f TO 100.0f]</td></tr>
-<tr><td>double</td><td>[0-9]+.[0-9]+</td><td>[0.0 TO 100.0]</td></tr>
-<tr><td>date</td><td>yyyy-MM-dd or yyyy-MM-ddZZ or yyyy-MM-dd'T'HH:mm:ss or yyyy-MM-dd'T'HH:mm:ssZZ</td><td>2001-01-01 or 2001-01-01-0500 or 2000-01-01T00:00:00 or 2000-01-01T00:00:00-0500</td></tr>
+<tr><td>type</td><td>example</td></tr>
+<tr><td>integer</td><td>field<int>:[0 TO 100]</td></tr>
+<tr><td>long</td><td>field<long>:[0 TO 100]</td></tr>
+<tr><td>float</td><td>field<float>:[0.0 TO 100.0]</td></tr>
+<tr><td>double</td><td>field<double>:[0.0 TO 100.0]</td></tr>
+<tr><td>date</td><td>field<date>:[2001-01-01 TO 2010-01-01] or field<date>:[2000-01-01T00:00:00-0500 TO 2010-01-01T00:00:00-0500]</td></tr>
</table>
-Both the upper and lower bound must be of the same type to trigger numeric range searching. If they don't match, then a normal text-based range search is performed.
-
An example numeric range query for spatial searching.
<pre>
-?q=pizza AND lat:[51.4707 TO 51.5224] AND long:[-0.6622 TO -0.5775]
+?q=pizza AND lat<double>:[51.4707 TO 51.5224] AND long<double>:[-0.6622 TO -0.5775]
</pre>
The following parameters can be passed for more sophisticated searches;
View
79 src/main/java/com/github/rnewson/couchdb/lucene/CustomQueryParser.java
@@ -16,6 +16,9 @@
* limitations under the License.
*/
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
@@ -41,6 +44,8 @@
private static String[] DATE_PATTERNS = new String[] { "yyyy-MM-dd'T'HH:mm:ssZZ", "yyyy-MM-dd'T'HH:mm:ss", "yyyy-MM-ddZZ",
"yyyy-MM-dd" };
+ private static Pattern NUMERIC_RANGE_PATTERN = Pattern.compile("^(\\w+)(<\\w+>)?$");
+
public CustomQueryParser(final Version matchVersion, final String f, final Analyzer a) {
super(matchVersion, f, a);
}
@@ -134,55 +139,53 @@ public static String toString(final SortField[] sortFields) {
return result.toString();
}
- private Object fixup(final String value) {
- if (value.matches("[-+]?\\d+\\.\\d+f")) {
- return Float.parseFloat(value);
- }
- if (value.matches("[-+]?\\d+\\.\\d+")) {
- return Double.parseDouble(value);
- }
- if (value.matches("[-+]?\\d+[lL]")) {
- return Long.parseLong(value.substring(0, value.length() - 1));
+ @Override
+ protected Query getRangeQuery(final String fieldAndType, final String part1, final String part2, final boolean inclusive)
+ throws ParseException {
+ final Matcher matcher = NUMERIC_RANGE_PATTERN.matcher(fieldAndType);
+
+ if (!matcher.matches()) {
+ throw new ParseException("Field name '" + fieldAndType + "' not recognized.");
}
- if (value.matches("[-+]?\\d+")) {
- return Integer.parseInt(value);
+
+ final String field = matcher.group(1);
+ final String type = matcher.group(2) == null ? "<string>" : matcher.group(2);
+
+ if ("<string>".equals(type)) {
+ return newRangeQuery(field, part1, part2, inclusive);
}
- try {
- return DateUtils.parseDate(value.toUpperCase(), DATE_PATTERNS).getTime();
- } catch (final DateParseException e) {
- // Ignore.
+ if ("<int>".equals(type)) {
+ return NumericRangeQuery.newIntRange(field, 4, Integer.parseInt(part1), Integer.parseInt(part2), inclusive, inclusive);
}
- return value;
- }
+ if ("<long>".equals(type)) {
+ return NumericRangeQuery.newLongRange(field, 4, Long.parseLong(part1), Long.parseLong(part2), inclusive, inclusive);
+ }
- @Override
- protected Query getRangeQuery(final String field, final String part1, final String part2, final boolean inclusive)
- throws ParseException {
- final Object lower = fixup(part1);
- final Object upper = fixup(part2);
+ if ("<float>".equals(type)) {
+ return NumericRangeQuery
+ .newFloatRange(field, 4, Float.parseFloat(part1), Float.parseFloat(part2), inclusive, inclusive);
+ }
- // Sanity check.
- if (lower.getClass() == upper.getClass()) {
- if (lower instanceof Float) {
- return NumericRangeQuery.newFloatRange(field, 4, (Float) lower, (Float) upper, inclusive, inclusive);
- }
+ if ("<double>".equals(type)) {
+ return NumericRangeQuery.newDoubleRange(field, 4, Double.parseDouble(part1), Double.parseDouble(part2), inclusive,
+ inclusive);
+ }
- if (lower instanceof Double) {
- return NumericRangeQuery.newDoubleRange(field, 8, (Double) lower, (Double) upper, inclusive, inclusive);
- }
+ if ("<date>".equals(type)) {
+ return NumericRangeQuery.newLongRange(field, 8, date(part1), date(part2), inclusive, inclusive);
+ }
- if (lower instanceof Long) {
- return NumericRangeQuery.newLongRange(field, 8, (Long) lower, (Long) upper, inclusive, inclusive);
- }
+ throw new ParseException("Unrecognized type '" + type + "'");
+ }
- if (lower instanceof Integer) {
- return NumericRangeQuery.newIntRange(field, 4, (Integer) lower, (Integer) upper, inclusive, inclusive);
- }
+ private long date(final String str) throws ParseException {
+ try {
+ return DateUtils.parseDate(str.toUpperCase(), DATE_PATTERNS).getTime();
+ } catch (DateParseException e) {
+ throw new ParseException(e.getMessage());
}
-
- return newRangeQuery(field, part1, part2, inclusive);
}
}
View
2 src/main/java/com/github/rnewson/couchdb/lucene/SearchServlet.java
@@ -123,7 +123,7 @@ public void callback(final IndexSearcher searcher, final String version) throws
try {
arr.add(performQuery(debug, rewrite_query, searcher, version, parser.parse(query)));
} catch (final ParseException e) {
- ServletUtils.sendJSONError(req, resp, 400, "Bad query syntax");
+ ServletUtils.sendJSONError(req, resp, 400, "Bad query syntax: " + e.getMessage());
return;
}
}
View
16 src/test/java/com/github/rnewson/couchdb/lucene/CustomQueryParserTest.java
@@ -21,49 +21,49 @@ public void setup() {
@Test
public void integerRangeQuery() throws Exception {
- final Query q = parser.parse("blah:[0 TO 123]");
+ final Query q = parser.parse("blah<int>:[0 TO 123]");
assertRange(q, Integer.class, 0, 123);
}
@Test
public void longRangeQuery() throws Exception {
- final Query q = parser.parse("blah:[0L TO 123L]");
+ final Query q = parser.parse("blah<long>:[0 TO 123]");
assertRange(q, Long.class, 0L, 123L);
}
@Test
public void floatRangeQuery() throws Exception {
- final Query q = parser.parse("blah:[0.0f TO 123.5f]");
+ final Query q = parser.parse("blah<float>:[0.0 TO 123.5]");
assertRange(q, Float.class, 0.0f, 123.5f);
}
@Test
public void doubleRangeQuery() throws Exception {
- final Query q = parser.parse("blah:[0.0 TO 123.0]");
+ final Query q = parser.parse("blah<double>:[0.0 TO 123.0]");
assertRange(q, Double.class, 0.0, 123.0);
}
@Test
public void dateRangeQuery() throws Exception {
- final Query q = parser.parse("blah:[2000-01-01 TO 2010-02-04]");
+ final Query q = parser.parse("blah<date>:[2000-01-01 TO 2010-02-04]");
assertRange(q, Long.class, 946684800000L, 1265241600000L);
}
@Test
public void dateTimeRangeQuery() throws Exception {
- final Query q = parser.parse("blah:[2000-01-01T00:00:01 TO 2010-02-04T00:00:01]");
+ final Query q = parser.parse("blah<date>:[2000-01-01T00:00:01 TO 2010-02-04T00:00:01]");
assertRange(q, Long.class, 946684801000L, 1265241601000L);
}
@Test
public void dateTimeZoneRangeQuery() throws Exception {
- final Query q = parser.parse("blah:[2000-01-01-0100 TO 2010-02-04-0100]");
+ final Query q = parser.parse("blah<date>:[2000-01-01-0100 TO 2010-02-04-0100]");
assertRange(q, Long.class, 946688400000L, 1265245200000L);
}
@Test
public void dateTimeTimeZoneRangeQuery() throws Exception {
- final Query q = parser.parse("blah:[2000-01-01T00:00:00-0100 TO 2010-02-04T00:00:00-0100]");
+ final Query q = parser.parse("blah<date>:[2000-01-01T00:00:00-0100 TO 2010-02-04T00:00:00-0100]");
assertRange(q, Long.class, 946688400000L, 1265245200000L);
}

0 comments on commit bf989bc

Please sign in to comment.
Something went wrong with that request. Please try again.