LUCENE-9385: Add FacetsConfig option to control which drill-down terms are indexed for a FacetLabel (#25)

This commit is contained in:
zacharymorn 2021-03-27 09:38:00 -07:00 committed by GitHub
parent 3596e05e5c
commit 3648a1020a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 469 additions and 83 deletions

View File

@ -65,6 +65,44 @@ public class FacetsConfig {
// int/float/bytes in a single indexed field:
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
*
@ -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);
}
ft.indexFieldName = indexFieldName;
dimConfig.indexFieldName = indexFieldName;
}
/** 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 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.requireDimensionDrillDown = v;
dimConfig.drillDownTermsIndexing =
value ? DrillDownTermsIndexing.ALL : DrillDownTermsIndexing.ALL_PATHS_NO_DIM;
}
/** 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);
}
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)));
}

View File

@ -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);
}
}

View File

@ -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 {