From 95b6184135f23a6e1bcd8aef363025b12679f25c Mon Sep 17 00:00:00 2001 From: kimchy Date: Sun, 23 Jan 2011 16:09:18 +0200 Subject: [PATCH] Terms Facets: Allow to get `all_terms` back (possibly with count 0), closes #647. --- .../search/facet/terms/TermsFacetBuilder.java | 13 +++++++++++ .../facet/terms/TermsFacetProcessor.java | 19 +++++++++------- .../terms/bytes/TermsByteFacetCollector.java | 20 +++++++++++++++-- .../doubles/TermsDoubleFacetCollector.java | 20 +++++++++++++++-- .../floats/TermsFloatFacetCollector.java | 20 +++++++++++++++-- .../terms/ints/TermsIntFacetCollector.java | 20 +++++++++++++++-- .../terms/longs/TermsLongFacetCollector.java | 20 +++++++++++++++-- .../shorts/TermsShortFacetCollector.java | 20 +++++++++++++++-- .../FieldsTermsStringFacetCollector.java | 22 +++++++++++++++++-- .../strings/TermsStringFacetCollector.java | 20 +++++++++++++++-- .../search/facet/SimpleFacetsTests.java | 15 +++++++++++++ 11 files changed, 185 insertions(+), 24 deletions(-) diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/terms/TermsFacetBuilder.java b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/terms/TermsFacetBuilder.java index 2c7718a4502..e9867d1cab9 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/terms/TermsFacetBuilder.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/terms/TermsFacetBuilder.java @@ -38,6 +38,7 @@ public class TermsFacetBuilder extends AbstractFacetBuilder { private String fieldName; private String[] fieldsNames; private int size = 10; + private Boolean allTerms; private String[] exclude; private String regex; private int regexFlags = 0; @@ -176,6 +177,15 @@ public class TermsFacetBuilder extends AbstractFacetBuilder { return this; } + /** + * Sets all possible terms to be loaded, even ones with 0 count. Note, this *should not* be used + * with a field that has many possible terms. + */ + public TermsFacetBuilder allTerms(boolean allTerms) { + this.allTerms = allTerms; + return this; + } + @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { if (fieldName == null && fieldsNames == null && script == null) { throw new SearchSourceBuilderException("field/fields/script must be set on terms facet for facet [" + name + "]"); @@ -209,6 +219,9 @@ public class TermsFacetBuilder extends AbstractFacetBuilder { if (comparatorType != null) { builder.field("order", comparatorType.name().toLowerCase()); } + if (allTerms != null) { + builder.field("all_terms", allTerms); + } if (script != null) { builder.field("script", script); diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/terms/TermsFacetProcessor.java b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/terms/TermsFacetProcessor.java index b9b9b2c52a8..9a56441cbb6 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/terms/TermsFacetProcessor.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/terms/TermsFacetProcessor.java @@ -74,6 +74,7 @@ public class TermsFacetProcessor extends AbstractComponent implements FacetProce String scriptLang = null; String script = null; Map params = null; + boolean allTerms = false; String currentFieldName = null; XContentParser.Token token; @@ -105,6 +106,8 @@ public class TermsFacetProcessor extends AbstractComponent implements FacetProce script = parser.text(); } else if ("size".equals(currentFieldName)) { size = parser.intValue(); + } else if ("all_terms".equals(currentFieldName) || "allTerms".equals(currentFieldName)) { + allTerms = parser.booleanValue(); } else if ("regex".equals(currentFieldName)) { regex = parser.text(); } else if ("regex_flags".equals(currentFieldName) || "regexFlags".equals(currentFieldName)) { @@ -128,7 +131,7 @@ public class TermsFacetProcessor extends AbstractComponent implements FacetProce pattern = Regex.compile(regex, regexFlags); } if (fieldsNames != null) { - return new FieldsTermsStringFacetCollector(facetName, fieldsNames, size, comparatorType, context, excluded, pattern, scriptLang, script, params); + return new FieldsTermsStringFacetCollector(facetName, fieldsNames, size, comparatorType, allTerms, context, excluded, pattern, scriptLang, script, params); } if (field == null && fieldsNames == null && script != null) { return new ScriptTermsStringFieldFacetCollector(facetName, size, comparatorType, context, excluded, pattern, scriptLang, script, params); @@ -137,20 +140,20 @@ public class TermsFacetProcessor extends AbstractComponent implements FacetProce FieldMapper fieldMapper = context.mapperService().smartNameFieldMapper(field); if (fieldMapper != null) { if (fieldMapper.fieldDataType() == FieldDataType.DefaultTypes.LONG) { - return new TermsLongFacetCollector(facetName, field, size, comparatorType, context, scriptLang, script, params); + return new TermsLongFacetCollector(facetName, field, size, comparatorType, allTerms, context, scriptLang, script, params); } else if (fieldMapper.fieldDataType() == FieldDataType.DefaultTypes.DOUBLE) { - return new TermsDoubleFacetCollector(facetName, field, size, comparatorType, context, scriptLang, script, params); + return new TermsDoubleFacetCollector(facetName, field, size, comparatorType, allTerms, context, scriptLang, script, params); } else if (fieldMapper.fieldDataType() == FieldDataType.DefaultTypes.INT) { - return new TermsIntFacetCollector(facetName, field, size, comparatorType, context, scriptLang, script, params); + return new TermsIntFacetCollector(facetName, field, size, comparatorType, allTerms, context, scriptLang, script, params); } else if (fieldMapper.fieldDataType() == FieldDataType.DefaultTypes.FLOAT) { - return new TermsFloatFacetCollector(facetName, field, size, comparatorType, context, scriptLang, script, params); + return new TermsFloatFacetCollector(facetName, field, size, comparatorType, allTerms, context, scriptLang, script, params); } else if (fieldMapper.fieldDataType() == FieldDataType.DefaultTypes.SHORT) { - return new TermsShortFacetCollector(facetName, field, size, comparatorType, context, scriptLang, script, params); + return new TermsShortFacetCollector(facetName, field, size, comparatorType, allTerms, context, scriptLang, script, params); } else if (fieldMapper.fieldDataType() == FieldDataType.DefaultTypes.BYTE) { - return new TermsByteFacetCollector(facetName, field, size, comparatorType, context, scriptLang, script, params); + return new TermsByteFacetCollector(facetName, field, size, comparatorType, allTerms, context, scriptLang, script, params); } } - return new TermsStringFacetCollector(facetName, field, size, comparatorType, context, excluded, pattern, scriptLang, script, params); + return new TermsStringFacetCollector(facetName, field, size, comparatorType, allTerms, context, excluded, pattern, scriptLang, script, params); } @Override public Facet reduce(String name, List facets) { diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/terms/bytes/TermsByteFacetCollector.java b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/terms/bytes/TermsByteFacetCollector.java index 1a6d207d33d..0e772aad831 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/terms/bytes/TermsByteFacetCollector.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/terms/bytes/TermsByteFacetCollector.java @@ -34,6 +34,7 @@ import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.script.search.SearchScript; import org.elasticsearch.search.facet.AbstractFacetCollector; import org.elasticsearch.search.facet.Facet; +import org.elasticsearch.search.facet.FacetPhaseExecutionException; import org.elasticsearch.search.facet.terms.TermsFacet; import org.elasticsearch.search.internal.SearchContext; @@ -73,7 +74,7 @@ public class TermsByteFacetCollector extends AbstractFacetCollector { private final SearchScript script; - public TermsByteFacetCollector(String facetName, String fieldName, int size, TermsFacet.ComparatorType comparatorType, SearchContext context, + public TermsByteFacetCollector(String facetName, String fieldName, int size, TermsFacet.ComparatorType comparatorType, boolean allTerms, SearchContext context, String scriptLang, String script, Map params) { super(facetName); this.fieldDataCache = context.fieldDataCache(); @@ -111,6 +112,17 @@ public class TermsByteFacetCollector extends AbstractFacetCollector { } else { aggregator = new AggregatorValueProc(popFacets(), this.script); } + + if (allTerms) { + try { + for (IndexReader reader : context.searcher().subReaders()) { + ByteFieldData fieldData = (ByteFieldData) fieldDataCache.cache(fieldDataType, reader, indexFieldName); + fieldData.forEachValue(aggregator); + } + } catch (Exception e) { + throw new FacetPhaseExecutionException(facetName, "failed to load all terms", e); + } + } } @Override protected void doSetNextReader(IndexReader reader, int docBase) throws IOException { @@ -194,7 +206,7 @@ public class TermsByteFacetCollector extends AbstractFacetCollector { } } - public static class StaticAggregatorValueProc implements ByteFieldData.ValueInDocProc { + public static class StaticAggregatorValueProc implements ByteFieldData.ValueInDocProc, ByteFieldData.ValueProc { private final TByteIntHashMap facets; @@ -204,6 +216,10 @@ public class TermsByteFacetCollector extends AbstractFacetCollector { this.facets = facets; } + @Override public void onValue(byte value) { + facets.putIfAbsent(value, 0); + } + @Override public void onValue(int docId, byte value) { facets.adjustOrPutValue(value, 1, 1); } diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/terms/doubles/TermsDoubleFacetCollector.java b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/terms/doubles/TermsDoubleFacetCollector.java index a8667bdbca5..c311f0bda41 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/terms/doubles/TermsDoubleFacetCollector.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/terms/doubles/TermsDoubleFacetCollector.java @@ -34,6 +34,7 @@ import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.script.search.SearchScript; import org.elasticsearch.search.facet.AbstractFacetCollector; import org.elasticsearch.search.facet.Facet; +import org.elasticsearch.search.facet.FacetPhaseExecutionException; import org.elasticsearch.search.facet.terms.TermsFacet; import org.elasticsearch.search.internal.SearchContext; @@ -73,7 +74,7 @@ public class TermsDoubleFacetCollector extends AbstractFacetCollector { private final SearchScript script; - public TermsDoubleFacetCollector(String facetName, String fieldName, int size, TermsFacet.ComparatorType comparatorType, SearchContext context, + public TermsDoubleFacetCollector(String facetName, String fieldName, int size, TermsFacet.ComparatorType comparatorType, boolean allTerms, SearchContext context, String scriptLang, String script, Map params) { super(facetName); this.fieldDataCache = context.fieldDataCache(); @@ -111,6 +112,17 @@ public class TermsDoubleFacetCollector extends AbstractFacetCollector { } else { aggregator = new AggregatorValueProc(popFacets(), this.script); } + + if (allTerms) { + try { + for (IndexReader reader : context.searcher().subReaders()) { + DoubleFieldData fieldData = (DoubleFieldData) fieldDataCache.cache(fieldDataType, reader, indexFieldName); + fieldData.forEachValue(aggregator); + } + } catch (Exception e) { + throw new FacetPhaseExecutionException(facetName, "failed to load all terms", e); + } + } } @Override protected void doSetNextReader(IndexReader reader, int docBase) throws IOException { @@ -194,7 +206,7 @@ public class TermsDoubleFacetCollector extends AbstractFacetCollector { } } - public static class StaticAggregatorValueProc implements DoubleFieldData.ValueInDocProc { + public static class StaticAggregatorValueProc implements DoubleFieldData.ValueInDocProc, DoubleFieldData.ValueProc { private final TDoubleIntHashMap facets; @@ -204,6 +216,10 @@ public class TermsDoubleFacetCollector extends AbstractFacetCollector { this.facets = facets; } + @Override public void onValue(double value) { + facets.putIfAbsent(value, 0); + } + @Override public void onValue(int docId, double value) { facets.adjustOrPutValue(value, 1, 1); } diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/terms/floats/TermsFloatFacetCollector.java b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/terms/floats/TermsFloatFacetCollector.java index 6ef0308160f..c8a91236470 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/terms/floats/TermsFloatFacetCollector.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/terms/floats/TermsFloatFacetCollector.java @@ -34,6 +34,7 @@ import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.script.search.SearchScript; import org.elasticsearch.search.facet.AbstractFacetCollector; import org.elasticsearch.search.facet.Facet; +import org.elasticsearch.search.facet.FacetPhaseExecutionException; import org.elasticsearch.search.facet.terms.TermsFacet; import org.elasticsearch.search.internal.SearchContext; @@ -73,7 +74,7 @@ public class TermsFloatFacetCollector extends AbstractFacetCollector { private final SearchScript script; - public TermsFloatFacetCollector(String facetName, String fieldName, int size, TermsFacet.ComparatorType comparatorType, SearchContext context, + public TermsFloatFacetCollector(String facetName, String fieldName, int size, TermsFacet.ComparatorType comparatorType, boolean allTerms, SearchContext context, String scriptLang, String script, Map params) { super(facetName); this.fieldDataCache = context.fieldDataCache(); @@ -111,6 +112,17 @@ public class TermsFloatFacetCollector extends AbstractFacetCollector { } else { aggregator = new AggregatorValueProc(popFacets(), this.script); } + + if (allTerms) { + try { + for (IndexReader reader : context.searcher().subReaders()) { + FloatFieldData fieldData = (FloatFieldData) fieldDataCache.cache(fieldDataType, reader, indexFieldName); + fieldData.forEachValue(aggregator); + } + } catch (Exception e) { + throw new FacetPhaseExecutionException(facetName, "failed to load all terms", e); + } + } } @Override protected void doSetNextReader(IndexReader reader, int docBase) throws IOException { @@ -194,7 +206,7 @@ public class TermsFloatFacetCollector extends AbstractFacetCollector { } } - public static class StaticAggregatorValueProc implements FloatFieldData.ValueInDocProc { + public static class StaticAggregatorValueProc implements FloatFieldData.ValueInDocProc, FloatFieldData.ValueProc { private final TFloatIntHashMap facets; @@ -204,6 +216,10 @@ public class TermsFloatFacetCollector extends AbstractFacetCollector { this.facets = facets; } + @Override public void onValue(float value) { + facets.putIfAbsent(value, 0); + } + @Override public void onValue(int docId, float value) { facets.adjustOrPutValue(value, 1, 1); } diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/terms/ints/TermsIntFacetCollector.java b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/terms/ints/TermsIntFacetCollector.java index e5f1901c4eb..c9bb5883196 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/terms/ints/TermsIntFacetCollector.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/terms/ints/TermsIntFacetCollector.java @@ -34,6 +34,7 @@ import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.script.search.SearchScript; import org.elasticsearch.search.facet.AbstractFacetCollector; import org.elasticsearch.search.facet.Facet; +import org.elasticsearch.search.facet.FacetPhaseExecutionException; import org.elasticsearch.search.facet.terms.TermsFacet; import org.elasticsearch.search.internal.SearchContext; @@ -73,7 +74,7 @@ public class TermsIntFacetCollector extends AbstractFacetCollector { private final SearchScript script; - public TermsIntFacetCollector(String facetName, String fieldName, int size, TermsFacet.ComparatorType comparatorType, SearchContext context, + public TermsIntFacetCollector(String facetName, String fieldName, int size, TermsFacet.ComparatorType comparatorType, boolean allTerms, SearchContext context, String scriptLang, String script, Map params) { super(facetName); this.fieldDataCache = context.fieldDataCache(); @@ -111,6 +112,17 @@ public class TermsIntFacetCollector extends AbstractFacetCollector { } else { aggregator = new AggregatorValueProc(popFacets(), this.script); } + + if (allTerms) { + try { + for (IndexReader reader : context.searcher().subReaders()) { + IntFieldData fieldData = (IntFieldData) fieldDataCache.cache(fieldDataType, reader, indexFieldName); + fieldData.forEachValue(aggregator); + } + } catch (Exception e) { + throw new FacetPhaseExecutionException(facetName, "failed to load all terms", e); + } + } } @Override protected void doSetNextReader(IndexReader reader, int docBase) throws IOException { @@ -194,7 +206,7 @@ public class TermsIntFacetCollector extends AbstractFacetCollector { } } - public static class StaticAggregatorValueProc implements IntFieldData.ValueInDocProc { + public static class StaticAggregatorValueProc implements IntFieldData.ValueInDocProc, IntFieldData.ValueProc { private final TIntIntHashMap facets; @@ -204,6 +216,10 @@ public class TermsIntFacetCollector extends AbstractFacetCollector { this.facets = facets; } + @Override public void onValue(int value) { + facets.putIfAbsent(value, 0); + } + @Override public void onValue(int docId, int value) { facets.adjustOrPutValue(value, 1, 1); } diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/terms/longs/TermsLongFacetCollector.java b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/terms/longs/TermsLongFacetCollector.java index 06315ea3ab3..8110b4f8d2b 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/terms/longs/TermsLongFacetCollector.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/terms/longs/TermsLongFacetCollector.java @@ -34,6 +34,7 @@ import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.script.search.SearchScript; import org.elasticsearch.search.facet.AbstractFacetCollector; import org.elasticsearch.search.facet.Facet; +import org.elasticsearch.search.facet.FacetPhaseExecutionException; import org.elasticsearch.search.facet.terms.TermsFacet; import org.elasticsearch.search.internal.SearchContext; @@ -74,7 +75,7 @@ public class TermsLongFacetCollector extends AbstractFacetCollector { private final SearchScript script; - public TermsLongFacetCollector(String facetName, String fieldName, int size, TermsFacet.ComparatorType comparatorType, SearchContext context, + public TermsLongFacetCollector(String facetName, String fieldName, int size, TermsFacet.ComparatorType comparatorType, boolean allTerms, SearchContext context, String scriptLang, String script, Map params) { super(facetName); this.fieldDataCache = context.fieldDataCache(); @@ -112,6 +113,17 @@ public class TermsLongFacetCollector extends AbstractFacetCollector { } else { aggregator = new AggregatorValueProc(popFacets(), this.script); } + + if (allTerms) { + try { + for (IndexReader reader : context.searcher().subReaders()) { + LongFieldData fieldData = (LongFieldData) fieldDataCache.cache(fieldDataType, reader, indexFieldName); + fieldData.forEachValue(aggregator); + } + } catch (Exception e) { + throw new FacetPhaseExecutionException(facetName, "failed to load all terms", e); + } + } } @Override protected void doSetNextReader(IndexReader reader, int docBase) throws IOException { @@ -195,7 +207,7 @@ public class TermsLongFacetCollector extends AbstractFacetCollector { } } - public static class StaticAggregatorValueProc implements LongFieldData.ValueInDocProc { + public static class StaticAggregatorValueProc implements LongFieldData.ValueInDocProc, LongFieldData.ValueProc { private final TLongIntHashMap facets; @@ -205,6 +217,10 @@ public class TermsLongFacetCollector extends AbstractFacetCollector { this.facets = facets; } + @Override public void onValue(long value) { + facets.putIfAbsent(value, 0); + } + @Override public void onValue(int docId, long value) { facets.adjustOrPutValue(value, 1, 1); } diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/terms/shorts/TermsShortFacetCollector.java b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/terms/shorts/TermsShortFacetCollector.java index 44a54307ef7..9d24e88c2b0 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/terms/shorts/TermsShortFacetCollector.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/terms/shorts/TermsShortFacetCollector.java @@ -34,6 +34,7 @@ import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.script.search.SearchScript; import org.elasticsearch.search.facet.AbstractFacetCollector; import org.elasticsearch.search.facet.Facet; +import org.elasticsearch.search.facet.FacetPhaseExecutionException; import org.elasticsearch.search.facet.terms.TermsFacet; import org.elasticsearch.search.internal.SearchContext; @@ -73,7 +74,7 @@ public class TermsShortFacetCollector extends AbstractFacetCollector { private final SearchScript script; - public TermsShortFacetCollector(String facetName, String fieldName, int size, TermsFacet.ComparatorType comparatorType, SearchContext context, + public TermsShortFacetCollector(String facetName, String fieldName, int size, TermsFacet.ComparatorType comparatorType, boolean allTerms, SearchContext context, String scriptLang, String script, Map params) { super(facetName); this.fieldDataCache = context.fieldDataCache(); @@ -111,6 +112,17 @@ public class TermsShortFacetCollector extends AbstractFacetCollector { } else { aggregator = new AggregatorValueProc(popFacets(), this.script); } + + if (allTerms) { + try { + for (IndexReader reader : context.searcher().subReaders()) { + ShortFieldData fieldData = (ShortFieldData) fieldDataCache.cache(fieldDataType, reader, indexFieldName); + fieldData.forEachValue(aggregator); + } + } catch (Exception e) { + throw new FacetPhaseExecutionException(facetName, "failed to load all terms", e); + } + } } @Override protected void doSetNextReader(IndexReader reader, int docBase) throws IOException { @@ -194,7 +206,7 @@ public class TermsShortFacetCollector extends AbstractFacetCollector { } } - public static class StaticAggregatorValueProc implements ShortFieldData.ValueInDocProc { + public static class StaticAggregatorValueProc implements ShortFieldData.ValueInDocProc, ShortFieldData.ValueProc { private final TShortIntHashMap facets; @@ -204,6 +216,10 @@ public class TermsShortFacetCollector extends AbstractFacetCollector { this.facets = facets; } + @Override public void onValue(short value) { + facets.putIfAbsent(value, 0); + } + @Override public void onValue(int docId, short value) { facets.adjustOrPutValue(value, 1, 1); } diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/terms/strings/FieldsTermsStringFacetCollector.java b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/terms/strings/FieldsTermsStringFacetCollector.java index 408c07c7e41..0a670f860eb 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/terms/strings/FieldsTermsStringFacetCollector.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/terms/strings/FieldsTermsStringFacetCollector.java @@ -33,6 +33,7 @@ import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.script.search.SearchScript; import org.elasticsearch.search.facet.AbstractFacetCollector; import org.elasticsearch.search.facet.Facet; +import org.elasticsearch.search.facet.FacetPhaseExecutionException; import org.elasticsearch.search.internal.SearchContext; import java.io.IOException; @@ -67,7 +68,7 @@ public class FieldsTermsStringFacetCollector extends AbstractFacetCollector { private final SearchScript script; - public FieldsTermsStringFacetCollector(String facetName, String[] fieldsNames, int size, InternalStringTermsFacet.ComparatorType comparatorType, SearchContext context, + public FieldsTermsStringFacetCollector(String facetName, String[] fieldsNames, int size, InternalStringTermsFacet.ComparatorType comparatorType, boolean allTerms, SearchContext context, ImmutableSet excluded, Pattern pattern, String scriptLang, String script, Map params) { super(facetName); this.fieldDataCache = context.fieldDataCache(); @@ -104,6 +105,19 @@ public class FieldsTermsStringFacetCollector extends AbstractFacetCollector { } else { aggregator = new AggregatorValueProc(TermsStringFacetCollector.popFacets(), excluded, pattern, this.script); } + + if (allTerms) { + try { + for (int i = 0; i < fieldsNames.length; i++) { + for (IndexReader reader : context.searcher().subReaders()) { + FieldData fieldData = fieldDataCache.cache(fieldsDataType[i], reader, indexFieldsNames[i]); + fieldData.forEachValue(aggregator); + } + } + } catch (Exception e) { + throw new FacetPhaseExecutionException(facetName, "failed to load all terms", e); + } + } } @Override protected void doSetNextReader(IndexReader reader, int docBase) throws IOException { @@ -185,7 +199,7 @@ public class FieldsTermsStringFacetCollector extends AbstractFacetCollector { } } - public static class StaticAggregatorValueProc implements FieldData.StringValueInDocProc { + public static class StaticAggregatorValueProc implements FieldData.StringValueInDocProc, FieldData.StringValueProc { private final TObjectIntHashMap facets; @@ -195,6 +209,10 @@ public class FieldsTermsStringFacetCollector extends AbstractFacetCollector { this.facets = facets; } + @Override public void onValue(String value) { + facets.putIfAbsent(value, 0); + } + @Override public void onValue(int docId, String value) { facets.adjustOrPutValue(value, 1, 1); } diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/terms/strings/TermsStringFacetCollector.java b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/terms/strings/TermsStringFacetCollector.java index a17a60e89ff..a585db01143 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/terms/strings/TermsStringFacetCollector.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/terms/strings/TermsStringFacetCollector.java @@ -34,6 +34,7 @@ import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.script.search.SearchScript; import org.elasticsearch.search.facet.AbstractFacetCollector; import org.elasticsearch.search.facet.Facet; +import org.elasticsearch.search.facet.FacetPhaseExecutionException; import org.elasticsearch.search.facet.terms.TermsFacet; import org.elasticsearch.search.internal.SearchContext; @@ -76,7 +77,7 @@ public class TermsStringFacetCollector extends AbstractFacetCollector { private final SearchScript script; - public TermsStringFacetCollector(String facetName, String fieldName, int size, TermsFacet.ComparatorType comparatorType, SearchContext context, + public TermsStringFacetCollector(String facetName, String fieldName, int size, TermsFacet.ComparatorType comparatorType, boolean allTerms, SearchContext context, ImmutableSet excluded, Pattern pattern, String scriptLang, String script, Map params) { super(facetName); this.fieldDataCache = context.fieldDataCache(); @@ -111,6 +112,17 @@ public class TermsStringFacetCollector extends AbstractFacetCollector { } else { aggregator = new AggregatorValueProc(popFacets(), excluded, pattern, this.script); } + + if (allTerms) { + try { + for (IndexReader reader : context.searcher().subReaders()) { + FieldData fieldData = fieldDataCache.cache(fieldDataType, reader, indexFieldName); + fieldData.forEachValue(aggregator); + } + } catch (Exception e) { + throw new FacetPhaseExecutionException(facetName, "failed to load all terms", e); + } + } } @Override protected void doSetNextReader(IndexReader reader, int docBase) throws IOException { @@ -206,7 +218,7 @@ public class TermsStringFacetCollector extends AbstractFacetCollector { } } - public static class StaticAggregatorValueProc implements FieldData.StringValueInDocProc { + public static class StaticAggregatorValueProc implements FieldData.StringValueInDocProc, FieldData.StringValueProc { private final TObjectIntHashMap facets; @@ -216,6 +228,10 @@ public class TermsStringFacetCollector extends AbstractFacetCollector { this.facets = facets; } + @Override public void onValue(String value) { + facets.putIfAbsent(value, 0); + } + @Override public void onValue(int docId, String value) { facets.adjustOrPutValue(value, 1, 1); } diff --git a/modules/test/integration/src/test/java/org/elasticsearch/test/integration/search/facet/SimpleFacetsTests.java b/modules/test/integration/src/test/java/org/elasticsearch/test/integration/search/facet/SimpleFacetsTests.java index c052e9f6ea2..e0735c622af 100644 --- a/modules/test/integration/src/test/java/org/elasticsearch/test/integration/search/facet/SimpleFacetsTests.java +++ b/modules/test/integration/src/test/java/org/elasticsearch/test/integration/search/facet/SimpleFacetsTests.java @@ -552,6 +552,21 @@ public class SimpleFacetsTests extends AbstractNodesTests { assertThat(facet.entries().get(3).term(), anyOf(equalTo("zzz"), equalTo("xxx"))); assertThat(facet.entries().get(3).count(), equalTo(1)); + searchResponse = client.prepareSearch() + .setQuery(termQuery("xxx", "yyy")) // don't match anything + .addFacet(termsFacet("facet1").field("tag").size(10).allTerms(true)) + .execute().actionGet(); + + facet = searchResponse.facets().facet("facet1"); + assertThat(facet.name(), equalTo("facet1")); + assertThat(facet.entries().size(), equalTo(3)); + assertThat(facet.entries().get(0).term(), anyOf(equalTo("xxx"), equalTo("yyy"), equalTo("zzz"))); + assertThat(facet.entries().get(0).count(), equalTo(0)); + assertThat(facet.entries().get(1).term(), anyOf(equalTo("xxx"), equalTo("yyy"), equalTo("zzz"))); + assertThat(facet.entries().get(1).count(), equalTo(0)); + assertThat(facet.entries().get(2).term(), anyOf(equalTo("xxx"), equalTo("yyy"), equalTo("zzz"))); + assertThat(facet.entries().get(2).count(), equalTo(0)); + // Script Field searchResponse = client.prepareSearch()