From 9578ad3ef1e857391e01996a8fd9dccc2d569135 Mon Sep 17 00:00:00 2001 From: kimchy Date: Wed, 7 Jul 2010 14:41:34 +0300 Subject: [PATCH] Terms Facets: Allow to specify a set of terms to exclude in the request, closes #246. --- .../facets/terms/TermsFacetBuilder.java | 13 +++++++ .../facets/terms/TermsFacetCollector.java | 33 +++++++++++++--- .../terms/TermsFacetCollectorParser.java | 12 +++++- .../search/facets/SimpleFacetsTests.java | 39 +++++++++++++++++++ 4 files changed, 90 insertions(+), 7 deletions(-) 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 687e2fcec30..223a669d101 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 @@ -32,6 +32,7 @@ import java.io.IOException; public class TermsFacetBuilder extends AbstractFacetBuilder { private String fieldName; private int size = 10; + private String[] exclude; public TermsFacetBuilder(String name) { super(name); @@ -52,6 +53,11 @@ public class TermsFacetBuilder extends AbstractFacetBuilder { return this; } + public TermsFacetBuilder exclude(String... exclude) { + this.exclude = exclude; + return this; + } + public TermsFacetBuilder size(int size) { this.size = size; return this; @@ -66,6 +72,13 @@ public class TermsFacetBuilder extends AbstractFacetBuilder { builder.startObject(TermsFacetCollectorParser.NAME); builder.field("field", fieldName); builder.field("size", size); + if (exclude != null) { + builder.startArray("exclude"); + for (String ex : exclude) { + builder.value(ex); + } + builder.endArray(); + } builder.endObject(); if (filter != null) { 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 db71d8ff4de..6c6d76737d7 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 @@ -22,6 +22,7 @@ package org.elasticsearch.search.facets.terms; import org.apache.lucene.index.IndexReader; import org.elasticsearch.common.collect.BoundedTreeSet; import org.elasticsearch.common.collect.ImmutableList; +import org.elasticsearch.common.collect.ImmutableSet; import org.elasticsearch.common.thread.ThreadLocals; import org.elasticsearch.common.trove.TObjectIntHashMap; import org.elasticsearch.common.trove.TObjectIntIterator; @@ -60,12 +61,15 @@ public class TermsFacetCollector extends AbstractFacetCollector { private FieldData fieldData; - private final AggregatorValueProc aggregator; + private final StaticAggregatorValueProc aggregator; - public TermsFacetCollector(String facetName, String fieldName, int size, FieldDataCache fieldDataCache, MapperService mapperService) { + private final ImmutableSet excluded; + + public TermsFacetCollector(String facetName, String fieldName, int size, FieldDataCache fieldDataCache, MapperService mapperService, ImmutableSet excluded) { super(facetName); this.fieldDataCache = fieldDataCache; this.size = size; + this.excluded = excluded; FieldMapper mapper = mapperService.smartNameFieldMapper(fieldName); this.fieldName = fieldName; @@ -76,8 +80,11 @@ public class TermsFacetCollector extends AbstractFacetCollector { this.indexFieldName = fieldName; this.fieldDataType = FieldData.Type.STRING; } - - aggregator = new AggregatorValueProc(popFacets()); + if (excluded.isEmpty()) { + aggregator = new StaticAggregatorValueProc(popFacets()); + } else { + aggregator = new AggregatorValueProc(popFacets()); + } } @Override protected void doSetNextReader(IndexReader reader, int docBase) throws IOException { @@ -122,11 +129,25 @@ public class TermsFacetCollector extends AbstractFacetCollector { } } - public static class AggregatorValueProc implements FieldData.StringValueInDocProc { + public class AggregatorValueProc extends StaticAggregatorValueProc { + + public AggregatorValueProc(TObjectIntHashMap facets) { + super(facets); + } + + @Override public void onValue(int docId, String value) { + if (excluded.contains(value)) { + return; + } + super.onValue(docId, value); + } + } + + public static class StaticAggregatorValueProc implements FieldData.StringValueInDocProc { private final TObjectIntHashMap facets; - public AggregatorValueProc(TObjectIntHashMap facets) { + public StaticAggregatorValueProc(TObjectIntHashMap facets) { this.facets = facets; } 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 845aacc1cca..b77a4b3b477 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 @@ -19,6 +19,7 @@ package org.elasticsearch.search.facets.terms; +import org.elasticsearch.common.collect.ImmutableSet; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.search.facets.collector.FacetCollector; import org.elasticsearch.search.facets.collector.FacetCollectorParser; @@ -43,9 +44,18 @@ public class TermsFacetCollectorParser implements FacetCollectorParser { String fieldName = null; XContentParser.Token token; + ImmutableSet excluded = ImmutableSet.of(); while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { if (token == XContentParser.Token.FIELD_NAME) { fieldName = parser.currentName(); + } else if (token == XContentParser.Token.START_ARRAY) { + if ("exclude".equals(fieldName)) { + ImmutableSet.Builder builder = ImmutableSet.builder(); + while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) { + builder.add(parser.text()); + } + excluded = builder.build(); + } } else if (token.isValue()) { if ("field".equals(fieldName)) { field = parser.text(); @@ -54,6 +64,6 @@ public class TermsFacetCollectorParser implements FacetCollectorParser { } } } - return new TermsFacetCollector(facetName, field, size, context.fieldDataCache(), context.mapperService()); + return new TermsFacetCollector(facetName, field, size, context.fieldDataCache(), context.mapperService(), excluded); } } 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 edcb0894e4d..3b34853b20c 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 @@ -165,6 +165,45 @@ public class SimpleFacetsTests extends AbstractNodesTests { assertThat(facet.entries().size(), equalTo(1)); assertThat(facet.entries().get(0).term(), equalTo("111")); assertThat(facet.entries().get(0).count(), equalTo(1)); + + searchResponse = client.prepareSearch() + .setQuery(matchAllQuery()) + .addFacet(termsFacet("facet1").field("tag").size(10)) + .execute().actionGet(); + + facet = searchResponse.facets().facet(TermsFacet.class, "facet1"); + assertThat(facet.name(), equalTo("facet1")); + assertThat(facet.entries().size(), equalTo(3)); + assertThat(facet.entries().get(0).term(), equalTo("yyy")); + assertThat(facet.entries().get(0).count(), equalTo(2)); + assertThat(facet.entries().get(1).term(), anyOf(equalTo("xxx"), equalTo("zzz"))); + assertThat(facet.entries().get(1).count(), equalTo(1)); + assertThat(facet.entries().get(2).term(), anyOf(equalTo("xxx"), equalTo("zzz"))); + assertThat(facet.entries().get(2).count(), equalTo(1)); + + searchResponse = client.prepareSearch() + .setQuery(matchAllQuery()) + .addFacet(termsFacet("facet1").field("tag").size(1)) + .execute().actionGet(); + + facet = searchResponse.facets().facet(TermsFacet.class, "facet1"); + assertThat(facet.name(), equalTo("facet1")); + assertThat(facet.entries().size(), equalTo(1)); + assertThat(facet.entries().get(0).term(), equalTo("yyy")); + assertThat(facet.entries().get(0).count(), equalTo(2)); + + searchResponse = client.prepareSearch() + .setQuery(matchAllQuery()) + .addFacet(termsFacet("facet1").field("tag").size(10).exclude("yyy")) + .execute().actionGet(); + + facet = searchResponse.facets().facet(TermsFacet.class, "facet1"); + assertThat(facet.name(), equalTo("facet1")); + assertThat(facet.entries().size(), equalTo(2)); + assertThat(facet.entries().get(0).term(), anyOf(equalTo("xxx"), equalTo("zzz"))); + 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 public void testStatsFacets() throws Exception {