mirror of https://github.com/apache/lucene.git
SOLR-6103: DateRangeField
git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1600557 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
1e24c0218f
commit
eee1f14787
|
@ -67,6 +67,8 @@ 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)
|
||||
|
||||
Other Changes
|
||||
----------------------
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
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.
|
||||
* 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
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import com.spatial4j.core.shape.Shape;
|
||||
import org.apache.lucene.index.StorableField;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.spatial.NumberRangePrefixTreeStrategy;
|
||||
import org.apache.lucene.spatial.prefix.tree.DateRangePrefixTree;
|
||||
import org.apache.lucene.spatial.query.SpatialArgs;
|
||||
import org.apache.lucene.spatial.query.SpatialOperation;
|
||||
import org.apache.solr.common.SolrException;
|
||||
import org.apache.solr.common.params.SolrParams;
|
||||
import org.apache.solr.search.QParser;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @see NumberRangePrefixTreeStrategy
|
||||
* @see DateRangePrefixTree
|
||||
*/
|
||||
public class DateRangeField extends AbstractSpatialPrefixTreeFieldType<NumberRangePrefixTreeStrategy> {
|
||||
|
||||
private static final String OP_PARAM = "op";//local-param to resolve SpatialOperation
|
||||
|
||||
private final DateRangePrefixTree tree = DateRangePrefixTree.INSTANCE;
|
||||
|
||||
@Override
|
||||
protected void init(IndexSchema schema, Map<String, String> args) {
|
||||
super.init(schema, addDegrees(args));
|
||||
}
|
||||
|
||||
private Map<String, String> addDegrees(Map<String, String> args) {
|
||||
args.put("units", "degrees");//HACK!
|
||||
return args;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NumberRangePrefixTreeStrategy newPrefixTreeStrategy(String fieldName) {
|
||||
return new NumberRangePrefixTreeStrategy(tree, fieldName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StorableField> createFields(SchemaField field, Object val, float boost) {
|
||||
if (val instanceof Date || val instanceof Calendar)//From URP
|
||||
val = tree.toShape(val);
|
||||
return super.createFields(field, val, boost);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Shape 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);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String shapeToString(Shape shape) {
|
||||
return shape.toString();//generally round-trips for DateRangePrefixTree
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SpatialArgs parseSpatialArgs(QParser parser, String externalVal) {
|
||||
//We avoid SpatialArgsParser entirely because it isn't very Solr-friendly
|
||||
final Shape shape = parseShape(externalVal);
|
||||
final SolrParams localParams = parser.getLocalParams();
|
||||
SpatialOperation op = SpatialOperation.Intersects;
|
||||
if (localParams != null) {
|
||||
String opStr = localParams.get(OP_PARAM);
|
||||
if (opStr != null)
|
||||
op = SpatialOperation.get(opStr);
|
||||
}
|
||||
return new SpatialArgs(op, shape);
|
||||
}
|
||||
|
||||
@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(parseShape(part1), parseShape(part2));
|
||||
SpatialArgs spatialArgs = new SpatialArgs(SpatialOperation.Intersects, shape);
|
||||
return getQueryFromSpatialArgs(parser, field, spatialArgs);
|
||||
}
|
||||
}
|
|
@ -84,6 +84,7 @@
|
|||
<fieldtype name="date" class="solr.TrieDateField" precisionStep="0"/>
|
||||
<fieldtype name="tdate" class="solr.TrieDateField" precisionStep="6"/>
|
||||
|
||||
<fieldtype name="dateRange" class="solr.DateRangeField" />
|
||||
|
||||
<!-- solr.TextField allows the specification of custom
|
||||
text analyzers specified as a tokenizer and a list
|
||||
|
@ -498,6 +499,7 @@
|
|||
|
||||
<field name="nullfirst" type="string" indexed="true" stored="true" sortMissingFirst="true" multiValued="false"/>
|
||||
|
||||
<field name="dateRange" type="dateRange" multiValued="false" />
|
||||
|
||||
<field name="cat" type="string" indexed="true" stored="true" multiValued="true"/>
|
||||
<field name="price" type="float" indexed="true" stored="true" multiValued="false"/>
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
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.
|
||||
* 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
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import org.apache.solr.SolrTestCaseJ4;
|
||||
import org.junit.BeforeClass;
|
||||
|
||||
public class DateRangeFieldTest extends SolrTestCaseJ4 {
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
initCore("solrconfig.xml", "schema.xml");
|
||||
}
|
||||
|
||||
public void test() {
|
||||
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(commit());
|
||||
|
||||
//ensure stored value is the same (not toString of Shape)
|
||||
assertQ(req("q", "id:1", "fl", "dateRange"), "//result/doc/str[.='2014-05-21T12:00:00.000Z']");
|
||||
|
||||
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", "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));
|
||||
|
||||
//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));
|
||||
}
|
||||
|
||||
private String[] xpathMatches(int... docIds) {
|
||||
String[] tests = new String[docIds != null ? docIds.length + 1 : 1];
|
||||
tests[0] = "*[count(//doc)=" + (tests.length-1) + "]";
|
||||
if (docIds != null && docIds.length > 0) {
|
||||
int i = 1;
|
||||
for (int docId : docIds) {
|
||||
tests[i++] = "//result/doc/int[@name='id'][.='" + docId + "']";
|
||||
}
|
||||
}
|
||||
return tests;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue