mirror of https://github.com/apache/lucene.git
SOLR-6267: Let user override Interval Faceting key with LocalParams. Thanks Tomas
git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1613308 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
0bfaf5cdfc
commit
0b11b8ab6b
|
@ -158,6 +158,9 @@ New Features
|
|||
* SOLR-6216: Better faceting for multiple intervals on DV fields (Tomas Fernandez-Lobbe
|
||||
via Erick Erickson)
|
||||
|
||||
* SOLR-6267: Let user override Interval Faceting key with LocalParams (Tomas Fernandez_Lobbe
|
||||
via Erick Erickson)
|
||||
|
||||
|
||||
Bug Fixes
|
||||
----------------------
|
||||
|
|
|
@ -22,12 +22,15 @@ import org.apache.lucene.util.Bits;
|
|||
import org.apache.lucene.util.BytesRef;
|
||||
import org.apache.lucene.util.NumericUtils;
|
||||
import org.apache.solr.common.SolrException;
|
||||
import org.apache.solr.common.params.CommonParams;
|
||||
import org.apache.solr.common.params.SolrParams;
|
||||
import org.apache.solr.request.IntervalFacets.FacetInterval;
|
||||
import org.apache.solr.schema.FieldType;
|
||||
import org.apache.solr.schema.SchemaField;
|
||||
import org.apache.solr.schema.TrieDateField;
|
||||
import org.apache.solr.search.DocIterator;
|
||||
import org.apache.solr.search.DocSet;
|
||||
import org.apache.solr.search.QueryParsing;
|
||||
import org.apache.solr.search.SolrIndexSearcher;
|
||||
import org.apache.solr.search.SyntaxError;
|
||||
|
||||
|
@ -60,7 +63,7 @@ import org.apache.solr.search.SyntaxError;
|
|||
* be faster in cases where there are a larger number of intervals per field.
|
||||
* <p/>
|
||||
* To use this class, create an instance using
|
||||
* {@link #IntervalFacets(SchemaField, SolrIndexSearcher, DocSet, String[])}
|
||||
* {@link #IntervalFacets(SchemaField, SolrIndexSearcher, DocSet, String[], SolrParams)}
|
||||
* and then iterate the {@link FacetInterval} using {@link #iterator()}
|
||||
* <p/>
|
||||
* Intervals Format</br>
|
||||
|
@ -82,11 +85,14 @@ import org.apache.solr.search.SyntaxError;
|
|||
* comparator can't be changed.
|
||||
* Commas, brackets and square brackets can be escaped by using '\' in front of them.
|
||||
* Whitespaces before and after the values will be omitted. Start limit can't be grater
|
||||
* than the end limit. Equal limits are allowed.
|
||||
* than the end limit. Equal limits are allowed.<p>
|
||||
* As with facet.query, the key used to display the result can be set by using local params
|
||||
* syntax, for example:<p>
|
||||
* <code>{!key='First Half'}[0,5) </code>
|
||||
* <p/>
|
||||
* To use this class:
|
||||
* <pre>
|
||||
* IntervalFacets intervalFacets = new IntervalFacets(schemaField, searcher, docs, intervalStrs);
|
||||
* IntervalFacets intervalFacets = new IntervalFacets(schemaField, searcher, docs, intervalStrs, params);
|
||||
* for (FacetInterval interval : intervalFacets) {
|
||||
* results.add(interval.getKey(), interval.getCount());
|
||||
* }
|
||||
|
@ -98,19 +104,19 @@ public class IntervalFacets implements Iterable<FacetInterval> {
|
|||
private final DocSet docs;
|
||||
private final FacetInterval[] intervals;
|
||||
|
||||
public IntervalFacets(SchemaField schemaField, SolrIndexSearcher searcher, DocSet docs, String[] intervals) throws SyntaxError, IOException {
|
||||
public IntervalFacets(SchemaField schemaField, SolrIndexSearcher searcher, DocSet docs, String[] intervals, SolrParams params) throws SyntaxError, IOException {
|
||||
this.schemaField = schemaField;
|
||||
this.searcher = searcher;
|
||||
this.docs = docs;
|
||||
this.intervals = getSortedIntervals(intervals);
|
||||
this.intervals = getSortedIntervals(intervals, params);
|
||||
doCount();
|
||||
}
|
||||
|
||||
private FacetInterval[] getSortedIntervals(String[] intervals) throws SyntaxError {
|
||||
private FacetInterval[] getSortedIntervals(String[] intervals, SolrParams params) throws SyntaxError {
|
||||
FacetInterval[] sortedIntervals = new FacetInterval[intervals.length];
|
||||
int idx = 0;
|
||||
for (String intervalStr : intervals) {
|
||||
sortedIntervals[idx++] = new FacetInterval(schemaField, intervalStr);
|
||||
sortedIntervals[idx++] = new FacetInterval(schemaField, intervalStr, params);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -400,11 +406,31 @@ public class IntervalFacets implements Iterable<FacetInterval> {
|
|||
*/
|
||||
private int count;
|
||||
|
||||
FacetInterval(SchemaField schemaField, String intervalStr) throws SyntaxError {
|
||||
FacetInterval(SchemaField schemaField, String intervalStr, SolrParams params) throws SyntaxError {
|
||||
if (intervalStr == null) throw new SyntaxError("empty facet interval");
|
||||
intervalStr = intervalStr.trim();
|
||||
if (intervalStr.length() == 0) throw new SyntaxError("empty facet interval");
|
||||
key = intervalStr;
|
||||
|
||||
try {
|
||||
SolrParams localParams = QueryParsing.getLocalParams(intervalStr, params);
|
||||
if (localParams != null ) {
|
||||
int localParamEndIdx = 2; // omit index of {!
|
||||
while (true) {
|
||||
localParamEndIdx = intervalStr.indexOf(QueryParsing.LOCALPARAM_END, localParamEndIdx);
|
||||
// Local param could be escaping '}'
|
||||
if (intervalStr.charAt(localParamEndIdx - 1) != '\\') {
|
||||
break;
|
||||
}
|
||||
localParamEndIdx++;
|
||||
}
|
||||
intervalStr = intervalStr.substring(localParamEndIdx + 1);
|
||||
key = localParams.get(CommonParams.OUTPUT_KEY, intervalStr);
|
||||
} else {
|
||||
key = intervalStr;
|
||||
}
|
||||
} catch (SyntaxError e) {
|
||||
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
|
||||
}
|
||||
if (intervalStr.charAt(0) == '(') {
|
||||
startOpen = true;
|
||||
} else if (intervalStr.charAt(0) == '[') {
|
||||
|
|
|
@ -17,6 +17,26 @@
|
|||
|
||||
package org.apache.solr.request;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.EnumSet;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.FutureTask;
|
||||
import java.util.concurrent.RunnableFuture;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.lucene.index.AtomicReader;
|
||||
import org.apache.lucene.index.AtomicReaderContext;
|
||||
import org.apache.lucene.index.DocsEnum;
|
||||
|
@ -74,26 +94,6 @@ import org.apache.solr.util.BoundedTreeSet;
|
|||
import org.apache.solr.util.DateMathParser;
|
||||
import org.apache.solr.util.DefaultSolrThreadFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.EnumSet;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.FutureTask;
|
||||
import java.util.concurrent.RunnableFuture;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* A class that generates simple Facet information for a request.
|
||||
*
|
||||
|
@ -1433,7 +1433,7 @@ public class SimpleFacets {
|
|||
|
||||
SimpleOrderedMap<Integer> fieldResults = new SimpleOrderedMap<Integer>();
|
||||
res.add(field, fieldResults);
|
||||
IntervalFacets intervalFacets = new IntervalFacets(schemaField, searcher, docs, intervalStrs);
|
||||
IntervalFacets intervalFacets = new IntervalFacets(schemaField, searcher, docs, intervalStrs, params);
|
||||
for (FacetInterval interval : intervalFacets) {
|
||||
fieldResults.add(interval.getKey(), interval.getCount());
|
||||
}
|
||||
|
|
|
@ -389,6 +389,24 @@ public class TestIntervalFaceting extends SolrTestCaseJ4 {
|
|||
assertBadInterval("test_s_dv", "(B,A)", "Start is higher than end in interval for key");
|
||||
assertBadInterval("test_s_dv", "(a,B)", "Start is higher than end in interval for key");
|
||||
|
||||
assertIntervalKey("test_s_dv", "[A,B]", "[A,B]");
|
||||
assertIntervalKey("test_s_dv", "(A,*]", "(A,*]");
|
||||
assertIntervalKey("test_s_dv", "{!}(A,*]", "(A,*]");
|
||||
assertIntervalKey("test_s_dv", "{!key=foo}(A,*]", "foo");
|
||||
assertIntervalKey("test_s_dv", "{!key='foo'}(A,*]", "foo");
|
||||
assertIntervalKey("test_s_dv", "{!key='foo bar'}(A,*]", "foo bar");
|
||||
assertIntervalKey("test_s_dv", "{!key='foo' bar}(A,*]", "foo");
|
||||
assertIntervalKey("test_s_dv", "{!key=$i}(A,*]", "foo", "i", "foo");
|
||||
assertIntervalKey("test_s_dv", "{!key=$i}(A,*]", "foo bar", "i", "foo bar");
|
||||
assertIntervalKey("test_s_dv", "{!key=$i}(A,*]", "'foo'", "i", "'foo'");
|
||||
assertIntervalKey("test_s_dv", "{!key=$i}(A,*]", "\"foo\"", "i", "\"foo\"");
|
||||
assertIntervalKey("test_s_dv", "{!key='[A,B]'}(A,B)", "[A,B]");
|
||||
assertIntervalKey("test_s_dv", "{!key='\\{\\{\\{'}(A,B)", "{{{");
|
||||
assertIntervalKey("test_s_dv", "{!key='\\{A,B\\}'}(A,B)", "{A,B}");
|
||||
assertIntervalKey("test_s_dv", "{!key='\"A,B\"'}(A,B)", "\"A,B\"");
|
||||
assertIntervalKey("test_s_dv", "{!key='A..B'}(A,B)", "A..B");
|
||||
assertIntervalKey("test_s_dv", "{!key='A TO B'}(A,B)", "A TO B");
|
||||
|
||||
|
||||
assertU(adoc("id", "1", "test_s_dv", "dog", "test_l_dv", "1"));
|
||||
assertU(adoc("id", "2", "test_s_dv", "cat", "test_l_dv", "2"));
|
||||
|
@ -496,7 +514,7 @@ public class TestIntervalFaceting extends SolrTestCaseJ4 {
|
|||
private void assertStringInterval(String fieldName, String intervalStr,
|
||||
String expectedStart, String expectedEnd) throws SyntaxError {
|
||||
SchemaField f = h.getCore().getLatestSchema().getField(fieldName);
|
||||
FacetInterval interval = new FacetInterval(f, intervalStr);
|
||||
FacetInterval interval = new FacetInterval(f, intervalStr, new ModifiableSolrParams());
|
||||
|
||||
assertEquals("Expected start " + expectedStart + " but found " + f.getType().toObject(f, interval.start),
|
||||
interval.start, new BytesRef(f.getType().toInternal(expectedStart)));
|
||||
|
@ -508,7 +526,7 @@ public class TestIntervalFaceting extends SolrTestCaseJ4 {
|
|||
private void assertBadInterval(String fieldName, String intervalStr, String errorMsg) {
|
||||
SchemaField f = h.getCore().getLatestSchema().getField(fieldName);
|
||||
try {
|
||||
new FacetInterval(f, intervalStr);
|
||||
new FacetInterval(f, intervalStr, new ModifiableSolrParams());
|
||||
fail("Expecting SyntaxError for interval String: " + intervalStr);
|
||||
} catch (SyntaxError e) {
|
||||
assertTrue("Unexpected error message for interval String: " + intervalStr + ": " +
|
||||
|
@ -518,7 +536,7 @@ public class TestIntervalFaceting extends SolrTestCaseJ4 {
|
|||
|
||||
private void assertInterval(String fieldName, String intervalStr, long[] included, long[] lowerThanStart, long[] graterThanEnd) throws SyntaxError {
|
||||
SchemaField f = h.getCore().getLatestSchema().getField(fieldName);
|
||||
FacetInterval interval = new FacetInterval(f, intervalStr);
|
||||
FacetInterval interval = new FacetInterval(f, intervalStr, new ModifiableSolrParams());
|
||||
for (long l : included) {
|
||||
assertEquals("Value " + l + " should be INCLUDED for interval" + interval,
|
||||
IntervalCompareResult.INCLUDED, interval.includes(l));
|
||||
|
@ -533,6 +551,61 @@ public class TestIntervalFaceting extends SolrTestCaseJ4 {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
private void assertIntervalKey(String fieldName, String intervalStr,
|
||||
String expectedKey, String...params) throws SyntaxError {
|
||||
assert (params.length&1)==0:"Params must have an even number of elements";
|
||||
SchemaField f = h.getCore().getLatestSchema().getField(fieldName);
|
||||
ModifiableSolrParams solrParams = new ModifiableSolrParams();
|
||||
for (int i = 0; i < params.length - 1;) {
|
||||
solrParams.set(params[i], params[i+1]);
|
||||
i+=2;
|
||||
}
|
||||
FacetInterval interval = new FacetInterval(f, intervalStr, solrParams);
|
||||
|
||||
assertEquals("Expected key " + expectedKey + " but found " + interval.getKey(),
|
||||
expectedKey, interval.getKey());
|
||||
}
|
||||
|
||||
public void testChangeKey() {
|
||||
assertU(adoc("id", "1", "test_s_dv", "dog"));
|
||||
assertU(adoc("id", "2", "test_s_dv", "cat"));
|
||||
assertU(adoc("id", "3", "test_s_dv", "bird"));
|
||||
assertU(adoc("id", "4", "test_s_dv", "cat"));
|
||||
assertU(adoc("id", "5", "test_s_dv", "turtle"));
|
||||
assertU(adoc("id", "6", "test_s_dv", "dog"));
|
||||
assertU(adoc("id", "7", "test_s_dv", "dog"));
|
||||
assertU(adoc("id", "8", "test_s_dv", "dog"));
|
||||
assertU(adoc("id", "9", "test_s_dv", "cat"));
|
||||
assertU(adoc("id", "10"));
|
||||
assertU(commit());
|
||||
|
||||
assertQ(req("q", "*:*", "facet", "true", "facet.interval", "test_s_dv",
|
||||
"f.test_s_dv.facet.interval.set", "{!key=foo}[bird,bird]",
|
||||
"f.test_s_dv.facet.interval.set", "{!key='bar'}(bird,dog)"),
|
||||
"//lst[@name='facet_intervals']/lst[@name='test_s_dv']/int[@name='foo'][.=1]",
|
||||
"//lst[@name='facet_intervals']/lst[@name='test_s_dv']/int[@name='bar'][.=3]");
|
||||
|
||||
assertQ(req("q", "*:*", "facet", "true", "facet.interval", "test_s_dv",
|
||||
"f.test_s_dv.facet.interval.set", "{!key=Birds}[bird,bird]",
|
||||
"f.test_s_dv.facet.interval.set", "{!key='foo bar'}(bird,dog)"),
|
||||
"//lst[@name='facet_intervals']/lst[@name='test_s_dv']/int[@name='Birds'][.=1]",
|
||||
"//lst[@name='facet_intervals']/lst[@name='test_s_dv']/int[@name='foo bar'][.=3]");
|
||||
|
||||
assertQ(req("q", "*:*", "facet", "true", "facet.interval", "test_s_dv",
|
||||
"f.test_s_dv.facet.interval.set", "{!key=$p}[bird,bird]",
|
||||
"p", "foo bar"),
|
||||
"//lst[@name='facet_intervals']/lst[@name='test_s_dv']/int[@name='foo bar'][.=1]");
|
||||
|
||||
assertQ(req("q", "*:*", "facet", "true", "facet.interval", "test_s_dv",
|
||||
"f.test_s_dv.facet.interval.set", "{!key='[bird,\\}'}[bird,*]",
|
||||
"f.test_s_dv.facet.interval.set", "{!key='\\{bird,dog\\}'}(bird,dog)",
|
||||
"f.test_s_dv.facet.interval.set", "{!key='foo'}(bird,dog})"),
|
||||
"//lst[@name='facet_intervals']/lst[@name='test_s_dv']/int[@name='[bird,}'][.=9]",
|
||||
"//lst[@name='facet_intervals']/lst[@name='test_s_dv']/int[@name='{bird,dog}'][.=3]",
|
||||
"//lst[@name='facet_intervals']/lst[@name='test_s_dv']/int[@name='foo'][.=7]");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLongFields() {
|
||||
|
@ -755,7 +828,7 @@ public class TestIntervalFaceting extends SolrTestCaseJ4 {
|
|||
assertIntervalQuery(field, "[0,2)", "2");
|
||||
assertIntervalQuery(field, "(0,2]", "2");
|
||||
assertIntervalQuery(field, "[*,5]", "6");
|
||||
assertIntervalQuery(field, "[*,3)", "3", "[2,5)", "3", "[6,8)", "2", "[3,*]", "7", "[10,10]", "1");
|
||||
assertIntervalQuery(field, "[*,3)", "3", "[2,5)", "3", "[6,8)", "2", "[3,*]", "7", "[10,10]", "1", "[10,10]", "1", "[10,10]", "1");
|
||||
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue