You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ro...@apache.org on 2016/06/10 14:42:11 UTC

lucene-solr:branch_6_1: SOLR-9176: Fix facet method fallback selection

Repository: lucene-solr
Updated Branches:
  refs/heads/branch_6_1 5e87c2b31 -> f77afe120


SOLR-9176: Fix facet method fallback selection


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/f77afe12
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/f77afe12
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/f77afe12

Branch: refs/heads/branch_6_1
Commit: f77afe120590c2fde866e773ca296b8c0ad8a9a5
Parents: 5e87c2b
Author: Alan Woodward <ro...@apache.org>
Authored: Fri Jun 10 15:23:27 2016 +0100
Committer: Alan Woodward <ro...@apache.org>
Committed: Fri Jun 10 15:42:00 2016 +0100

----------------------------------------------------------------------
 solr/CHANGES.txt                                |   3 +
 .../org/apache/solr/request/SimpleFacets.java   | 112 ++++++----
 .../apache/solr/request/TestFacetMethods.java   | 207 +++++++++++++++++++
 .../org/apache/solr/request/TestFaceting.java   |  48 ++++-
 4 files changed, 319 insertions(+), 51 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/f77afe12/solr/CHANGES.txt
----------------------------------------------------------------------
diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index 673c1ab..71497fb 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -169,6 +169,9 @@ Bug Fixes
   and there are explicit operators (except for AND) - addresses problems caused by SOLR-2649.
   (Greg Pendlebury, Jan H�ydahl, Erick Erickson, Steve Rowe)
 
+* SOLR-9176: facet method ENUM was sometimes unnecessarily being rewritten to
+  FCS, causing slowdowns (Alessandro Benedetti, Jesse McLaughlin, Alan Woodward)
+
 Optimizations
 ----------------------
 * SOLR-8722: Don't force a full ZkStateReader refresh on every Overseer operation.

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/f77afe12/solr/core/src/java/org/apache/solr/request/SimpleFacets.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/request/SimpleFacets.java b/solr/core/src/java/org/apache/solr/request/SimpleFacets.java
index 0668ee6..c804b74 100644
--- a/solr/core/src/java/org/apache/solr/request/SimpleFacets.java
+++ b/solr/core/src/java/org/apache/solr/request/SimpleFacets.java
@@ -413,54 +413,27 @@ public class SimpleFacets {
 
     // determine what type of faceting method to use
     final String methodStr = params.getFieldParam(field, FacetParams.FACET_METHOD);
-    FacetMethod method = null;
+    final FacetMethod requestedMethod;
     if (FacetParams.FACET_METHOD_enum.equals(methodStr)) {
-      method = FacetMethod.ENUM;
+      requestedMethod = FacetMethod.ENUM;
     } else if (FacetParams.FACET_METHOD_fcs.equals(methodStr)) {
-      method = FacetMethod.FCS;
+      requestedMethod = FacetMethod.FCS;
     } else if (FacetParams.FACET_METHOD_fc.equals(methodStr)) {
-      method = FacetMethod.FC;
+      requestedMethod = FacetMethod.FC;
     } else if(FacetParams.FACET_METHOD_uif.equals(methodStr)) {
-      method = FacetMethod.UIF;
-    }
-
-    if (method == FacetMethod.ENUM && TrieField.getMainValuePrefix(ft) != null) {
-      // enum can't deal with trie fields that index several terms per value
-      method = sf.multiValued() ? FacetMethod.FC : FacetMethod.FCS;
-    }
-
-    if (method == null && ft instanceof BoolField) {
-      // Always use filters for booleans... we know the number of values is very small.
-      method = FacetMethod.ENUM;
+      requestedMethod = FacetMethod.UIF;
+    }else{
+      requestedMethod=null;
     }
 
     final boolean multiToken = sf.multiValued() || ft.multiValuedFieldCache();
-    
-    if (ft.getNumericType() != null && !sf.multiValued()) {
-      // the per-segment approach is optimal for numeric field types since there
-      // are no global ords to merge and no need to create an expensive
-      // top-level reader
-      method = FacetMethod.FCS;
-    }
-
-    if (method == null) {
-      // TODO: default to per-segment or not?
-      method = FacetMethod.FC;
-    }
 
-    if (method == FacetMethod.FCS && multiToken) {
-      // only fc knows how to deal with multi-token fields
-      method = FacetMethod.FC;
-    }
-    
-    if (method == FacetMethod.ENUM && sf.hasDocValues()) {
-      // only fc can handle docvalues types
-      method = FacetMethod.FC;
-    }
+    FacetMethod appliedFacetMethod = selectFacetMethod(sf, requestedMethod, mincount);
 
     RTimer timer = null;
     if (fdebug != null) {
-       fdebug.putInfoItem("method", method.name());
+       fdebug.putInfoItem("requestedMethod", requestedMethod==null?"not specified":requestedMethod.name());
+       fdebug.putInfoItem("appliedMethod", appliedFacetMethod.name());
        fdebug.putInfoItem("inputDocSetSize", docs.size());
        fdebug.putInfoItem("field", field);
        timer = new RTimer();
@@ -469,8 +442,8 @@ public class SimpleFacets {
     if (params.getFieldBool(field, GroupParams.GROUP_FACET, false)) {
       counts = getGroupedCounts(searcher, docs, field, multiToken, offset,limit, mincount, missing, sort, prefix, contains, ignoreCase);
     } else {
-      assert method != null;
-      switch (method) {
+      assert appliedFacetMethod != null;
+      switch (appliedFacetMethod) {
         case ENUM:
           assert TrieField.getMainValuePrefix(ft) == null;
           counts = getFacetTermEnumCounts(searcher, docs, field, offset, limit, mincount,missing,sort,prefix, contains, ignoreCase, params);
@@ -494,7 +467,6 @@ public class SimpleFacets {
           }
           break;
         case UIF:
-
             //Emulate the JSON Faceting structure so we can use the same parsing classes
             Map<String, Object> jsonFacet = new HashMap<>(13);
             jsonFacet.put("type", "terms");
@@ -566,6 +538,66 @@ public class SimpleFacets {
     return counts;
   }
 
+  /**
+   * This method will force the appropriate facet method even if the user provided a different one as a request parameter
+   *
+   * N.B. this method could overwrite what you passed as request parameter. Be Extra careful
+   *
+   * @param field field we are faceting
+   * @param method the facet method passed as a request parameter
+   * @param mincount the minimum value a facet should have to be returned
+   * @return the FacetMethod to use
+   */
+   static FacetMethod selectFacetMethod(SchemaField field, FacetMethod method, Integer mincount) {
+
+     FieldType type = field.getType();
+
+     /*The user did not specify any preference*/
+     if (method == null) {
+      /* Always use filters for booleans... we know the number of values is very small. */
+       if (type instanceof BoolField) {
+         method = FacetMethod.ENUM;
+       } else if (type.getNumericType() != null && !field.multiValued()) {
+        /* the per-segment approach is optimal for numeric field types since there
+           are no global ords to merge and no need to create an expensive
+           top-level reader */
+         method = FacetMethod.FCS;
+       } else {
+         // TODO: default to per-segment or not?
+         method = FacetMethod.FC;
+       }
+     }
+
+     /* FC without docValues does not support single valued numeric facets */
+     if (method == FacetMethod.FC
+         && type.getNumericType() != null && !field.multiValued()) {
+       method = FacetMethod.FCS;
+     }
+
+     /* UIF without DocValues can't deal with mincount=0, the reason is because
+         we create the buckets based on the values present in the result set.
+         So we are not going to see facet values which are not in the result set */
+     if (method == FacetMethod.UIF
+         && !field.hasDocValues() && mincount == 0) {
+       method = field.multiValued() ? FacetMethod.FC : FacetMethod.FCS;
+     }
+
+     /* ENUM can't deal with trie fields that index several terms per value */
+     if (method == FacetMethod.ENUM
+         && TrieField.getMainValuePrefix(type) != null) {
+       method = field.multiValued() ? FacetMethod.FC : FacetMethod.FCS;
+     }
+
+     /* FCS can't deal with multi token fields */
+     final boolean multiToken = field.multiValued() || type.multiValuedFieldCache();
+     if (method == FacetMethod.FCS
+         && multiToken) {
+       method = FacetMethod.FC;
+     }
+
+     return method;
+  }
+
   public NamedList<Integer> getGroupedCounts(SolrIndexSearcher searcher,
                                              DocSet base,
                                              String field,

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/f77afe12/solr/core/src/test/org/apache/solr/request/TestFacetMethods.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/request/TestFacetMethods.java b/solr/core/src/test/org/apache/solr/request/TestFacetMethods.java
new file mode 100644
index 0000000..29c0ef2
--- /dev/null
+++ b/solr/core/src/test/org/apache/solr/request/TestFacetMethods.java
@@ -0,0 +1,207 @@
+package org.apache.solr.request;
+
+/*
+ * 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.schema.BoolField;
+import org.apache.solr.schema.SchemaField;
+import org.apache.solr.schema.StrField;
+import org.apache.solr.schema.TrieIntField;
+import org.junit.Test;
+
+import static junit.framework.Assert.assertEquals;
+
+public class TestFacetMethods {
+
+  // TODO - make these public in FieldProperties?
+  protected final static int MULTIVALUED         = 0x00000200;
+  protected final static int DOC_VALUES          = 0x00008000;
+
+  @Test
+  public void testNumericSingleValuedDV() {
+
+    SchemaField field = new SchemaField("field", new TrieIntField(), DOC_VALUES, null);
+
+    // default is FCS, can't use ENUM due to trie-field terms, FC rewrites to FCS for efficiency
+
+    assertEquals(SimpleFacets.FacetMethod.FCS, SimpleFacets.selectFacetMethod(field, null, 0));
+    assertEquals(SimpleFacets.FacetMethod.FCS, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.ENUM, 0));
+    assertEquals(SimpleFacets.FacetMethod.FCS, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.FC, 0));
+    assertEquals(SimpleFacets.FacetMethod.UIF, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.UIF, 0));
+    assertEquals(SimpleFacets.FacetMethod.FCS, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.FCS, 0));
+    assertEquals(SimpleFacets.FacetMethod.FCS, SimpleFacets.selectFacetMethod(field, null, 1));
+    assertEquals(SimpleFacets.FacetMethod.FCS, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.ENUM, 1));
+    assertEquals(SimpleFacets.FacetMethod.FCS, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.FC, 1));
+    assertEquals(SimpleFacets.FacetMethod.UIF, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.UIF, 1));
+    assertEquals(SimpleFacets.FacetMethod.FCS, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.FCS, 1));
+
+  }
+
+  @Test
+  public void testNumericMultiValuedDV() {
+
+    SchemaField field = new SchemaField("field", new TrieIntField(), DOC_VALUES ^ MULTIVALUED, null);
+
+    // default is FC, can't use ENUM due to trie-field terms, can't use FCS because of multivalues
+
+    // default value is FC
+    assertEquals(SimpleFacets.FacetMethod.FC, SimpleFacets.selectFacetMethod(field, null, 0));
+    assertEquals(SimpleFacets.FacetMethod.FC, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.ENUM, 0));
+    assertEquals(SimpleFacets.FacetMethod.FC, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.FCS, 0));
+    assertEquals(SimpleFacets.FacetMethod.UIF, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.UIF, 0));
+    assertEquals(SimpleFacets.FacetMethod.FC, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.FC, 0));
+    assertEquals(SimpleFacets.FacetMethod.FC, SimpleFacets.selectFacetMethod(field, null, 1));
+    assertEquals(SimpleFacets.FacetMethod.FC, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.ENUM, 1));
+    assertEquals(SimpleFacets.FacetMethod.FC, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.FCS, 1));
+    assertEquals(SimpleFacets.FacetMethod.UIF, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.UIF, 1));
+    assertEquals(SimpleFacets.FacetMethod.FC, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.FC, 1));
+
+  }
+
+  @Test
+  public void testNumericSingleValuedNoDV() {
+
+    SchemaField field = new SchemaField("field", new TrieIntField(), 0, null);
+
+    // only works with FCS for mincount = 0, UIF for count > 0 is fine
+
+    assertEquals(SimpleFacets.FacetMethod.FCS, SimpleFacets.selectFacetMethod(field, null, 0));
+    assertEquals(SimpleFacets.FacetMethod.FCS, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.ENUM, 0));
+    assertEquals(SimpleFacets.FacetMethod.FCS, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.FC, 0));
+    assertEquals(SimpleFacets.FacetMethod.FCS, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.UIF, 0));
+    assertEquals(SimpleFacets.FacetMethod.FCS, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.FCS, 0));
+    assertEquals(SimpleFacets.FacetMethod.FCS, SimpleFacets.selectFacetMethod(field, null, 1));
+    assertEquals(SimpleFacets.FacetMethod.FCS, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.ENUM, 1));
+    assertEquals(SimpleFacets.FacetMethod.FCS, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.FC, 1));
+    assertEquals(SimpleFacets.FacetMethod.UIF, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.UIF, 1));
+    assertEquals(SimpleFacets.FacetMethod.FCS, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.FCS, 1));
+
+  }
+
+  @Test
+  public void testNumericMultiValuedNoDV() {
+
+    SchemaField field = new SchemaField("field", new TrieIntField(), MULTIVALUED, null);
+
+    // only works with FC for mincount = 0, UIF for count > 1 is fine
+
+    assertEquals(SimpleFacets.FacetMethod.FC, SimpleFacets.selectFacetMethod(field, null, 0));
+    assertEquals(SimpleFacets.FacetMethod.FC, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.ENUM, 0));
+    assertEquals(SimpleFacets.FacetMethod.FC, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.FCS, 0));
+    assertEquals(SimpleFacets.FacetMethod.FC, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.UIF, 0));
+    assertEquals(SimpleFacets.FacetMethod.FC, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.FC, 0));
+    assertEquals(SimpleFacets.FacetMethod.FC, SimpleFacets.selectFacetMethod(field, null, 1));
+    assertEquals(SimpleFacets.FacetMethod.FC, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.ENUM, 1));
+    assertEquals(SimpleFacets.FacetMethod.FC, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.FCS, 1));
+    assertEquals(SimpleFacets.FacetMethod.UIF, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.UIF, 1));
+    assertEquals(SimpleFacets.FacetMethod.FC, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.FC, 1));
+
+  }
+
+  @Test
+  public void testTextSingleValuedDV() {
+
+    SchemaField field = new SchemaField("field", new StrField(), DOC_VALUES, null);
+
+    // default is FC, otherwise just uses the passed-in method
+
+    assertEquals(SimpleFacets.FacetMethod.FC, SimpleFacets.selectFacetMethod(field, null, 0));
+    assertEquals(SimpleFacets.FacetMethod.ENUM, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.ENUM, 0));
+    assertEquals(SimpleFacets.FacetMethod.FC, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.FC, 0));
+    assertEquals(SimpleFacets.FacetMethod.UIF, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.UIF, 0));
+    assertEquals(SimpleFacets.FacetMethod.FCS, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.FCS, 0));
+    assertEquals(SimpleFacets.FacetMethod.FC, SimpleFacets.selectFacetMethod(field, null, 1));
+    assertEquals(SimpleFacets.FacetMethod.ENUM, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.ENUM, 1));
+    assertEquals(SimpleFacets.FacetMethod.FC, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.FC, 1));
+    assertEquals(SimpleFacets.FacetMethod.UIF, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.UIF, 1));
+    assertEquals(SimpleFacets.FacetMethod.FCS, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.FCS, 1));
+
+  }
+
+  @Test
+  public void testTextMultiValuedDV() {
+
+    SchemaField field = new SchemaField("field", new StrField(), DOC_VALUES ^ MULTIVALUED, null);
+
+    // default is FC, can't use FCS because of multivalues
+
+    assertEquals(SimpleFacets.FacetMethod.FC, SimpleFacets.selectFacetMethod(field, null, 0));
+    assertEquals(SimpleFacets.FacetMethod.ENUM, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.ENUM, 0));
+    assertEquals(SimpleFacets.FacetMethod.FC, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.FCS, 0));
+    assertEquals(SimpleFacets.FacetMethod.UIF, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.UIF, 0));
+    assertEquals(SimpleFacets.FacetMethod.FC, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.FC, 0));
+    assertEquals(SimpleFacets.FacetMethod.FC, SimpleFacets.selectFacetMethod(field, null, 1));
+    assertEquals(SimpleFacets.FacetMethod.ENUM, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.ENUM, 1));
+    assertEquals(SimpleFacets.FacetMethod.FC, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.FCS, 1));
+    assertEquals(SimpleFacets.FacetMethod.UIF, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.UIF, 1));
+    assertEquals(SimpleFacets.FacetMethod.FC, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.FC, 1));
+
+  }
+
+  @Test
+  public void testTextSingleValuedNoDV() {
+
+    SchemaField field = new SchemaField("field", new StrField(), 0, null);
+
+    // default is FC, UIF rewrites to FCS for mincount = 0
+    // TODO should it rewrite to FC instead?
+
+    assertEquals(SimpleFacets.FacetMethod.FC, SimpleFacets.selectFacetMethod(field, null, 0));
+    assertEquals(SimpleFacets.FacetMethod.ENUM, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.ENUM, 0));
+    assertEquals(SimpleFacets.FacetMethod.FC, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.FC, 0));
+    assertEquals(SimpleFacets.FacetMethod.FCS, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.UIF, 0));
+    assertEquals(SimpleFacets.FacetMethod.FCS, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.FCS, 0));
+    assertEquals(SimpleFacets.FacetMethod.FC, SimpleFacets.selectFacetMethod(field, null, 1));
+    assertEquals(SimpleFacets.FacetMethod.ENUM, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.ENUM, 1));
+    assertEquals(SimpleFacets.FacetMethod.FC, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.FC, 1));
+    assertEquals(SimpleFacets.FacetMethod.UIF, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.UIF, 1));
+    assertEquals(SimpleFacets.FacetMethod.FCS, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.FCS, 1));
+
+  }
+
+  @Test
+  public void testTextMultiValuedNoDV() {
+
+    SchemaField field = new SchemaField("field", new StrField(), MULTIVALUED, null);
+
+    // default is FC, can't use FCS for multivalued fields, UIF rewrites to FC for mincount = 0
+
+    assertEquals(SimpleFacets.FacetMethod.FC, SimpleFacets.selectFacetMethod(field, null, 0));
+    assertEquals(SimpleFacets.FacetMethod.ENUM, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.ENUM, 0));
+    assertEquals(SimpleFacets.FacetMethod.FC, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.FCS, 0));
+    assertEquals(SimpleFacets.FacetMethod.FC, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.UIF, 0));
+    assertEquals(SimpleFacets.FacetMethod.FC, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.FC, 0));
+    assertEquals(SimpleFacets.FacetMethod.FC, SimpleFacets.selectFacetMethod(field, null, 1));
+    assertEquals(SimpleFacets.FacetMethod.ENUM, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.ENUM, 1));
+    assertEquals(SimpleFacets.FacetMethod.FC, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.FCS, 1));
+    assertEquals(SimpleFacets.FacetMethod.UIF, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.UIF, 1));
+    assertEquals(SimpleFacets.FacetMethod.FC, SimpleFacets.selectFacetMethod(field, SimpleFacets.FacetMethod.FC, 1));
+
+  }
+
+  @Test
+  public void testBooleanDefaults() {
+
+    // BoolField defaults to ENUM
+
+    SchemaField field = new SchemaField("field", new BoolField(), 0, null);
+    assertEquals(SimpleFacets.FacetMethod.ENUM, SimpleFacets.selectFacetMethod(field, null, 0));
+    assertEquals(SimpleFacets.FacetMethod.ENUM, SimpleFacets.selectFacetMethod(field, null, 1));
+
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/f77afe12/solr/core/src/test/org/apache/solr/request/TestFaceting.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/request/TestFaceting.java b/solr/core/src/test/org/apache/solr/request/TestFaceting.java
index 4dd49e1..cee9f52 100644
--- a/solr/core/src/test/org/apache/solr/request/TestFaceting.java
+++ b/solr/core/src/test/org/apache/solr/request/TestFaceting.java
@@ -255,17 +255,17 @@ public class TestFaceting extends SolrTestCaseJ4 {
 
     int i=iter-1;
     assertQ("check many tokens",
-            req("q", "id:"+t(i),"indent","true"
-                ,"facet", "true", "facet.method",((methodSeed + i)%2 ==0 ?"fc":"uif")
-                ,"facet.field", "many_ws"
-                ,"facet.limit", "-1"
-                ,"facet.mincount", "1"
+        req("q", "id:" + t(i), "indent", "true"
+            , "facet", "true", "facet.method", ((methodSeed + i) % 2 == 0 ? "fc" : "uif")
+            , "facet.field", "many_ws"
+            , "facet.limit", "-1"
+            , "facet.mincount", "1"
 
-                )
-            ,"*[count(//lst[@name='many_ws']/int)=" + 2 + "]"
-            ,"//lst[@name='many_ws']/int[@name='" + t(i1+i) + "'][.='1']"
-            ,"//lst[@name='many_ws']/int[@name='" + t(i1*2+i) + "'][.='1']"
-            );
+        )
+        , "*[count(//lst[@name='many_ws']/int)=" + 2 + "]"
+        , "//lst[@name='many_ws']/int[@name='" + t(i1 + i) + "'][.='1']"
+        , "//lst[@name='many_ws']/int[@name='" + t(i1 * 2 + i) + "'][.='1']"
+    );
   }
 
   @Test
@@ -314,8 +314,34 @@ public class TestFaceting extends SolrTestCaseJ4 {
         "//lst[@name='facet_fields']/lst[@name='f_td']/int[1][@name='-420.126']",
         "//lst[@name='facet_fields']/lst[@name='f_td']/int[2][@name='-285.672']",
         "//lst[@name='facet_fields']/lst[@name='f_td']/int[3][@name='-1.218']");
+
+    assertQ(req("q", "*:*", FacetParams.FACET, "true", FacetParams.FACET_FIELD, "f_td", "f.f_td.facet.sort", FacetParams.FACET_SORT_INDEX, FacetParams.FACET_MINCOUNT, "1", FacetParams.FACET_METHOD, FacetParams.FACET_METHOD_uif),
+        "*[count(//lst[@name='f_td']/int)=3]",
+        "//lst[@name='facet_fields']/lst[@name='f_td']/int[1][@name='-420.126']",
+        "//lst[@name='facet_fields']/lst[@name='f_td']/int[2][@name='-285.672']",
+        "//lst[@name='facet_fields']/lst[@name='f_td']/int[3][@name='-1.218']");
     
-    assertQ(req("q", "*:*", FacetParams.FACET, "true", FacetParams.FACET_FIELD, "f_td", "f.f_td.facet.sort", FacetParams.FACET_SORT_INDEX, FacetParams.FACET_MINCOUNT, "1", "indent","true"),
+    assertQ(req("q", "*:*", FacetParams.FACET, "true", FacetParams.FACET_FIELD, "f_td", "f.f_td.facet.sort", FacetParams.FACET_SORT_INDEX, FacetParams.FACET_MINCOUNT, "1", "indent", "true"),
+        "*[count(//lst[@name='f_td']/int)=3]",
+        "//lst[@name='facet_fields']/lst[@name='f_td']/int[1][@name='-420.126']",
+        "//lst[@name='facet_fields']/lst[@name='f_td']/int[2][@name='-285.672']",
+        "//lst[@name='facet_fields']/lst[@name='f_td']/int[3][@name='-1.218']");
+  }
+
+  @Test
+  public void testFacetSortWithMinCount0() {
+    assertU(adoc("id", "1.0", "f_td", "-420.126"));
+    assertU(adoc("id", "2.0", "f_td", "-285.672"));
+    assertU(adoc("id", "3.0", "f_td", "-1.218"));
+    assertU(commit());
+
+    assertQ(req("q", "id:1.0", FacetParams.FACET, "true", FacetParams.FACET_FIELD, "f_td", "f.f_td.facet.sort", FacetParams.FACET_SORT_INDEX, FacetParams.FACET_MINCOUNT, "0", FacetParams.FACET_METHOD, FacetParams.FACET_METHOD_fc),
+        "*[count(//lst[@name='f_td']/int)=3]",
+        "//lst[@name='facet_fields']/lst[@name='f_td']/int[1][@name='-420.126']",
+        "//lst[@name='facet_fields']/lst[@name='f_td']/int[2][@name='-285.672']",
+        "//lst[@name='facet_fields']/lst[@name='f_td']/int[3][@name='-1.218']");
+
+    assertQ(req("q", "id:1.0", FacetParams.FACET, "true", FacetParams.FACET_FIELD, "f_td", "f.f_td.facet.sort", FacetParams.FACET_SORT_INDEX, FacetParams.FACET_MINCOUNT, "0", FacetParams.FACET_METHOD, FacetParams.FACET_METHOD_uif),
         "*[count(//lst[@name='f_td']/int)=3]",
         "//lst[@name='facet_fields']/lst[@name='f_td']/int[1][@name='-420.126']",
         "//lst[@name='facet_fields']/lst[@name='f_td']/int[2][@name='-285.672']",