You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by mi...@apache.org on 2021/03/27 16:38:09 UTC

[lucene] branch main updated: LUCENE-9385: Add FacetsConfig option to control which drill-down terms are indexed for a FacetLabel (#25)

This is an automated email from the ASF dual-hosted git repository.

mikemccand pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/lucene.git


The following commit(s) were added to refs/heads/main by this push:
     new 3648a10  LUCENE-9385: Add FacetsConfig option to control which drill-down terms are indexed for a FacetLabel (#25)
3648a10 is described below

commit 3648a1020a8ab6b729ed53e0360499e624bb0cd1
Author: zacharymorn <za...@yahoo.com>
AuthorDate: Sat Mar 27 09:38:00 2021 -0700

    LUCENE-9385: Add FacetsConfig option to control which drill-down terms are indexed for a FacetLabel (#25)
---
 .../java/org/apache/lucene/facet/FacetsConfig.java | 233 +++++++++++++--------
 .../apache/lucene/facet/TestDrillDownQuery.java    | 230 ++++++++++++++++++++
 .../sortedset/TestSortedSetDocValuesFacets.java    |  89 ++++++++
 3 files changed, 469 insertions(+), 83 deletions(-)

diff --git a/lucene/facet/src/java/org/apache/lucene/facet/FacetsConfig.java b/lucene/facet/src/java/org/apache/lucene/facet/FacetsConfig.java
index 4d4fedd..fc3d32a 100644
--- a/lucene/facet/src/java/org/apache/lucene/facet/FacetsConfig.java
+++ b/lucene/facet/src/java/org/apache/lucene/facet/FacetsConfig.java
@@ -66,6 +66,44 @@ public class FacetsConfig {
   private final Map<String, String> assocDimTypes = new ConcurrentHashMap<>();
 
   /**
+   * Drill down terms indexing option to control whether dimension and sub-path terms should be
+   * indexed.
+   */
+  public enum DrillDownTermsIndexing {
+    /**
+     * Index no drill down terms. e.g. for FacetField("a", "foo/bar/baz"), we would index no drill
+     * down terms at all (not even full-path drill down term).
+     */
+    NONE,
+
+    /**
+     * Index only full-path drill down terms. No dimension nor sub-path indexing. e.g. for
+     * FacetField("a", "foo/bar/baz"), we would only index value "a/foo/bar/baz".
+     */
+    FULL_PATH_ONLY,
+
+    /**
+     * Index sub-path and full-path drill down terms. No dimension indexing. e.g. for
+     * FacetField("a", "foo/bar/baz"), we would only index values "a/foo", "a/foo/bar", and
+     * "a/foo/bar/baz".
+     */
+    ALL_PATHS_NO_DIM,
+
+    /**
+     * Index dimension and full-path drill down terms. No sub-path indexing. e.g. for
+     * FacetField("a", "foo/bar/baz"), we would only index values "a" and "a/foo/bar/baz".
+     */
+    DIMENSION_AND_FULL_PATH,
+
+    /**
+     * Index dimension, sub-path and full-path drill down terms. e.g. for FacetField("a",
+     * "foo/bar/baz"), we would index all values "a", "a/foo", "a/foo/bar", and "a/foo/bar/baz".
+     * This is the default / existing behavior.
+     */
+    ALL
+  }
+
+  /**
    * Holds the configuration for one dimension
    *
    * @lucene.experimental
@@ -83,11 +121,8 @@ public class FacetsConfig {
      */
     public boolean requireDimCount;
 
-    /**
-     * True if drilling down by a whole dimension, to match all documents that had any value for
-     * this dimension, is necessary (default is true)
-     */
-    public boolean requireDimensionDrillDown = true;
+    /** Default drill down terms indexing option that index all. */
+    public DrillDownTermsIndexing drillDownTermsIndexing = DrillDownTermsIndexing.ALL;
 
     /** Actual field where this dimension's facet labels should be indexed */
     public String indexFieldName = DEFAULT_INDEX_FIELD_NAME;
@@ -115,44 +150,44 @@ public class FacetsConfig {
 
   /** Get the current configuration for a dimension. */
   public DimConfig getDimConfig(String dimName) {
-    DimConfig ft = fieldTypes.get(dimName);
-    if (ft == null) {
-      ft = getDefaultDimConfig();
+    DimConfig dimConfig = fieldTypes.get(dimName);
+    if (dimConfig == null) {
+      dimConfig = getDefaultDimConfig();
     }
-    return ft;
+    return dimConfig;
   }
 
   /** Pass {@code true} if this dimension is hierarchical (has depth &gt; 1 paths). */
   public synchronized void setHierarchical(String dimName, boolean v) {
-    DimConfig ft = fieldTypes.get(dimName);
-    if (ft == null) {
-      ft = new DimConfig();
-      fieldTypes.put(dimName, ft);
+    DimConfig dimConfig = fieldTypes.get(dimName);
+    if (dimConfig == null) {
+      dimConfig = new DimConfig();
+      fieldTypes.put(dimName, dimConfig);
     }
-    ft.hierarchical = v;
+    dimConfig.hierarchical = v;
   }
 
   /** Pass {@code true} if this dimension may have more than one value per document. */
-  public synchronized void setMultiValued(String dimName, boolean v) {
-    DimConfig ft = fieldTypes.get(dimName);
-    if (ft == null) {
-      ft = new DimConfig();
-      fieldTypes.put(dimName, ft);
+  public synchronized void setMultiValued(String dimName, boolean value) {
+    DimConfig dimConfig = fieldTypes.get(dimName);
+    if (dimConfig == null) {
+      dimConfig = new DimConfig();
+      fieldTypes.put(dimName, dimConfig);
     }
-    ft.multiValued = v;
+    dimConfig.multiValued = value;
   }
 
   /**
    * Pass {@code true} if at search time you require accurate counts of the dimension, i.e. how many
    * hits have this dimension.
    */
-  public synchronized void setRequireDimCount(String dimName, boolean v) {
-    DimConfig ft = fieldTypes.get(dimName);
-    if (ft == null) {
-      ft = new DimConfig();
-      fieldTypes.put(dimName, ft);
+  public synchronized void setRequireDimCount(String dimName, boolean value) {
+    DimConfig dimConfig = fieldTypes.get(dimName);
+    if (dimConfig == null) {
+      dimConfig = new DimConfig();
+      fieldTypes.put(dimName, dimConfig);
     }
-    ft.requireDimCount = v;
+    dimConfig.requireDimCount = value;
   }
 
   /**
@@ -160,22 +195,42 @@ public class FacetsConfig {
    * by the taxonomy based facet methods.
    */
   public synchronized void setIndexFieldName(String dimName, String indexFieldName) {
-    DimConfig ft = fieldTypes.get(dimName);
-    if (ft == null) {
-      ft = new DimConfig();
-      fieldTypes.put(dimName, ft);
+    DimConfig dimConfig = fieldTypes.get(dimName);
+    if (dimConfig == null) {
+      dimConfig = new DimConfig();
+      fieldTypes.put(dimName, dimConfig);
+    }
+    dimConfig.indexFieldName = indexFieldName;
+  }
+
+  /**
+   * Specify whether drill down on the dimension is necessary.
+   *
+   * @deprecated Use {@link FacetsConfig#setDrillDownTermsIndexing(String, DrillDownTermsIndexing)}
+   *     instead
+   */
+  @Deprecated
+  public synchronized void setRequireDimensionDrillDown(String dimName, boolean value) {
+    DimConfig dimConfig = fieldTypes.get(dimName);
+    if (dimConfig == null) {
+      dimConfig = new DimConfig();
+      fieldTypes.put(dimName, dimConfig);
     }
-    ft.indexFieldName = indexFieldName;
+
+    dimConfig.drillDownTermsIndexing =
+        value ? DrillDownTermsIndexing.ALL : DrillDownTermsIndexing.ALL_PATHS_NO_DIM;
   }
 
-  /** Specify whether drill down on just the dimension is necessary. */
-  public synchronized void setRequireDimensionDrillDown(String dimName, boolean v) {
-    DimConfig ft = fieldTypes.get(dimName);
-    if (ft == null) {
-      ft = new DimConfig();
-      fieldTypes.put(dimName, ft);
+  /** Specify drill down terms option on the field / dimension. */
+  public synchronized void setDrillDownTermsIndexing(
+      String dimName, DrillDownTermsIndexing drillDownTermsIndexing) {
+    DimConfig dimConfig = fieldTypes.get(dimName);
+    if (dimConfig == null) {
+      dimConfig = new DimConfig();
+      fieldTypes.put(dimName, dimConfig);
     }
-    ft.requireDimensionDrillDown = v;
+
+    dimConfig.drillDownTermsIndexing = drillDownTermsIndexing;
   }
 
   /** Returns map of field name to {@link DimConfig}. */
@@ -308,8 +363,6 @@ public class FacetsConfig {
     processSSDVFacetFields(dvByField, result);
     processAssocFacetFields(taxoWriter, assocByField, result);
 
-    // System.out.println("add stored: " + addedStoredFields);
-
     for (IndexableField field : doc.getFields()) {
       IndexableFieldType ft = field.fieldType();
       if (ft != FacetField.TYPE
@@ -319,9 +372,6 @@ public class FacetsConfig {
       }
     }
 
-    // System.out.println("all indexed: " + allIndexedFields);
-    // System.out.println("all stored: " + allStoredFields);
-
     return result;
   }
 
@@ -330,15 +380,13 @@ public class FacetsConfig {
       throws IOException {
 
     for (Map.Entry<String, List<FacetField>> ent : byField.entrySet()) {
-
       String indexFieldName = ent.getKey();
-      // System.out.println("  indexFieldName=" + indexFieldName + " fields=" + ent.getValue());
 
       IntsRefBuilder ordinals = new IntsRefBuilder();
       for (FacetField facetField : ent.getValue()) {
 
-        FacetsConfig.DimConfig ft = getDimConfig(facetField.dim);
-        if (facetField.path.length > 1 && ft.hierarchical == false) {
+        FacetsConfig.DimConfig dimConfig = getDimConfig(facetField.dim);
+        if (facetField.path.length > 1 && dimConfig.hierarchical == false) {
           throw new IllegalArgumentException(
               "dimension \""
                   + facetField.dim
@@ -347,16 +395,13 @@ public class FacetsConfig {
                   + " components");
         }
 
-        FacetLabel cp = new FacetLabel(facetField.dim, facetField.path);
+        FacetLabel facetLabel = new FacetLabel(facetField.dim, facetField.path);
 
         checkTaxoWriter(taxoWriter);
-        int ordinal = taxoWriter.addCategory(cp);
+        int ordinal = taxoWriter.addCategory(facetLabel);
         ordinals.append(ordinal);
-        // System.out.println("ords[" + (ordinals.length-1) + "]=" + ordinal);
-        // System.out.println("  add cp=" + cp);
 
-        if (ft.multiValued && (ft.hierarchical || ft.requireDimCount)) {
-          // System.out.println("  add parents");
+        if (dimConfig.multiValued && (dimConfig.hierarchical || dimConfig.requireDimCount)) {
           // Add all parents too:
           int parent = taxoWriter.getParent(ordinal);
           while (parent > 0) {
@@ -364,22 +409,13 @@ public class FacetsConfig {
             parent = taxoWriter.getParent(parent);
           }
 
-          if (ft.requireDimCount == false) {
+          if (dimConfig.requireDimCount == false) {
             // Remove last (dimension) ord:
             ordinals.setLength(ordinals.length() - 1);
           }
         }
 
-        // Drill down:
-        int start;
-        if (ft.requireDimensionDrillDown) {
-          start = 1;
-        } else {
-          start = 2;
-        }
-        for (int i = start; i <= cp.length; i++) {
-          doc.add(new StringField(indexFieldName, pathToString(cp.components, i), Field.Store.NO));
-        }
+        indexDrillDownTerms(doc, indexFieldName, dimConfig, facetLabel);
       }
 
       // Facet counts:
@@ -388,29 +424,64 @@ public class FacetsConfig {
     }
   }
 
+  private void indexDrillDownTerms(
+      Document doc, String indexFieldName, DimConfig dimConfig, FacetLabel facetLabel) {
+    if (dimConfig.drillDownTermsIndexing != DrillDownTermsIndexing.NONE) {
+      // index full-path drill down term
+      doc.add(
+          new StringField(
+              indexFieldName,
+              pathToString(facetLabel.components, facetLabel.length),
+              Field.Store.NO));
+
+      switch (dimConfig.drillDownTermsIndexing) {
+        case NONE:
+        case FULL_PATH_ONLY:
+          // these two cases are already handled above
+          break;
+        case DIMENSION_AND_FULL_PATH:
+          doc.add(
+              new StringField(
+                  indexFieldName, pathToString(facetLabel.components, 1), Field.Store.NO));
+          break;
+        case ALL_PATHS_NO_DIM:
+          for (int i = 2; i < facetLabel.length; i++) {
+            doc.add(
+                new StringField(
+                    indexFieldName, pathToString(facetLabel.components, i), Field.Store.NO));
+          }
+          break;
+        case ALL:
+          for (int i = 1; i < facetLabel.length; i++) {
+            doc.add(
+                new StringField(
+                    indexFieldName, pathToString(facetLabel.components, i), Field.Store.NO));
+          }
+          break;
+        default:
+          throw new AssertionError(
+              "Drill down term indexing option "
+                  + dimConfig.drillDownTermsIndexing
+                  + " is not supported.");
+      }
+    }
+  }
+
   private void processSSDVFacetFields(
-      Map<String, List<SortedSetDocValuesFacetField>> byField, Document doc) throws IOException {
-    // System.out.println("process SSDV: " + byField);
+      Map<String, List<SortedSetDocValuesFacetField>> byField, Document doc) {
     for (Map.Entry<String, List<SortedSetDocValuesFacetField>> ent : byField.entrySet()) {
 
       String indexFieldName = ent.getKey();
-      // System.out.println("  field=" + indexFieldName);
 
       for (SortedSetDocValuesFacetField facetField : ent.getValue()) {
-        FacetLabel cp = new FacetLabel(facetField.dim, facetField.label);
-        String fullPath = pathToString(cp.components, cp.length);
-        // System.out.println("add " + fullPath);
+        FacetLabel facetLabel = new FacetLabel(facetField.dim, facetField.label);
+        String fullPath = pathToString(facetLabel.components, facetLabel.length);
 
         // For facet counts:
         doc.add(new SortedSetDocValuesField(indexFieldName, new BytesRef(fullPath)));
 
         // For drill-down:
-        doc.add(new StringField(indexFieldName, fullPath, Field.Store.NO));
-
-        FacetsConfig.DimConfig ft = getDimConfig(facetField.dim);
-        if (ft.requireDimensionDrillDown) {
-          doc.add(new StringField(indexFieldName, facetField.dim, Field.Store.NO));
-        }
+        indexDrillDownTerms(doc, indexFieldName, getDimConfig(facetField.dim), facetLabel);
       }
     }
   }
@@ -425,8 +496,8 @@ public class FacetsConfig {
       for (AssociationFacetField field : ent.getValue()) {
         // NOTE: we don't add parents for associations
         checkTaxoWriter(taxoWriter);
-        FacetLabel label = new FacetLabel(field.dim, field.path);
-        int ordinal = taxoWriter.addCategory(label);
+        FacetLabel facetLabel = new FacetLabel(field.dim, field.path);
+        int ordinal = taxoWriter.addCategory(facetLabel);
         if (upto + 4 > bytes.length) {
           bytes = ArrayUtil.grow(bytes, upto + 4);
         }
@@ -441,11 +512,7 @@ public class FacetsConfig {
         System.arraycopy(field.assoc.bytes, field.assoc.offset, bytes, upto, field.assoc.length);
         upto += field.assoc.length;
 
-        // Drill down:
-        for (int i = 1; i <= label.length; i++) {
-          doc.add(
-              new StringField(indexFieldName, pathToString(label.components, i), Field.Store.NO));
-        }
+        indexDrillDownTerms(doc, indexFieldName, getDimConfig(field.dim), facetLabel);
       }
       doc.add(new BinaryDocValuesField(indexFieldName, new BytesRef(bytes, 0, upto)));
     }
diff --git a/lucene/facet/src/test/org/apache/lucene/facet/TestDrillDownQuery.java b/lucene/facet/src/test/org/apache/lucene/facet/TestDrillDownQuery.java
index 722db93..e69090f 100644
--- a/lucene/facet/src/test/org/apache/lucene/facet/TestDrillDownQuery.java
+++ b/lucene/facet/src/test/org/apache/lucene/facet/TestDrillDownQuery.java
@@ -23,6 +23,7 @@ import org.apache.lucene.analysis.MockTokenizer;
 import org.apache.lucene.document.Document;
 import org.apache.lucene.document.Field;
 import org.apache.lucene.document.TextField;
+import org.apache.lucene.facet.taxonomy.IntAssociationFacetField;
 import org.apache.lucene.facet.taxonomy.TaxonomyWriter;
 import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyReader;
 import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyWriter;
@@ -299,4 +300,233 @@ public class TestDrillDownQuery extends FacetTestCase {
     assertEquals(0, searcher.count(q));
     IOUtils.close(taxoReader, reader, writer, dir, taxoDir);
   }
+
+  public void testSkipDrillDownTermsIndexing() throws Exception {
+    Directory dir = newDirectory();
+    RandomIndexWriter writer =
+        new RandomIndexWriter(
+            random(),
+            dir,
+            newIndexWriterConfig(new MockAnalyzer(random(), MockTokenizer.KEYWORD, false)));
+    Directory taxoDir = newDirectory();
+    TaxonomyWriter taxoWriter = new DirectoryTaxonomyWriter(taxoDir);
+    FacetsConfig config = new FacetsConfig();
+    config.setDrillDownTermsIndexing("a", FacetsConfig.DrillDownTermsIndexing.FULL_PATH_ONLY);
+    config.setDrillDownTermsIndexing("b", FacetsConfig.DrillDownTermsIndexing.FULL_PATH_ONLY);
+
+    Document doc = new Document();
+    doc.add(new FacetField("a", "1"));
+    doc.add(new FacetField("b", "2"));
+    writer.addDocument(config.build(taxoWriter, doc));
+    taxoWriter.close();
+
+    IndexReader reader = writer.getReader();
+    DirectoryTaxonomyReader taxoReader = new DirectoryTaxonomyReader(taxoDir);
+    IndexSearcher searcher = newSearcher(reader);
+
+    DrillDownQuery q = new DrillDownQuery(config);
+    q.add("a");
+    // no hits because we disabled dimension drill down completely
+    assertEquals(0, searcher.count(q));
+
+    q = new DrillDownQuery(config);
+    q.add("a", "1");
+    assertEquals(1, searcher.count(q));
+
+    q = new DrillDownQuery(config);
+    q.add("b");
+    // no hits because we disabled dimension drill down completely
+    assertEquals(0, searcher.count(q));
+
+    q = new DrillDownQuery(config);
+    q.add("b", "2");
+    assertEquals(1, searcher.count(q));
+
+    IOUtils.close(taxoReader, reader, writer, dir, taxoDir);
+  }
+
+  public void testDrillDownTermsDifferentOptions() throws Exception {
+    Directory dir = newDirectory();
+    RandomIndexWriter writer =
+        new RandomIndexWriter(
+            random(),
+            dir,
+            newIndexWriterConfig(new MockAnalyzer(random(), MockTokenizer.KEYWORD, false)));
+    Directory taxoDir = newDirectory();
+    TaxonomyWriter taxoWriter = new DirectoryTaxonomyWriter(taxoDir);
+    FacetsConfig config = new FacetsConfig();
+    config.setHierarchical("a", true);
+    config.setHierarchical("b", true);
+    config.setHierarchical("c", true);
+    config.setHierarchical("d", true);
+    config.setHierarchical("e", true);
+    config.setDrillDownTermsIndexing("a", FacetsConfig.DrillDownTermsIndexing.NONE);
+    config.setDrillDownTermsIndexing("b", FacetsConfig.DrillDownTermsIndexing.FULL_PATH_ONLY);
+    config.setDrillDownTermsIndexing("c", FacetsConfig.DrillDownTermsIndexing.ALL_PATHS_NO_DIM);
+    config.setDrillDownTermsIndexing(
+        "d", FacetsConfig.DrillDownTermsIndexing.DIMENSION_AND_FULL_PATH);
+    config.setDrillDownTermsIndexing("e", FacetsConfig.DrillDownTermsIndexing.ALL);
+    config.setDrillDownTermsIndexing("f", FacetsConfig.DrillDownTermsIndexing.NONE);
+    config.setIndexFieldName("f", "facet-for-f");
+
+    Document doc = new Document();
+    doc.add(new FacetField("a", "a1", "a2", "a3"));
+    doc.add(new FacetField("b", "b1", "b2", "b3"));
+    doc.add(new FacetField("c", "c1", "c2", "c3"));
+    doc.add(new FacetField("d", "d1", "d2", "d3"));
+    doc.add(new FacetField("e", "e1", "e2", "e3"));
+    doc.add(new IntAssociationFacetField(5, "f", "f1"));
+    writer.addDocument(config.build(taxoWriter, doc));
+    taxoWriter.close();
+
+    IndexReader reader = writer.getReader();
+    DirectoryTaxonomyReader taxoReader = new DirectoryTaxonomyReader(taxoDir);
+    IndexSearcher searcher = newSearcher(reader);
+
+    // Verifies for FacetsConfig.DrillDownTermsIndexing.NONE option
+    DrillDownQuery q = new DrillDownQuery(config);
+    q.add("a");
+    assertEquals(0, searcher.count(q));
+
+    q = new DrillDownQuery(config);
+    q.add("a", "a1");
+    assertEquals(0, searcher.count(q));
+
+    q = new DrillDownQuery(config);
+    q.add("a", "a1", "a2");
+    assertEquals(0, searcher.count(q));
+
+    q = new DrillDownQuery(config);
+    q.add("a", "a1", "a2", "a3");
+    assertEquals(0, searcher.count(q));
+
+    // Verifies for FacetsConfig.DrillDownTermsIndexing.FULL_PATH_ONLY option
+    q = new DrillDownQuery(config);
+    q.add("b");
+    assertEquals(0, searcher.count(q));
+
+    q = new DrillDownQuery(config);
+    q.add("b", "b1");
+    assertEquals(0, searcher.count(q));
+
+    q = new DrillDownQuery(config);
+    q.add("b", "b1", "b2");
+    assertEquals(0, searcher.count(q));
+
+    q = new DrillDownQuery(config);
+    q.add("b", "b1", "b2", "b3");
+    assertEquals(1, searcher.count(q));
+
+    // Verifies for FacetsConfig.DrillDownTermsIndexing.ALL_PATHS_NO_DIM option
+    q = new DrillDownQuery(config);
+    q.add("c");
+    assertEquals(0, searcher.count(q));
+
+    q = new DrillDownQuery(config);
+    q.add("c", "c1");
+    assertEquals(1, searcher.count(q));
+
+    q = new DrillDownQuery(config);
+    q.add("c", "c1", "c2");
+    assertEquals(1, searcher.count(q));
+
+    q = new DrillDownQuery(config);
+    q.add("c", "c1", "c2", "c3");
+    assertEquals(1, searcher.count(q));
+
+    // Verifies for FacetsConfig.DrillDownTermsIndexing.DIMENSION_AND_FULL_PATH option
+    q = new DrillDownQuery(config);
+    q.add("d");
+    assertEquals(1, searcher.count(q));
+
+    q = new DrillDownQuery(config);
+    q.add("d", "d1");
+    assertEquals(0, searcher.count(q));
+
+    q = new DrillDownQuery(config);
+    q.add("d", "d1", "d2");
+    assertEquals(0, searcher.count(q));
+
+    q = new DrillDownQuery(config);
+    q.add("d", "d1", "d2", "d3");
+    assertEquals(1, searcher.count(q));
+
+    // Verifies for FacetsConfig.DrillDownTermsIndexing.ALL option
+    q = new DrillDownQuery(config);
+    q.add("e");
+    assertEquals(1, searcher.count(q));
+
+    q = new DrillDownQuery(config);
+    q.add("e", "e1");
+    assertEquals(1, searcher.count(q));
+
+    q = new DrillDownQuery(config);
+    q.add("e", "e1", "e2");
+    assertEquals(1, searcher.count(q));
+
+    q = new DrillDownQuery(config);
+    q.add("e", "e1", "e2", "e3");
+    assertEquals(1, searcher.count(q));
+
+    // Verifies for FacetsConfig.DrillDownTermsIndexing.DIMENSION_AND_FULL_PATH option with
+    // IntAssociationFacetField
+    q = new DrillDownQuery(config);
+    q.add("f");
+    assertEquals(0, searcher.count(q));
+
+    q = new DrillDownQuery(config);
+    q.add("f", "f1");
+    assertEquals(0, searcher.count(q));
+
+    IOUtils.close(taxoReader, reader, writer, dir, taxoDir);
+  }
+
+  public void testDrillDownTermsDefaultWithHierarchicalSetting() throws Exception {
+    Directory dir = newDirectory();
+    RandomIndexWriter writer =
+        new RandomIndexWriter(
+            random(),
+            dir,
+            newIndexWriterConfig(new MockAnalyzer(random(), MockTokenizer.KEYWORD, false)));
+    Directory taxoDir = newDirectory();
+    TaxonomyWriter taxoWriter = new DirectoryTaxonomyWriter(taxoDir);
+    FacetsConfig config = new FacetsConfig();
+    config.setHierarchical("a", true);
+
+    Document doc = new Document();
+    doc.add(new FacetField("a", "1", "2", "3"));
+    doc.add(new FacetField("b", "4"));
+    writer.addDocument(config.build(taxoWriter, doc));
+    taxoWriter.close();
+
+    IndexReader reader = writer.getReader();
+    DirectoryTaxonomyReader taxoReader = new DirectoryTaxonomyReader(taxoDir);
+    IndexSearcher searcher = newSearcher(reader);
+
+    DrillDownQuery q = new DrillDownQuery(config);
+    q.add("a");
+    assertEquals(1, searcher.count(q));
+
+    q = new DrillDownQuery(config);
+    q.add("a", "1");
+    assertEquals(1, searcher.count(q));
+
+    q = new DrillDownQuery(config);
+    q.add("a", "1", "2");
+    assertEquals(1, searcher.count(q));
+
+    q = new DrillDownQuery(config);
+    q.add("a", "1", "2", "3");
+    assertEquals(1, searcher.count(q));
+
+    q = new DrillDownQuery(config);
+    q.add("b");
+    assertEquals(1, searcher.count(q));
+
+    q = new DrillDownQuery(config);
+    q.add("b", "4");
+    assertEquals(1, searcher.count(q));
+
+    IOUtils.close(taxoReader, reader, writer, dir, taxoDir);
+  }
 }
diff --git a/lucene/facet/src/test/org/apache/lucene/facet/sortedset/TestSortedSetDocValuesFacets.java b/lucene/facet/src/test/org/apache/lucene/facet/sortedset/TestSortedSetDocValuesFacets.java
index c20986f..91a70fc 100644
--- a/lucene/facet/src/test/org/apache/lucene/facet/sortedset/TestSortedSetDocValuesFacets.java
+++ b/lucene/facet/src/test/org/apache/lucene/facet/sortedset/TestSortedSetDocValuesFacets.java
@@ -105,6 +105,95 @@ public class TestSortedSetDocValuesFacets extends FacetTestCase {
     IOUtils.close(searcher.getIndexReader(), dir);
   }
 
+  public void testDrillDownOptions() throws Exception {
+    Directory dir = newDirectory();
+
+    FacetsConfig config = new FacetsConfig();
+    config.setDrillDownTermsIndexing("c", FacetsConfig.DrillDownTermsIndexing.NONE);
+    config.setDrillDownTermsIndexing(
+        "d", FacetsConfig.DrillDownTermsIndexing.DIMENSION_AND_FULL_PATH);
+    config.setDrillDownTermsIndexing("e", FacetsConfig.DrillDownTermsIndexing.ALL_PATHS_NO_DIM);
+    config.setDrillDownTermsIndexing("f", FacetsConfig.DrillDownTermsIndexing.FULL_PATH_ONLY);
+    config.setDrillDownTermsIndexing("g", FacetsConfig.DrillDownTermsIndexing.ALL);
+    RandomIndexWriter writer = new RandomIndexWriter(random(), dir);
+
+    Document doc = new Document();
+    doc.add(new SortedSetDocValuesFacetField("c", "foo"));
+    doc.add(new SortedSetDocValuesFacetField("d", "foo"));
+    doc.add(new SortedSetDocValuesFacetField("e", "foo"));
+    doc.add(new SortedSetDocValuesFacetField("f", "foo"));
+    doc.add(new SortedSetDocValuesFacetField("g", "foo"));
+    writer.addDocument(config.build(doc));
+    if (random().nextBoolean()) {
+      writer.commit();
+    }
+
+    doc = new Document();
+    doc.add(new SortedSetDocValuesFacetField("a", "foo"));
+    writer.addDocument(config.build(doc));
+
+    // NRT open
+    IndexSearcher searcher = newSearcher(writer.getReader());
+    ExecutorService exec = randomExecutorServiceOrNull();
+
+    // Drill down with different indexing configuration options
+    DrillDownQuery q = new DrillDownQuery(config);
+    q.add("c");
+    TopDocs hits = searcher.search(q, 1);
+    assertEquals(0, hits.totalHits.value);
+
+    q = new DrillDownQuery(config);
+    q.add("c", "foo");
+    hits = searcher.search(q, 1);
+    assertEquals(0, hits.totalHits.value);
+
+    q = new DrillDownQuery(config);
+    q.add("d");
+    hits = searcher.search(q, 1);
+    assertEquals(1, hits.totalHits.value);
+
+    q = new DrillDownQuery(config);
+    q.add("d", "foo");
+    hits = searcher.search(q, 1);
+    assertEquals(1, hits.totalHits.value);
+
+    q = new DrillDownQuery(config);
+    q.add("e");
+    hits = searcher.search(q, 1);
+    assertEquals(0, hits.totalHits.value);
+
+    q = new DrillDownQuery(config);
+    q.add("e", "foo");
+    hits = searcher.search(q, 1);
+    assertEquals(1, hits.totalHits.value);
+
+    q = new DrillDownQuery(config);
+    q.add("f");
+    hits = searcher.search(q, 1);
+    assertEquals(0, hits.totalHits.value);
+
+    q = new DrillDownQuery(config);
+    q.add("f", "foo");
+    hits = searcher.search(q, 1);
+    assertEquals(1, hits.totalHits.value);
+
+    q = new DrillDownQuery(config);
+    q.add("g");
+    hits = searcher.search(q, 1);
+    assertEquals(1, hits.totalHits.value);
+
+    q = new DrillDownQuery(config);
+    q.add("g", "foo");
+    hits = searcher.search(q, 1);
+    assertEquals(1, hits.totalHits.value);
+
+    if (exec != null) {
+      exec.shutdownNow();
+    }
+    writer.close();
+    IOUtils.close(searcher.getIndexReader(), dir);
+  }
+
   // LUCENE-5090
   @SuppressWarnings("unused")
   public void testStaleState() throws Exception {