diff --git a/src/main/java/org/springframework/data/elasticsearch/core/facet/FacetMapper.java b/src/main/java/org/springframework/data/elasticsearch/core/facet/FacetMapper.java index a1cd30e89..8c26c3969 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/facet/FacetMapper.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/facet/FacetMapper.java @@ -1,18 +1,18 @@ package org.springframework.data.elasticsearch.core.facet; import org.elasticsearch.search.facet.Facet; +import org.elasticsearch.search.facet.histogram.HistogramFacet; import org.elasticsearch.search.facet.range.RangeFacet; +import org.elasticsearch.search.facet.statistical.StatisticalFacet; import org.elasticsearch.search.facet.terms.TermsFacet; -import org.springframework.data.elasticsearch.core.facet.result.Range; -import org.springframework.data.elasticsearch.core.facet.result.RangeResult; -import org.springframework.data.elasticsearch.core.facet.result.Term; -import org.springframework.data.elasticsearch.core.facet.result.TermResult; +import org.springframework.data.elasticsearch.core.facet.result.*; import java.util.ArrayList; import java.util.List; /** * @author Artur Konczak + * @author Petar Tahchiev */ public class FacetMapper { @@ -25,6 +25,10 @@ public class FacetMapper { return parseRange((RangeFacet) facet); } + if (facet instanceof StatisticalFacet) { + return parseStatistical((StatisticalFacet) facet); + } + return null; } @@ -44,4 +48,8 @@ public class FacetMapper { return new RangeResult(facet.getName(), entries); } + private static FacetResult parseStatistical(StatisticalFacet facet) { + return new StatisticalResult(facet.getName(), facet.getCount(), facet.getMax(), facet.getMin(), facet.getMean(), facet.getStdDeviation(), facet.getSumOfSquares(), facet.getTotal(), facet.getVariance()); + } + } diff --git a/src/main/java/org/springframework/data/elasticsearch/core/facet/FacetType.java b/src/main/java/org/springframework/data/elasticsearch/core/facet/FacetType.java index a0d344944..0c8beeb3e 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/facet/FacetType.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/facet/FacetType.java @@ -1,7 +1,11 @@ package org.springframework.data.elasticsearch.core.facet; +/** + * @author Artur Konczak + * @author Petar Tahchiev + */ public enum FacetType { - term, range, histogram + term, range, histogram, statistical } diff --git a/src/main/java/org/springframework/data/elasticsearch/core/facet/request/StatisticalFacetRequest.java b/src/main/java/org/springframework/data/elasticsearch/core/facet/request/StatisticalFacetRequest.java new file mode 100644 index 000000000..6c48c6d05 --- /dev/null +++ b/src/main/java/org/springframework/data/elasticsearch/core/facet/request/StatisticalFacetRequest.java @@ -0,0 +1,45 @@ +package org.springframework.data.elasticsearch.core.facet.request; + +import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.lang.StringUtils; +import org.elasticsearch.search.facet.FacetBuilder; +import org.elasticsearch.search.facet.FacetBuilders; +import org.elasticsearch.search.facet.statistical.StatisticalFacetBuilder; +import org.springframework.data.elasticsearch.core.facet.AbstractFacetRequest; +import org.springframework.util.Assert; + +/** + * @author Petar Tahchiev + */ +public class StatisticalFacetRequest extends AbstractFacetRequest { + + private String field; + + private String[] fields; + + public StatisticalFacetRequest(String name) { + super(name); + } + + public void setField(String field) { + this.field = field; + } + + public void setFields(String... fields) { + this.fields = fields; + } + + public FacetBuilder getFacet() { + Assert.notNull(getName(), "Facet name can't be a null !!!"); + Assert.isTrue(StringUtils.isNotBlank(field) && fields == null, "Please select field or fields on which to build the facets !!!"); + + StatisticalFacetBuilder builder = FacetBuilders.statisticalFacet(getName()); + if (ArrayUtils.isNotEmpty(fields)) { + builder.fields(fields); + } else { + builder.field(field); + } + + return builder; + } +} diff --git a/src/main/java/org/springframework/data/elasticsearch/core/facet/request/StatisticalFacetRequestBuilder.java b/src/main/java/org/springframework/data/elasticsearch/core/facet/request/StatisticalFacetRequestBuilder.java new file mode 100644 index 000000000..955805f94 --- /dev/null +++ b/src/main/java/org/springframework/data/elasticsearch/core/facet/request/StatisticalFacetRequestBuilder.java @@ -0,0 +1,34 @@ +package org.springframework.data.elasticsearch.core.facet.request; + +import org.springframework.data.elasticsearch.core.facet.FacetRequest; + +/** + * @author Petar Tahchiev + */ +public class StatisticalFacetRequestBuilder { + + StatisticalFacetRequest result; + + public StatisticalFacetRequestBuilder(String name) { + result = new StatisticalFacetRequest(name); + } + + public StatisticalFacetRequestBuilder field(String field) { + result.setField(field); + return this; + } + + public StatisticalFacetRequestBuilder fields(String... fields) { + result.setFields(fields); + return this; + } + + public StatisticalFacetRequestBuilder applyQueryFilter() { + result.setApplyQueryFilter(true); + return this; + } + + public FacetRequest build() { + return result; + } +} diff --git a/src/main/java/org/springframework/data/elasticsearch/core/facet/result/StatisticalResult.java b/src/main/java/org/springframework/data/elasticsearch/core/facet/result/StatisticalResult.java new file mode 100644 index 000000000..6b3489d8e --- /dev/null +++ b/src/main/java/org/springframework/data/elasticsearch/core/facet/result/StatisticalResult.java @@ -0,0 +1,70 @@ +package org.springframework.data.elasticsearch.core.facet.result; + +import org.springframework.data.elasticsearch.core.facet.AbstactFacetResult; +import org.springframework.data.elasticsearch.core.facet.FacetType; + +/** + * @author Petar Tahchiev + */ +public class StatisticalResult extends AbstactFacetResult { + + private long count; + + private double max; + + private double min; + + private double mean; + + private double stdDeviation; + + private double sumOfSquares; + + private double total; + + private double variance; + + public StatisticalResult(String name, long count, double max, double min, double mean, double stdDeviation, double sumOfSquares, double total, double variance) { + super(name, FacetType.statistical); + this.count = count; + this.max = max; + this.min = min; + this.mean = mean; + this.stdDeviation = stdDeviation; + this.sumOfSquares = sumOfSquares; + this.total = total; + this.variance = variance; + } + + public long getCount() { + return count; + } + + public double getMax() { + return max; + } + + public double getMin() { + return min; + } + + public double getMean() { + return mean; + } + + public double getStdDeviation() { + return stdDeviation; + } + + public double getSumOfSquares() { + return sumOfSquares; + } + + public double getTotal() { + return total; + } + + public double getVariance() { + return variance; + } +} diff --git a/src/test/java/org/springframework/data/elasticsearch/core/facet/ElasticsearchTemplateFacetTests.java b/src/test/java/org/springframework/data/elasticsearch/core/facet/ElasticsearchTemplateFacetTests.java index dda6f7f80..8d27db6f8 100644 --- a/src/test/java/org/springframework/data/elasticsearch/core/facet/ElasticsearchTemplateFacetTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/facet/ElasticsearchTemplateFacetTests.java @@ -23,13 +23,8 @@ import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.elasticsearch.core.ElasticsearchTemplate; import org.springframework.data.elasticsearch.core.FacetedPage; -import org.springframework.data.elasticsearch.core.facet.request.NativeFacetRequest; -import org.springframework.data.elasticsearch.core.facet.request.RangeFacetRequestBuilder; -import org.springframework.data.elasticsearch.core.facet.request.TermFacetRequestBuilder; -import org.springframework.data.elasticsearch.core.facet.result.Range; -import org.springframework.data.elasticsearch.core.facet.result.RangeResult; -import org.springframework.data.elasticsearch.core.facet.result.Term; -import org.springframework.data.elasticsearch.core.facet.result.TermResult; +import org.springframework.data.elasticsearch.core.facet.request.*; +import org.springframework.data.elasticsearch.core.facet.result.*; import org.springframework.data.elasticsearch.core.query.IndexQuery; import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder; import org.springframework.data.elasticsearch.core.query.SearchQuery; @@ -57,6 +52,7 @@ public class ElasticsearchTemplateFacetTests { public static final int YEAR_2002 = 2002; public static final int YEAR_2001 = 2001; public static final int YEAR_2000 = 2000; + public static final String PUBLISHED_YEARS = "publishedYears"; @Autowired private ElasticsearchTemplate elasticsearchTemplate; @@ -419,7 +415,7 @@ public class ElasticsearchTemplateFacetTests { String facetName = "rangeYears"; SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchAllQuery()) .withFacet( - new RangeFacetRequestBuilder(facetName).field("publishedYears") + new RangeFacetRequestBuilder(facetName).field(PUBLISHED_YEARS) .to(YEAR_2000).range(YEAR_2000, YEAR_2002).from(YEAR_2002).build() ).build(); // when @@ -456,7 +452,7 @@ public class ElasticsearchTemplateFacetTests { String facetName = "rangeScoreOverYears"; SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchAllQuery()) .withFacet( - new RangeFacetRequestBuilder(facetName).fields("publishedYears", "score") + new RangeFacetRequestBuilder(facetName).fields(PUBLISHED_YEARS, "score") .to(YEAR_2000).range(YEAR_2000, YEAR_2002).from(YEAR_2002).build() ).build(); // when @@ -487,5 +483,21 @@ public class ElasticsearchTemplateFacetTests { assertThat(range.getTotal(), is(40.0)); } + @Test + public void shouldReturnStatisticalFacetForGivenQuery() { + // given + String facetName = "statPublishedYear"; + SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchAllQuery()) + .withFacet(new StatisticalFacetRequestBuilder(facetName).field(PUBLISHED_YEARS).build() + ).build(); + // when + FacetedPage result = elasticsearchTemplate.queryForPage(searchQuery, ArticleEntity.class); + // then + assertThat(result.getNumberOfElements(), is(equalTo(4))); + StatisticalResult facet = (StatisticalResult) result.getFacet(facetName); + assertThat(facet.getCount(), is(equalTo(6L))); + assertThat(facet.getMax(), is(equalTo(2002.0))); + assertThat(facet.getMin(), is(equalTo(2000.0))); + } }