diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facets/terms/InternalTermsFacet.java b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facets/terms/InternalTermsFacet.java index dabad1ce73f..e08e61af6f8 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facets/terms/InternalTermsFacet.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facets/terms/InternalTermsFacet.java @@ -86,6 +86,14 @@ public class InternalTermsFacet implements InternalFacet, TermsFacet { return type(); } + @Override public ComparatorType comparatorType() { + return comparatorType; + } + + @Override public ComparatorType getComparatorType() { + return comparatorType(); + } + @Override public List entries() { if (!(entries instanceof List)) { entries = ImmutableList.copyOf(entries); diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facets/terms/TermsFacet.java b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facets/terms/TermsFacet.java index 6539f963053..9066067d952 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facets/terms/TermsFacet.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facets/terms/TermsFacet.java @@ -26,11 +26,19 @@ import java.util.Comparator; import java.util.List; /** + * Terms facet allows to return facets of the most popular terms within the search query. + * * @author kimchy (shay.banon) */ public interface TermsFacet extends Facet, Iterable { + /** + * Controls how the terms facets are ordered. + */ public static enum ComparatorType { + /** + * Order by the count of each term. + */ COUNT((byte) 0, new Comparator() { @Override public int compare(Entry o1, Entry o2) { @@ -44,14 +52,17 @@ public interface TermsFacet extends Facet, Iterable { return i; } }), + /** + * Order by the count of each term. + */ TERM((byte) 1, new Comparator() { @Override public int compare(Entry o1, Entry o2) { - int i = o2.term().compareTo(o1.term()); + int i = o1.term().compareTo(o2.term()); if (i == 0) { - i = o2.count() - o1.count(); + i = o1.count() - o2.count(); if (i == 0) { - i = System.identityHashCode(o2) - System.identityHashCode(o1); + i = System.identityHashCode(o1) - System.identityHashCode(o2); } } return i; @@ -81,7 +92,16 @@ public interface TermsFacet extends Facet, Iterable { } else if (id == 1) { return TERM; } - throw new ElasticSearchIllegalArgumentException("No type argument match for multi count comparator [" + id + "]"); + throw new ElasticSearchIllegalArgumentException("No type argument match for terms facet comparator [" + id + "]"); + } + + public static ComparatorType fromString(String type) { + if ("count".equals(type)) { + return COUNT; + } else if ("term".equals(type)) { + return TERM; + } + throw new ElasticSearchIllegalArgumentException("No type argument match for terms facet comparator [" + type + "]"); } } @@ -112,11 +132,33 @@ public interface TermsFacet extends Facet, Iterable { } } + /** + * The field name the terms were extracted from. + */ String fieldName(); + /** + * The field name the terms were extracted from. + */ String getFieldName(); + /** + * The ordering of the results. + */ + ComparatorType comparatorType(); + + /** + * The ordering of the results. + */ + ComparatorType getComparatorType(); + + /** + * The terms and counts. + */ List entries(); + /** + * The terms and counts. + */ List getEntries(); } \ No newline at end of file diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facets/terms/TermsFacetBuilder.java b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facets/terms/TermsFacetBuilder.java index 6b2936a29cf..9b0b0f7c18b 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facets/terms/TermsFacetBuilder.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facets/terms/TermsFacetBuilder.java @@ -36,6 +36,7 @@ public class TermsFacetBuilder extends AbstractFacetBuilder { private String[] exclude; private String regex; private int regexFlags = 0; + private TermsFacet.ComparatorType comparatorType; public TermsFacetBuilder(String name) { super(name); @@ -76,6 +77,11 @@ public class TermsFacetBuilder extends AbstractFacetBuilder { return this; } + public TermsFacetBuilder order(TermsFacet.ComparatorType comparatorType) { + this.comparatorType = comparatorType; + return this; + } + @Override public void toXContent(XContentBuilder builder, Params params) throws IOException { if (fieldName == null) { throw new SearchSourceBuilderException("field must be set on terms facet for facet [" + name + "]"); @@ -98,6 +104,9 @@ public class TermsFacetBuilder extends AbstractFacetBuilder { builder.field("regex_flags", Regex.flagsToString(regexFlags)); } } + if (comparatorType != null) { + builder.field("order", comparatorType.name().toLowerCase()); + } builder.endObject(); addFilterFacetAndGlobal(builder, params); diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facets/terms/TermsFacetCollector.java b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facets/terms/TermsFacetCollector.java index 4c1e7f675d4..27480c79714 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facets/terms/TermsFacetCollector.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facets/terms/TermsFacetCollector.java @@ -57,6 +57,8 @@ public class TermsFacetCollector extends AbstractFacetCollector { private final String indexFieldName; + private final InternalTermsFacet.ComparatorType comparatorType; + private final int size; private final int numberOfShards; @@ -71,10 +73,11 @@ public class TermsFacetCollector extends AbstractFacetCollector { private final Pattern pattern; - public TermsFacetCollector(String facetName, String fieldName, int size, int numberOfShards, FieldDataCache fieldDataCache, MapperService mapperService, ImmutableSet excluded, Pattern pattern) { + public TermsFacetCollector(String facetName, String fieldName, int size, InternalTermsFacet.ComparatorType comparatorType, int numberOfShards, FieldDataCache fieldDataCache, MapperService mapperService, ImmutableSet excluded, Pattern pattern) { super(facetName); this.fieldDataCache = fieldDataCache; this.size = size; + this.comparatorType = comparatorType; this.numberOfShards = numberOfShards; this.excluded = excluded; this.pattern = pattern; @@ -107,7 +110,7 @@ public class TermsFacetCollector extends AbstractFacetCollector { TObjectIntHashMap facets = aggregator.facets(); if (facets.isEmpty()) { pushFacets(facets); - return new InternalTermsFacet(facetName, fieldName, InternalTermsFacet.ComparatorType.COUNT, size, ImmutableList.of()); + return new InternalTermsFacet(facetName, fieldName, comparatorType, size, ImmutableList.of()); } else { // we need to fetch facets of "size * numberOfShards" because of problems in how they are distributed across shards BoundedTreeSet ordered = new BoundedTreeSet(InternalTermsFacet.ComparatorType.COUNT.comparator(), size * numberOfShards); @@ -116,7 +119,7 @@ public class TermsFacetCollector extends AbstractFacetCollector { ordered.add(new InternalTermsFacet.Entry(it.key(), it.value())); } pushFacets(facets); - return new InternalTermsFacet(facetName, fieldName, InternalTermsFacet.ComparatorType.COUNT, size, ordered); + return new InternalTermsFacet(facetName, fieldName, comparatorType, size, ordered); } } diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facets/terms/TermsFacetCollectorParser.java b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facets/terms/TermsFacetCollectorParser.java index f56e8d08fce..ed4b56de4d0 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facets/terms/TermsFacetCollectorParser.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facets/terms/TermsFacetCollectorParser.java @@ -49,6 +49,7 @@ public class TermsFacetCollectorParser implements FacetCollectorParser { ImmutableSet excluded = ImmutableSet.of(); String regex = null; String regexFlags = null; + TermsFacet.ComparatorType comparatorType = TermsFacet.ComparatorType.COUNT; while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { if (token == XContentParser.Token.FIELD_NAME) { fieldName = parser.currentName(); @@ -69,6 +70,8 @@ public class TermsFacetCollectorParser implements FacetCollectorParser { regex = parser.text(); } else if ("regex_flags".equals(fieldName) || "regexFlags".equals(fieldName)) { regexFlags = parser.text(); + } else if ("order".equals(fieldName) || "comparator".equals(field)) { + comparatorType = TermsFacet.ComparatorType.fromString(parser.text()); } } } @@ -76,6 +79,6 @@ public class TermsFacetCollectorParser implements FacetCollectorParser { if (regex != null) { pattern = Regex.compile(regex, regexFlags); } - return new TermsFacetCollector(facetName, field, size, context.numberOfShards(), context.fieldDataCache(), context.mapperService(), excluded, pattern); + return new TermsFacetCollector(facetName, field, size, comparatorType, context.numberOfShards(), context.fieldDataCache(), context.mapperService(), excluded, pattern); } } diff --git a/modules/test/integration/src/test/java/org/elasticsearch/test/integration/search/facets/SimpleFacetsTests.java b/modules/test/integration/src/test/java/org/elasticsearch/test/integration/search/facets/SimpleFacetsTests.java index 5dd94dff036..94fb033551a 100644 --- a/modules/test/integration/src/test/java/org/elasticsearch/test/integration/search/facets/SimpleFacetsTests.java +++ b/modules/test/integration/src/test/java/org/elasticsearch/test/integration/search/facets/SimpleFacetsTests.java @@ -230,6 +230,8 @@ public class SimpleFacetsTests extends AbstractNodesTests { assertThat(facet.entries().get(1).term(), anyOf(equalTo("xxx"), equalTo("zzz"))); assertThat(facet.entries().get(1).count(), equalTo(1)); + // Test Exclude + searchResponse = client.prepareSearch() .setQuery(matchAllQuery()) .addFacet(termsFacet("facet1").field("tag").size(10).exclude("yyy")) @@ -242,6 +244,23 @@ public class SimpleFacetsTests extends AbstractNodesTests { assertThat(facet.entries().get(0).count(), equalTo(1)); assertThat(facet.entries().get(1).term(), anyOf(equalTo("xxx"), equalTo("zzz"))); assertThat(facet.entries().get(1).count(), equalTo(1)); + + // Test Order + + searchResponse = client.prepareSearch() + .setQuery(matchAllQuery()) + .addFacet(termsFacet("facet1").field("tag").size(10).order(TermsFacet.ComparatorType.TERM)) + .execute().actionGet(); + + facet = searchResponse.facets().facet("facet1"); + assertThat(facet.name(), equalTo("facet1")); + assertThat(facet.entries().size(), equalTo(3)); + assertThat(facet.entries().get(0).term(), equalTo("xxx")); + assertThat(facet.entries().get(0).count(), equalTo(1)); + assertThat(facet.entries().get(1).term(), equalTo("yyy")); + assertThat(facet.entries().get(1).count(), equalTo(2)); + assertThat(facet.entries().get(2).term(), equalTo("zzz")); + assertThat(facet.entries().get(2).count(), equalTo(1)); } @Test public void testTermFacetWithEqualTermDistribution() throws Exception {