You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ds...@apache.org on 2014/12/14 05:59:01 UTC
svn commit: r1645384 - in /lucene/dev/branches/branch_5x: ./ solr/
solr/core/ solr/core/src/java/org/apache/solr/request/
solr/core/src/java/org/apache/solr/schema/
solr/core/src/test-files/solr/collection1/conf/
solr/core/src/test/org/apache/solr/requ...
Author: dsmiley
Date: Sun Dec 14 04:59:00 2014
New Revision: 1645384
URL: http://svn.apache.org/r1645384
Log:
SOLR-6827: DateRangeField support for facet.range, exclusive ranges, DateMath
Modified:
lucene/dev/branches/branch_5x/ (props changed)
lucene/dev/branches/branch_5x/solr/ (props changed)
lucene/dev/branches/branch_5x/solr/CHANGES.txt (contents, props changed)
lucene/dev/branches/branch_5x/solr/core/ (props changed)
lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/request/SimpleFacets.java
lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/schema/AbstractSpatialFieldType.java
lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/schema/DateRangeField.java
lucene/dev/branches/branch_5x/solr/core/src/test-files/solr/collection1/conf/schema.xml
lucene/dev/branches/branch_5x/solr/core/src/test/org/apache/solr/request/SimpleFacetsTest.java
lucene/dev/branches/branch_5x/solr/core/src/test/org/apache/solr/schema/DateRangeFieldTest.java
Modified: lucene/dev/branches/branch_5x/solr/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_5x/solr/CHANGES.txt?rev=1645384&r1=1645383&r2=1645384&view=diff
==============================================================================
--- lucene/dev/branches/branch_5x/solr/CHANGES.txt (original)
+++ lucene/dev/branches/branch_5x/solr/CHANGES.txt Sun Dec 14 04:59:00 2014
@@ -104,8 +104,9 @@ New Features
modifying solr configuration files. (Erick Erickson)
- SOLR-5539: Admin UI - Remove ability to create/modify files (steffkes)
-* SOLR-6103: Added DateRangeField for indexing date ranges, especially
- multi-valued ones. Based on LUCENE-5648. (David Smiley)
+* SOLR-6103: Added DateRangeField for indexing date ranges, especially multi-valued ones.
+ Supports facet.range, DateMath, and is mostly interoperable with TrieDateField.
+ Based on LUCENE-5648. (David Smiley)
* SOLR-6403: TransactionLog replay status logging. (Mark Miller)
Modified: lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/request/SimpleFacets.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/request/SimpleFacets.java?rev=1645384&r1=1645383&r2=1645384&view=diff
==============================================================================
--- lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/request/SimpleFacets.java (original)
+++ lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/request/SimpleFacets.java Sun Dec 14 04:59:00 2014
@@ -37,10 +37,10 @@ import java.util.concurrent.SynchronousQ
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
-import org.apache.lucene.index.LeafReader;
-import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.DocsEnum;
import org.apache.lucene.index.Fields;
+import org.apache.lucene.index.LeafReader;
+import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.MultiDocsEnum;
import org.apache.lucene.index.Term;
import org.apache.lucene.index.Terms;
@@ -74,6 +74,7 @@ import org.apache.solr.common.util.StrUt
import org.apache.solr.handler.component.ResponseBuilder;
import org.apache.solr.request.IntervalFacets.FacetInterval;
import org.apache.solr.schema.BoolField;
+import org.apache.solr.schema.DateRangeField;
import org.apache.solr.schema.FieldType;
import org.apache.solr.schema.IndexSchema;
import org.apache.solr.schema.SchemaField;
@@ -1080,6 +1081,8 @@ public class SimpleFacets {
(SolrException.ErrorCode.BAD_REQUEST,
"Unable to range facet on tried field of unexpected type:" + f);
}
+ } else if (ft instanceof DateRangeField) {
+ calc = new DateRangeFieldEndpointCalculator(sf, null);
} else {
throw new SolrException
(SolrException.ErrorCode.BAD_REQUEST,
@@ -1420,6 +1423,7 @@ public class SimpleFacets {
}
private static class DateRangeEndpointCalculator
extends RangeEndpointCalculator<Date> {
+ private static final String TYPE_ERR_MSG = "SchemaField must use field type extending TrieDateField or DateRangeField";
private final Date now;
public DateRangeEndpointCalculator(final SchemaField f,
final Date now) {
@@ -1427,7 +1431,7 @@ public class SimpleFacets {
this.now = now;
if (! (field.getType() instanceof TrieDateField) ) {
throw new IllegalArgumentException
- ("SchemaField must use field type extending TrieDateField");
+ (TYPE_ERR_MSG);
}
}
@Override
@@ -1440,6 +1444,36 @@ public class SimpleFacets {
}
@Override
protected Object parseGap(final String rawval) {
+ return rawval;
+ }
+ @Override
+ public Date parseAndAddGap(Date value, String gap) throws java.text.ParseException {
+ final DateMathParser dmp = new DateMathParser();
+ dmp.setNow(value);
+ return dmp.parseMath(gap);
+ }
+ }
+ private static class DateRangeFieldEndpointCalculator
+ extends RangeEndpointCalculator<Date> {
+ private final Date now;
+ public DateRangeFieldEndpointCalculator(final SchemaField f,
+ final Date now) {
+ super(f);
+ this.now = now;
+ if (! (field.getType() instanceof DateRangeField) ) {
+ throw new IllegalArgumentException(DateRangeEndpointCalculator.TYPE_ERR_MSG);
+ }
+ }
+ @Override
+ public String formatValue(Date val) {
+ return TrieDateField.formatExternal(val);
+ }
+ @Override
+ protected Date parseVal(String rawval) {
+ return ((DateRangeField)field.getType()).parseMath(now, rawval);
+ }
+ @Override
+ protected Object parseGap(final String rawval) {
return rawval;
}
@Override
Modified: lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/schema/AbstractSpatialFieldType.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/schema/AbstractSpatialFieldType.java?rev=1645384&r1=1645383&r2=1645384&view=diff
==============================================================================
--- lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/schema/AbstractSpatialFieldType.java (original)
+++ lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/schema/AbstractSpatialFieldType.java Sun Dec 14 04:59:00 2014
@@ -17,6 +17,19 @@ package org.apache.solr.schema;
* limitations under the License.
*/
+import java.io.IOException;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+
import com.google.common.base.Throwables;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
@@ -51,19 +64,6 @@ import org.apache.solr.util.SpatialUtils
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.IOException;
-import java.text.ParseException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-
/**
* Abstract base class for Solr FieldTypes based on a Lucene 4 {@link SpatialStrategy}.
*
@@ -159,7 +159,7 @@ public abstract class AbstractSpatialFie
@Override
public List<IndexableField> createFields(SchemaField field, Object val, float boost) {
String shapeStr = null;
- Shape shape = null;
+ Shape shape;
if (val instanceof Shape) {
shape = ((Shape) val);
} else {
@@ -178,14 +178,17 @@ public abstract class AbstractSpatialFie
}
if (field.stored()) {
- if (shapeStr == null)
- shapeStr = shapeToString(shape);
- result.add(new StoredField(field.getName(), shapeStr));
+ result.add(new StoredField(field.getName(), getStoredValue(shape, shapeStr)));
}
return result;
}
+ /** Called by {@link #createFields(SchemaField, Object, float)} to get the stored value. */
+ protected String getStoredValue(Shape shape, String shapeStr) {
+ return (shapeStr == null) ? shapeToString(shape) : shapeStr;
+ }
+
protected Shape parseShape(String str) {
if (str.length() == 0)
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "empty string shape");
Modified: lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/schema/DateRangeField.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/schema/DateRangeField.java?rev=1645384&r1=1645383&r2=1645384&view=diff
==============================================================================
--- lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/schema/DateRangeField.java (original)
+++ lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/schema/DateRangeField.java Sun Dec 14 04:59:00 2014
@@ -35,9 +35,13 @@ import org.apache.lucene.spatial.query.S
import org.apache.lucene.spatial.query.SpatialOperation;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.params.SolrParams;
+import org.apache.solr.request.SolrRequestInfo;
import org.apache.solr.search.QParser;
+import org.apache.solr.search.SyntaxError;
/**
+ * A field for indexed dates and date ranges. It's mostly compatible with TrieDateField.
+ *
* @see NumberRangePrefixTreeStrategy
* @see DateRangePrefixTree
*/
@@ -45,7 +49,9 @@ public class DateRangeField extends Abst
private static final String OP_PARAM = "op";//local-param to resolve SpatialOperation
- private final DateRangePrefixTree tree = DateRangePrefixTree.INSTANCE;
+ private static final DateRangePrefixTree tree = DateRangePrefixTree.INSTANCE;
+
+ private static final TrieDateField trieDateField = new TrieDateField();//used for utility methods
@Override
protected void init(IndexSchema schema, Map<String, String> args) {
@@ -64,24 +70,74 @@ public class DateRangeField extends Abst
@Override
public List<IndexableField> createFields(SchemaField field, Object val, float boost) {
- if (val instanceof Date || val instanceof Calendar)//From URP
+ if (val instanceof Date || val instanceof Calendar)//From URP?
val = tree.toUnitShape(val);
return super.createFields(field, val, boost);
}
@Override
+ protected String getStoredValue(Shape shape, String shapeStr) {
+ if (shape instanceof UnitNRShape) {
+ UnitNRShape unitShape = (UnitNRShape) shape;
+ if (unitShape.getLevel() == tree.getMaxLevels()) {
+ //fully precise date. We can be fully compatible with TrieDateField.
+ Date date = tree.toCalendar(unitShape).getTime();
+ return TrieDateField.formatExternal(date);
+ }
+ }
+ return (shapeStr == null ? shape.toString() : shapeStr);//we don't normalize ranges here; should we?
+ }
+
+ @Override
protected NRShape parseShape(String str) {
- try {
- return tree.parseShape(str);
- } catch (ParseException e) {
- throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
- "Couldn't parse date because: "+ e.getMessage(), e);
+ if (str.contains(" TO ")) {
+ //TODO parsing range syntax doesn't support DateMath on either side or exclusive/inclusive
+ try {
+ return tree.parseShape(str);
+ } catch (ParseException e) {
+ throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
+ "Couldn't parse date because: "+ e.getMessage(), e);
+ }
+ } else {
+ return tree.toShape(parseCalendar(str));
+ }
+ }
+
+ private Calendar parseCalendar(String str) {
+ if (str.startsWith("NOW") || str.lastIndexOf('Z') >= 0) {
+ //use Solr standard date format parsing rules.
+ //TODO parse a Calendar instead of a Date, rounded according to DateMath syntax.
+ Date date = trieDateField.parseMath(null, str);
+ Calendar cal = tree.newCal();
+ cal.setTime(date);
+ return cal;
+ } else {
+ try {
+ return tree.parseCalendar(str);
+ } catch (ParseException e) {
+ throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
+ "Couldn't parse date because: "+ e.getMessage(), e);
+ }
+
}
}
+ /** For easy compatibility with {@link TrieDateField#parseMath(Date, String)}. */
+ public Date parseMath(Date now, String rawval) {
+ return trieDateField.parseMath(now, rawval);
+ }
+
@Override
protected String shapeToString(Shape shape) {
- return shape.toString();//generally round-trips for DateRangePrefixTree
+ if (shape instanceof UnitNRShape) {
+ UnitNRShape unitShape = (UnitNRShape) shape;
+ if (unitShape.getLevel() == tree.getMaxLevels()) {
+ //fully precise date. We can be fully compatible with TrieDateField.
+ Date date = tree.toCalendar(unitShape).getTime();
+ return TrieDateField.formatExternal(date);
+ }
+ }
+ return shape.toString();//range shape
}
@Override
@@ -99,15 +155,38 @@ public class DateRangeField extends Abst
}
@Override
- public Query getRangeQuery(QParser parser, SchemaField field, String part1, String part2, boolean minInclusive, boolean maxInclusive) {
- if (!minInclusive || !maxInclusive)
- throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "exclusive range boundary not supported");
- if (part1 == null)
- part1 = "*";
- if (part2 == null)
- part2 = "*";
- Shape shape = tree.toRangeShape((UnitNRShape) parseShape(part1), (UnitNRShape) parseShape(part2));
+ public Query getRangeQuery(QParser parser, SchemaField field, String startStr, String endStr, boolean minInclusive, boolean maxInclusive) {
+ if (parser == null) {//null when invoked by SimpleFacets. But getQueryFromSpatialArgs expects to get localParams.
+ final SolrRequestInfo requestInfo = SolrRequestInfo.getRequestInfo();
+ parser = new QParser("", null, requestInfo.getReq().getParams(), requestInfo.getReq()) {
+ @Override
+ public Query parse() throws SyntaxError {
+ throw new IllegalStateException();
+ }
+ };
+ }
+
+ Calendar startCal;
+ if (startStr == null) {
+ startCal = tree.newCal();
+ } else {
+ startCal = parseCalendar(startStr);
+ if (!minInclusive) {
+ startCal.add(Calendar.MILLISECOND, 1);
+ }
+ }
+ Calendar endCal;
+ if (endStr == null) {
+ endCal = tree.newCal();
+ } else {
+ endCal = parseCalendar(endStr);
+ if (!maxInclusive) {
+ endCal.add(Calendar.MILLISECOND, -1);
+ }
+ }
+ Shape shape = tree.toRangeShape(tree.toShape(startCal), tree.toShape(endCal));
SpatialArgs spatialArgs = new SpatialArgs(SpatialOperation.Intersects, shape);
return getQueryFromSpatialArgs(parser, field, spatialArgs);
}
+
}
Modified: lucene/dev/branches/branch_5x/solr/core/src/test-files/solr/collection1/conf/schema.xml
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_5x/solr/core/src/test-files/solr/collection1/conf/schema.xml?rev=1645384&r1=1645383&r2=1645384&view=diff
==============================================================================
--- lucene/dev/branches/branch_5x/solr/core/src/test-files/solr/collection1/conf/schema.xml (original)
+++ lucene/dev/branches/branch_5x/solr/core/src/test-files/solr/collection1/conf/schema.xml Sun Dec 14 04:59:00 2014
@@ -575,6 +575,7 @@
<dynamicField name="*_tdt" type="tdate" indexed="true" stored="true"/>
<dynamicField name="*_tdt1" type="tdate" indexed="true" stored="true" multiValued="false"/>
<dynamicField name="*_tdtdv" type="tdatedv" indexed="true" stored="true"/>
+ <dynamicField name="*_drf" type="dateRange" indexed="true" stored="true"/>
<dynamicField name="*_sI" type="string" indexed="true" stored="false"/>
<dynamicField name="*_sS" type="string" indexed="false" stored="true"/>
Modified: lucene/dev/branches/branch_5x/solr/core/src/test/org/apache/solr/request/SimpleFacetsTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_5x/solr/core/src/test/org/apache/solr/request/SimpleFacetsTest.java?rev=1645384&r1=1645383&r2=1645384&view=diff
==============================================================================
--- lucene/dev/branches/branch_5x/solr/core/src/test/org/apache/solr/request/SimpleFacetsTest.java (original)
+++ lucene/dev/branches/branch_5x/solr/core/src/test/org/apache/solr/request/SimpleFacetsTest.java Sun Dec 14 04:59:00 2014
@@ -17,7 +17,12 @@
package org.apache.solr.request;
-import org.noggit.ObjectBuilder;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.params.ModifiableSolrParams;
@@ -25,10 +30,7 @@ import org.apache.solr.schema.SchemaFiel
import org.apache.solr.util.TimeZoneUtils;
import org.junit.BeforeClass;
import org.junit.Test;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Map;
+import org.noggit.ObjectBuilder;
public class SimpleFacetsTest extends SolrTestCaseJ4 {
@@ -53,6 +55,20 @@ public class SimpleFacetsTest extends So
// committing randomly gives different looking segments each time
static void add_doc(String... fieldsAndValues) {
do {
+ //do our own copy-field:
+ List<String> fieldsAndValuesList = new ArrayList<>(Arrays.asList(fieldsAndValues));
+ int idx = fieldsAndValuesList.indexOf("a_tdt");
+ if (idx >= 0) {
+ fieldsAndValuesList.add("a_drf");
+ fieldsAndValuesList.add(fieldsAndValuesList.get(idx + 1));//copy
+ }
+ idx = fieldsAndValuesList.indexOf("bday");
+ if (idx >= 0) {
+ fieldsAndValuesList.add("bday_drf");
+ fieldsAndValuesList.add(fieldsAndValuesList.get(idx + 1));//copy
+ }
+ fieldsAndValues = fieldsAndValuesList.toArray(new String[fieldsAndValuesList.size()]);
+
pendingDocs.add(fieldsAndValues);
} while (random().nextInt(100) <= random_dupe_percent);
@@ -690,6 +706,7 @@ public class SimpleFacetsTest extends So
final String ooo = "00:00:00.000Z";
final String xxx = "15:15:15.155Z";
+ //note: add_doc duplicates bday to bday_drf and a_tdt to a_drf (date range field)
add_doc(i, "201", f, "1976-07-04T12:08:56.235Z", ff, "1900-01-01T"+ooo);
add_doc(i, "202", f, "1976-07-05T00:00:00.000Z", ff, "1976-07-01T"+ooo);
add_doc(i, "203", f, "1976-07-15T00:07:67.890Z", ff, "1976-07-04T"+ooo);
@@ -716,6 +733,11 @@ public class SimpleFacetsTest extends So
helpTestDateFacets("bday", true);
}
+ @Test
+ public void testDateRangeFieldFacets() {
+ helpTestDateFacets("bday_drf", true);
+ }
+
private void helpTestDateFacets(final String fieldName,
final boolean rangeMode) {
final String p = rangeMode ? "facet.range" : "facet.date";
@@ -913,8 +935,13 @@ public class SimpleFacetsTest extends So
helpTestDateFacetsWithIncludeOption("a_tdt", true);
}
- /** similar to helpTestDateFacets, but for differnet fields with test data
- exactly on on boundary marks */
+ @Test
+ public void testDateRangeFieldDateRangeFacetsWithIncludeOption() {
+ helpTestDateFacetsWithIncludeOption("a_drf", true);
+ }
+
+ /** Similar to helpTestDateFacets, but for different fields with test data
+ exactly on boundary marks */
private void helpTestDateFacetsWithIncludeOption(final String fieldName,
final boolean rangeMode) {
final String p = rangeMode ? "facet.range" : "facet.date";
Modified: lucene/dev/branches/branch_5x/solr/core/src/test/org/apache/solr/schema/DateRangeFieldTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_5x/solr/core/src/test/org/apache/solr/schema/DateRangeFieldTest.java?rev=1645384&r1=1645383&r2=1645384&view=diff
==============================================================================
--- lucene/dev/branches/branch_5x/solr/core/src/test/org/apache/solr/schema/DateRangeFieldTest.java (original)
+++ lucene/dev/branches/branch_5x/solr/core/src/test/org/apache/solr/schema/DateRangeFieldTest.java Sun Dec 14 04:59:00 2014
@@ -3,7 +3,7 @@ package org.apache.solr.schema;
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
+ * this work for additional information regarding copyright ownership.NRP
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
@@ -33,19 +33,24 @@ public class DateRangeFieldTest extends
assertU(adoc("id", "0", "dateRange", "[* TO *]"));
assertU(adoc("id", "1", "dateRange", "2014-05-21T12:00:00.000Z"));
assertU(adoc("id", "2", "dateRange", "[2000 TO 2014-05-21]"));
+ assertU(adoc("id", "3", "dateRange", "2020-05-21T12:00:00.000Z/DAY"));//DateMath syntax
assertU(commit());
- //ensure stored value is the same (not toString of Shape)
- assertQ(req("q", "id:1", "fl", "dateRange"), "//result/doc/arr[@name='dateRange']/str[.='2014-05-21T12:00:00.000Z']");
+ //ensure stored value resolves datemath
+ assertQ(req("q", "id:1", "fl", "dateRange"), "//result/doc/arr[@name='dateRange']/str[.='2014-05-21T12:00:00Z']");//no 000 ms
+ assertQ(req("q", "id:2", "fl", "dateRange"), "//result/doc/arr[@name='dateRange']/str[.='[2000 TO 2014-05-21]']");//a range; same
+ assertQ(req("q", "id:3", "fl", "dateRange"), "//result/doc/arr[@name='dateRange']/str[.='2020-05-21T00:00:00Z']");//resolve datemath
String[] commonParams = {"q", "{!field f=dateRange op=$op v=$qq}", "sort", "id asc"};
- assertQ(req(commonParams, "qq", "[* TO *]"), xpathMatches(0, 1, 2));
+ assertQ(req(commonParams, "qq", "[* TO *]"), xpathMatches(0, 1, 2, 3));
assertQ(req(commonParams, "qq", "2012"), xpathMatches(0, 2));
assertQ(req(commonParams, "qq", "2013", "op", "Contains"), xpathMatches(0, 2));
assertQ(req(commonParams, "qq", "2014", "op", "Contains"), xpathMatches(0));
assertQ(req(commonParams, "qq", "[1999 TO 2001]", "op", "IsWithin"), xpathMatches());
assertQ(req(commonParams, "qq", "2014-05", "op", "IsWithin"), xpathMatches(1));
+ assertQ(req("q", "dateRange:[1998 TO 2000}"), xpathMatches(0));//exclusive end, so we barely miss one doc
+
//show without local-params
assertQ(req("q", "dateRange:\"2014-05-21T12:00:00.000Z\""), xpathMatches(0, 1, 2));
assertQ(req("q", "dateRange:[1999 TO 2001]"), xpathMatches(0, 2));