You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ho...@apache.org on 2010/05/03 20:21:25 UTC

svn commit: r940556 - in /lucene/dev/trunk/solr: CHANGES.txt src/common/org/apache/solr/common/params/FacetParams.java src/java/org/apache/solr/request/SimpleFacets.java src/test/org/apache/solr/request/SimpleFacetsTest.java

Author: hossman
Date: Mon May  3 18:21:25 2010
New Revision: 940556

URL: http://svn.apache.org/viewvc?rev=940556&view=rev
Log:
SOLR-397: creation of a facet.date.include param for controlling what range endpoints are inclusive when date faceting

Modified:
    lucene/dev/trunk/solr/CHANGES.txt
    lucene/dev/trunk/solr/src/common/org/apache/solr/common/params/FacetParams.java
    lucene/dev/trunk/solr/src/java/org/apache/solr/request/SimpleFacets.java
    lucene/dev/trunk/solr/src/test/org/apache/solr/request/SimpleFacetsTest.java

Modified: lucene/dev/trunk/solr/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/CHANGES.txt?rev=940556&r1=940555&r2=940556&view=diff
==============================================================================
--- lucene/dev/trunk/solr/CHANGES.txt (original)
+++ lucene/dev/trunk/solr/CHANGES.txt Mon May  3 18:21:25 2010
@@ -144,6 +144,14 @@ New Features
   supports "percentages" which get evaluated  relative the current size of 
   the cache when warming happens. 
   (Tomas Fernandez Lobbe and hossman)
+
+* SOLR-397: Date Faceting now supports a "facet.date.include" param
+  for specifying when the upper & lower end points of computed date
+  ranges should be included in the range.  Legal values are: "all",
+  "lower", "upper", "edge", and "outer".  For backwards compatibility
+  the default value is the set: [lower,upper,edge], so that al ranges
+  between start and ed are inclusive of their endpoints, but the
+  "before" and "after" ranges are not.
    
 Optimizations
 ----------------------

Modified: lucene/dev/trunk/solr/src/common/org/apache/solr/common/params/FacetParams.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/src/common/org/apache/solr/common/params/FacetParams.java?rev=940556&r1=940555&r2=940556&view=diff
==============================================================================
--- lucene/dev/trunk/solr/src/common/org/apache/solr/common/params/FacetParams.java (original)
+++ lucene/dev/trunk/solr/src/common/org/apache/solr/common/params/FacetParams.java Mon May  3 18:21:25 2010
@@ -19,6 +19,7 @@ package org.apache.solr.common.params;
 
 import org.apache.solr.common.SolrException;
 
+import java.util.EnumSet;
 
 /**
  * Facet parameters
@@ -165,6 +166,7 @@ public interface FacetParams {
    * <li>none = no additional info requested</li>
    * </ul>
    * @see #FACET_DATE_OTHER
+   * @see #FACET_DATE_INCLUDE
    */
   public enum FacetDateOther {
     BEFORE, AFTER, BETWEEN, ALL, NONE;
@@ -180,6 +182,73 @@ public interface FacetParams {
     }
   }
   
