You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by er...@apache.org on 2014/07/24 23:43:19 UTC

svn commit: r1613308 - in /lucene/dev/trunk/solr: CHANGES.txt core/src/java/org/apache/solr/request/IntervalFacets.java core/src/java/org/apache/solr/request/SimpleFacets.java core/src/test/org/apache/solr/request/TestIntervalFaceting.java

Author: erick
Date: Thu Jul 24 21:43:18 2014
New Revision: 1613308

URL: http://svn.apache.org/r1613308
Log:
SOLR-6267: Let user override Interval Faceting key with LocalParams. Thanks Tomas

Modified:
    lucene/dev/trunk/solr/CHANGES.txt
    lucene/dev/trunk/solr/core/src/java/org/apache/solr/request/IntervalFacets.java
    lucene/dev/trunk/solr/core/src/java/org/apache/solr/request/SimpleFacets.java
    lucene/dev/trunk/solr/core/src/test/org/apache/solr/request/TestIntervalFaceting.java

Modified: lucene/dev/trunk/solr/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/CHANGES.txt?rev=1613308&r1=1613307&r2=1613308&view=diff
==============================================================================
--- lucene/dev/trunk/solr/CHANGES.txt (original)
+++ lucene/dev/trunk/solr/CHANGES.txt Thu Jul 24 21:43:18 2014
@@ -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
 ----------------------

Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/request/IntervalFacets.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/request/IntervalFacets.java?rev=1613308&r1=1613307&r2=1613308&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/request/IntervalFacets.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/request/IntervalFacets.java Thu Jul 24 21:43:18 2014
@@ -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.SyntaxErro
  * 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.SyntaxErro
  * 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 I
   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 I
      */
     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) == '[') {

Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/request/SimpleFacets.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/request/SimpleFacets.java?rev=1613308&r1=1613307&r2=1613308&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/request/SimpleFacets.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/request/SimpleFacets.java Thu Jul 24 21:43:18 2014
@@ -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.BoundedTreeS
 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());
       }

Modified: lucene/dev/trunk/solr/core/src/test/org/apache/solr/request/TestIntervalFaceting.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/request/TestIntervalFaceting.java?rev=1613308&r1=1613307&r2=1613308&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/request/TestIntervalFaceting.java (original)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/request/TestIntervalFaceting.java Thu Jul 24 21:43:18 2014
@@ -389,6 +389,24 @@ public class TestIntervalFaceting extend
     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 extend
   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 extend
   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 extend
 
   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 extend
     }
 
   }
+  
+  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 extend
     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");
 
   }