+  /**
+   * <p>
+   * Multivalued string indicating what rules should be applied to determine 
+   * when the the ranges generated for date faceting should be inclusive or 
+   * exclusive of their end points.
+   * </p>
+   * <p>
+   * The default value if none are specified is: [lower,upper,edge]
+   * </p>
+   * <p>
+   * Can be overriden on a per field basis.
+   * </p>
+   * @see FacetDateInclude
+   */
+  public static final String FACET_DATE_INCLUDE = FACET_DATE + ".include";
+
+  /**
+   * An enumeration of the legal values for FACET_DATE_INCLUDE...
+   * <ul>
+   * <li>lower = all gap based ranges include their lower bound</li>
+   * <li>upper = all gap based ranges include their upper bound</li>
+   * <li>edge = the first and last gap ranges include their edge bounds (ie: lower 
+   *     for the first one, upper for the last one) even if the corrisponding 
+   *     upper/lower option is not specified
+   * </li>
+   * <li>outer = the FacetDateOther.BEFORE and FacetDateOther.AFTER ranges 
+   *     should be inclusive of their bounds, even if the first or last ranges 
+   *     already include thouse boundaries.
+   * </li>
+   * <li>all = shorthand for lower, upper, edge, and outer</li>
+   * </ul>
+   * @see #FACET_DATE_INCLUDE
+   */
+  public enum FacetDateInclude {
+    ALL, LOWER, UPPER, EDGE, OUTER;
+    public String toString() { return super.toString().toLowerCase(); }
+    public static FacetDateInclude get(String label) {
+      try {
+        return valueOf(label.toUpperCase());
+      } catch (IllegalArgumentException e) {
+        throw new SolrException
+          (SolrException.ErrorCode.BAD_REQUEST,
+           label+" is not a valid type of for "+FACET_DATE_INCLUDE+" information",e);
+      }
+    }
+    /**
+     * Convinience method for parsing the param value according to the correct semantics.
+     */
+    public static EnumSet<FacetDateInclude> parseParam(final String[] param) {
+      // short circut for default behavior
+      if (null == param || 0 == param.length ) 
+        return EnumSet.of(LOWER, UPPER, EDGE);
+
+      // build up set containing whatever is specified
+      final EnumSet<FacetDateInclude> include = EnumSet.noneOf(FacetDateInclude.class);
+      for (final String o : param) {
+        include.add(FacetDateInclude.get(o));
+      }
+
+      // if set contains all, then we're back to short circuting
+      if (include.contains(FacetDateInclude.ALL)) 
+        return EnumSet.allOf(FacetDateInclude.class);
+
+      // use whatever we've got.
+      return include;
+    }
+  }
 
 }
 

Modified: lucene/dev/trunk/solr/src/java/org/apache/solr/request/SimpleFacets.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/src/java/org/apache/solr/request/SimpleFacets.java?rev=940556&r1=940555&r2=940556&view=diff
==============================================================================
--- lucene/dev/trunk/solr/src/java/org/apache/solr/request/SimpleFacets.java (original)
+++ lucene/dev/trunk/solr/src/java/org/apache/solr/request/SimpleFacets.java Mon May  3 18:21:25 2010
@@ -29,6 +29,7 @@ import org.apache.solr.common.params.Req
 import org.apache.solr.common.params.SolrParams;
 import org.apache.solr.common.params.CommonParams;
 import org.apache.solr.common.params.FacetParams.FacetDateOther;
+import org.apache.solr.common.params.FacetParams.FacetDateInclude;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.SimpleOrderedMap;
 import org.apache.solr.common.util.StrUtils;
@@ -636,8 +637,10 @@ public class SimpleFacets {
 
       int minCount = params.getFieldInt(f,FacetParams.FACET_MINCOUNT, 0);
 
+      final EnumSet<FacetDateInclude> include = FacetDateInclude.parseParam
+        (params.getFieldParams(f,FacetParams.FACET_DATE_INCLUDE));
+
       try {
-        
         Date low = start;
         while (low.before(end)) {
           dmp.setNow(low);
@@ -656,7 +659,14 @@ public class SimpleFacets {
               (SolrException.ErrorCode.BAD_REQUEST,
                "date facet infinite loop (is gap negative?)");
           }
-          int count = rangeCount(sf,low,high,true,true);
+          boolean includeLower = 
+            (include.contains(FacetDateInclude.LOWER) ||
+             (include.contains(FacetDateInclude.EDGE) && low.equals(start)));
+          boolean includeUpper = 
+            (include.contains(FacetDateInclude.UPPER) ||
+             (include.contains(FacetDateInclude.EDGE) && high.equals(end)));
+
+          int count = rangeCount(sf,low,high,includeLower,includeUpper);
           if (count >= minCount) {
             resInner.add(label, count);
           }
@@ -687,16 +697,30 @@ public class SimpleFacets {
           boolean all = others.contains(FacetDateOther.ALL);
         
           if (all || others.contains(FacetDateOther.BEFORE)) {
+            // include upper bound if "outer" or if first gap doesn't already include it
             resInner.add(FacetDateOther.BEFORE.toString(),
-                         rangeCount(sf,null,start,false,false));
+                         rangeCount(sf,null,start,
+                                    false,
+                                    (include.contains(FacetDateInclude.OUTER) ||
+                                     (! (include.contains(FacetDateInclude.LOWER) ||
+                                         include.contains(FacetDateInclude.EDGE))))));
           }
           if (all || others.contains(FacetDateOther.AFTER)) {
+            // include lower bound if "outer" or if last gap doesn't already include it
             resInner.add(FacetDateOther.AFTER.toString(),
-                         rangeCount(sf,end,null,false,false));
+                         rangeCount(sf,end,null,
+                                    (include.contains(FacetDateInclude.OUTER) ||
+                                     (! (include.contains(FacetDateInclude.UPPER) ||
+                                         include.contains(FacetDateInclude.EDGE)))),
+                                    false));
           }
           if (all || others.contains(FacetDateOther.BETWEEN)) {
             resInner.add(FacetDateOther.BETWEEN.toString(),
-                         rangeCount(sf,start,end,true,true));
+                         rangeCount(sf,start,end,
+                                    (include.contains(FacetDateInclude.LOWER) ||
+                                     include.contains(FacetDateInclude.EDGE)),
+                                    (include.contains(FacetDateInclude.UPPER) ||
+                                     include.contains(FacetDateInclude.EDGE))));
           }
         }
       }

Modified: lucene/dev/trunk/solr/src/test/org/apache/solr/request/SimpleFacetsTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/src/test/org/apache/solr/request/SimpleFacetsTest.java?rev=940556&r1=940555&r2=940556&view=diff
==============================================================================
--- lucene/dev/trunk/solr/src/test/org/apache/solr/request/SimpleFacetsTest.java (original)
+++ lucene/dev/trunk/solr/src/test/org/apache/solr/request/SimpleFacetsTest.java Mon May  3 18:21:25 2010
@@ -19,6 +19,7 @@ package org.apache.solr.request;
 
 import org.apache.solr.SolrTestCaseJ4;
 import org.junit.BeforeClass;
+import org.junit.After;
 import org.junit.Test;
 
 import java.util.ArrayList;
@@ -258,23 +259,26 @@ public class SimpleFacetsTest extends So
   }
 
   public static void indexDateFacets() {
+    final String i = "id";
     final String f = "bday";
-    final String pre = "//lst[@name='facet_dates']/lst[@name='"+f+"']";
-
-    add_doc("id", "201",  f, "1976-07-04T12:08:56.235Z");
-    add_doc("id", "202",  f, "1976-07-05T00:00:00.000Z");
-    add_doc("id", "203",  f, "1976-07-15T00:07:67.890Z");
-    add_doc("id", "204",  f, "1976-07-21T00:07:67.890Z");
-    add_doc("id", "205",  f, "1976-07-13T12:12:25.255Z");
-    add_doc("id", "206",  f, "1976-07-03T17:01:23.456Z");
-    add_doc("id", "207",  f, "1976-07-12T12:12:25.255Z");
-    add_doc("id", "208",  f, "1976-07-15T15:15:15.155Z");
-    add_doc("id", "209",  f, "1907-07-12T13:13:23.235Z");
-    add_doc("id", "2010", f, "1976-07-03T11:02:45.678Z");
-    add_doc("id", "2011", f, "1907-07-12T12:12:25.255Z");
-    add_doc("id", "2012", f, "2007-07-30T07:07:07.070Z");
-    add_doc("id", "2013", f, "1976-07-30T22:22:22.222Z");
-    add_doc("id", "2014", f, "1976-07-05T22:22:22.222Z");
+    final String ff = "a_tdt";
+    final String ooo = "00:00:00.000Z";
+    final String xxx = "15:15:15.155Z";
+
+    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);
+    add_doc(i, "204",  f, "1976-07-21T00:07:67.890Z", ff, "1976-07-05T"+ooo);
+    add_doc(i, "205",  f, "1976-07-13T12:12:25.255Z", ff, "1976-07-05T"+xxx);
+    add_doc(i, "206",  f, "1976-07-03T17:01:23.456Z", ff, "1976-07-07T"+ooo);
+    add_doc(i, "207",  f, "1976-07-12T12:12:25.255Z", ff, "1976-07-13T"+ooo);
+    add_doc(i, "208",  f, "1976-07-15T15:15:15.155Z", ff, "1976-07-13T"+xxx);
+    add_doc(i, "209",  f, "1907-07-12T13:13:23.235Z", ff, "1976-07-15T"+xxx);
+    add_doc(i, "2010", f, "1976-07-03T11:02:45.678Z", ff, "2000-01-01T"+ooo);
+    add_doc(i, "2011", f, "1907-07-12T12:12:25.255Z");
+    add_doc(i, "2012", f, "2007-07-30T07:07:07.070Z");
+    add_doc(i, "2013", f, "1976-07-30T22:22:22.222Z");
+    add_doc(i, "2014", f, "1976-07-05T22:22:22.222Z");
   }
 
   @Test
@@ -385,6 +389,42 @@ public class SimpleFacetsTest extends So
             ,pre+"/int[@name='between'][.='11']"
             );
 
+    assertQ("check before is not inclusive of upper bound by default",
+            req("q", "*:*"
+                ,"rows", "0"
+                ,"facet", "true"
+                ,"facet.date", f
+                ,"facet.date.start",  "1976-07-05T00:00:00.000Z"
+                ,"facet.date.end",    "1976-07-07T00:00:00.000Z"
+                ,"facet.date.gap",    "+1DAY"
+                ,"facet.date.other",  "all"
+                )
+            // 2 gaps + pre+post+inner = 5
+            ,"*[count("+pre+"/int)=5]"
+            ,pre+"/int[@name='1976-07-05T00:00:00Z'][.='2'  ]"
+            ,pre+"/int[@name='1976-07-06T00:00:00Z'][.='0'  ]"
+            
+            ,pre+"/int[@name='before' ][.='5']"
+            );
+    assertQ("check after is not inclusive of lower bound by default",
+            req("q", "*:*"
+                ,"rows", "0"
+                ,"facet", "true"
+                ,"facet.date", f
+                ,"facet.date.start",  "1976-07-03T00:00:00.000Z"
+                ,"facet.date.end",    "1976-07-05T00:00:00.000Z"
+                ,"facet.date.gap",    "+1DAY"
+                ,"facet.date.other",  "all"
+                )
+            // 2 gaps + pre+post+inner = 5
+            ,"*[count("+pre+"/int)=5]"
+            ,pre+"/int[@name='1976-07-03T00:00:00Z'][.='2'  ]"
+            ,pre+"/int[@name='1976-07-04T00:00:00Z'][.='2'  ]"
+            
+            ,pre+"/int[@name='after' ][.='8']"
+            );
+            
+
     assertQ("check hardend=false",
             req( "q", "*:*"
                 ,"rows", "0"
@@ -431,6 +471,303 @@ public class SimpleFacetsTest extends So
     
   }
 
+  /** similar to testDateFacets, but a differnet field with test data 
+      exactly on on boundary marks */
+  @Test
+  public void testDateFacetsWithIncludeOption() {
+    final String f = "a_tdt";
+    final String pre = "//lst[@name='facet_dates']/lst[@name='"+f+"']";
+
+    assertQ("checking counts for lower",
+            req( "q", "*:*"
+                ,"rows", "0"
+                ,"facet", "true"
+                ,"facet.date", f
+                ,"facet.date.start", "1976-07-01T00:00:00.000Z"
+                ,"facet.date.end",   "1976-07-16T00:00:00.000Z"
+                ,"facet.date.gap",   "+1DAY"
+                ,"facet.date.other", "all"
+                ,"facet.date.include", "lower"
+                )
+            // 15 days + pre+post+inner = 18
+            ,"*[count("+pre+"/int)=18]"
+            ,pre+"/int[@name='1976-07-01T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='1976-07-02T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-03T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-04T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='1976-07-05T00:00:00Z'][.='2'  ]"
+            ,pre+"/int[@name='1976-07-06T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-07T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='1976-07-08T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-09T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-10T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-11T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-12T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-13T00:00:00Z'][.='2'  ]"
+            ,pre+"/int[@name='1976-07-14T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-15T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='before' ][.='1']"
+            ,pre+"/int[@name='after'  ][.='1']"
+            ,pre+"/int[@name='between'][.='8']"
+            );
+
+    assertQ("checking counts for upper",
+            req( "q", "*:*"
+                ,"rows", "0"
+                ,"facet", "true"
+                ,"facet.date", f
+                ,"facet.date.start", "1976-07-01T00:00:00.000Z"
+                ,"facet.date.end",   "1976-07-16T00:00:00.000Z"
+                ,"facet.date.gap",   "+1DAY"
+                ,"facet.date.other", "all"
+                ,"facet.date.include", "upper"
+                )
+            // 15 days + pre+post+inner = 18
+            ,"*[count("+pre+"/int)=18]"
+            ,pre+"/int[@name='1976-07-01T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-02T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-03T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='1976-07-04T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='1976-07-05T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='1976-07-06T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='1976-07-07T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-08T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-09T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-10T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-11T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-12T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='1976-07-13T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='1976-07-14T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-15T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='before' ][.='2']"
+            ,pre+"/int[@name='after'  ][.='1']"
+            ,pre+"/int[@name='between'][.='7']"
+            );
+
+    assertQ("checking counts for lower & upper",
+            req( "q", "*:*"
+                ,"rows", "0"
+                ,"facet", "true"
+                ,"facet.date", f
+                ,"facet.date.start", "1976-07-01T00:00:00.000Z"
+                ,"facet.date.end",   "1976-07-16T00:00:00.000Z"
+                ,"facet.date.gap",   "+1DAY"
+                ,"facet.date.other", "all"
+                ,"facet.date.include", "lower"
+                ,"facet.date.include", "upper"
+                )
+            // 15 days + pre+post+inner = 18
+            ,"*[count("+pre+"/int)=18]"
+            ,pre+"/int[@name='1976-07-01T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='1976-07-02T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-03T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='1976-07-04T00:00:00Z'][.='2'  ]"
+            ,pre+"/int[@name='1976-07-05T00:00:00Z'][.='2'  ]"
+            ,pre+"/int[@name='1976-07-06T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='1976-07-07T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='1976-07-08T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-09T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-10T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-11T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-12T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='1976-07-13T00:00:00Z'][.='2'  ]"
+            ,pre+"/int[@name='1976-07-14T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-15T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='before' ][.='1']"
+            ,pre+"/int[@name='after'  ][.='1']"
+            ,pre+"/int[@name='between'][.='8']"
+            );
+
+    assertQ("checking counts for upper & edge",
+            req( "q", "*:*"
+                ,"rows", "0"
+                ,"facet", "true"
+                ,"facet.date", f
+                ,"facet.date.start", "1976-07-01T00:00:00.000Z"
+                ,"facet.date.end",   "1976-07-16T00:00:00.000Z"
+                ,"facet.date.gap",   "+1DAY"
+                ,"facet.date.other", "all"
+                ,"facet.date.include", "upper"
+                ,"facet.date.include", "edge"
+                )
+            // 15 days + pre+post+inner = 18
+            ,"*[count("+pre+"/int)=18]"
+            ,pre+"/int[@name='1976-07-01T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='1976-07-02T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-03T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='1976-07-04T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='1976-07-05T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='1976-07-06T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='1976-07-07T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-08T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-09T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-10T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-11T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-12T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='1976-07-13T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='1976-07-14T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-15T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='before' ][.='1']"
+            ,pre+"/int[@name='after'  ][.='1']"
+            ,pre+"/int[@name='between'][.='8']"
+            );
+
+    assertQ("checking counts for upper & outer",
+            req( "q", "*:*"
+                ,"rows", "0"
+                ,"facet", "true"
+                ,"facet.date", f
+                ,"facet.date.start", "1976-07-01T00:00:00.000Z"
+                ,"facet.date.end",   "1976-07-13T00:00:00.000Z" // smaller now
+                ,"facet.date.gap",   "+1DAY"
+                ,"facet.date.other", "all"
+                ,"facet.date.include", "upper"
+                ,"facet.date.include", "outer"
+                )
+            // 12 days + pre+post+inner = 15
+            ,"*[count("+pre+"/int)=15]"
+            ,pre+"/int[@name='1976-07-01T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-02T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-03T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='1976-07-04T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='1976-07-05T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='1976-07-06T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='1976-07-07T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-08T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-09T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-10T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-11T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-12T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='before' ][.='2']"
+            ,pre+"/int[@name='after'  ][.='4']"
+            ,pre+"/int[@name='between'][.='5']"
+            );
+
+    assertQ("checking counts for lower & edge",
+            req( "q", "*:*"
+                ,"rows", "0"
+                ,"facet", "true"
+                ,"facet.date", f
+                ,"facet.date.start", "1976-07-01T00:00:00.000Z"
+                ,"facet.date.end",   "1976-07-13T00:00:00.000Z" // smaller now
+                ,"facet.date.gap",   "+1DAY"
+                ,"facet.date.other", "all"
+                ,"facet.date.include", "lower"
+                ,"facet.date.include", "edge"
+                )
+            // 12 days + pre+post+inner = 15
+            ,"*[count("+pre+"/int)=15]"
+            ,pre+"/int[@name='1976-07-01T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='1976-07-02T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-03T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-04T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='1976-07-05T00:00:00Z'][.='2'  ]"
+            ,pre+"/int[@name='1976-07-06T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-07T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='1976-07-08T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-09T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-10T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-11T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-12T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='before' ][.='1']"
+            ,pre+"/int[@name='after'  ][.='3']"
+            ,pre+"/int[@name='between'][.='6']"
+            );
+
+    assertQ("checking counts for lower & outer",
+            req( "q", "*:*"
+                ,"rows", "0"
+                ,"facet", "true"
+                ,"facet.date", f
+                ,"facet.date.start", "1976-07-01T00:00:00.000Z"
+                ,"facet.date.end",   "1976-07-13T00:00:00.000Z" // smaller now
+                ,"facet.date.gap",   "+1DAY"
+                ,"facet.date.other", "all"
+                ,"facet.date.include", "lower"
+                ,"facet.date.include", "outer"
+                )
+            // 12 days + pre+post+inner = 15
+            ,"*[count("+pre+"/int)=15]"
+            ,pre+"/int[@name='1976-07-01T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='1976-07-02T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-03T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-04T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='1976-07-05T00:00:00Z'][.='2'  ]"
+            ,pre+"/int[@name='1976-07-06T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-07T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='1976-07-08T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-09T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-10T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-11T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-12T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='before' ][.='2']"
+            ,pre+"/int[@name='after'  ][.='4']"
+            ,pre+"/int[@name='between'][.='5']"
+            );
+
+    assertQ("checking counts for lower & edge & outer",
+            req( "q", "*:*"
+                ,"rows", "0"
+                ,"facet", "true"
+                ,"facet.date", f
+                ,"facet.date.start", "1976-07-01T00:00:00.000Z"
+                ,"facet.date.end",   "1976-07-13T00:00:00.000Z" // smaller now
+                ,"facet.date.gap",   "+1DAY"
+                ,"facet.date.other", "all"
+                ,"facet.date.include", "lower"
+                ,"facet.date.include", "edge"
+                ,"facet.date.include", "outer"
+                )
+            // 12 days + pre+post+inner = 15
+            ,"*[count("+pre+"/int)=15]"
+            ,pre+"/int[@name='1976-07-01T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='1976-07-02T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-03T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-04T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='1976-07-05T00:00:00Z'][.='2'  ]"
+            ,pre+"/int[@name='1976-07-06T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-07T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='1976-07-08T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-09T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-10T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-11T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-12T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='before' ][.='2']"
+            ,pre+"/int[@name='after'  ][.='4']"
+            ,pre+"/int[@name='between'][.='6']"
+            );
+
+    assertQ("checking counts for all",
+            req( "q", "*:*"
+                ,"rows", "0"
+                ,"facet", "true"
+                ,"facet.date", f
+                ,"facet.date.start", "1976-07-01T00:00:00.000Z"
+                ,"facet.date.end",   "1976-07-13T00:00:00.000Z" // smaller now
+                ,"facet.date.gap",   "+1DAY"
+                ,"facet.date.other", "all"
+                ,"facet.date.include", "all"
+                )
+            // 12 days + pre+post+inner = 15
+            ,"*[count("+pre+"/int)=15]"
+            ,pre+"/int[@name='1976-07-01T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='1976-07-02T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-03T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='1976-07-04T00:00:00Z'][.='2'  ]"
+            ,pre+"/int[@name='1976-07-05T00:00:00Z'][.='2'  ]"
+            ,pre+"/int[@name='1976-07-06T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='1976-07-07T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='1976-07-08T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-09T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-10T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-11T00:00:00Z'][.='0']"
+            ,pre+"/int[@name='1976-07-12T00:00:00Z'][.='1'  ]"
+            ,pre+"/int[@name='before' ][.='2']"
+            ,pre+"/int[@name='after'  ][.='4']"
+            ,pre+"/int[@name='between'][.='6']"
+            );
+  }
+
   static void indexFacetSingleValued() {
     indexFacets("40","t_s1");
   }