diff --git a/source/java/org/alfresco/rest/api/search/impl/ResultMapper.java b/source/java/org/alfresco/rest/api/search/impl/ResultMapper.java index f0c99b5a61..a818c820ef 100644 --- a/source/java/org/alfresco/rest/api/search/impl/ResultMapper.java +++ b/source/java/org/alfresco/rest/api/search/impl/ResultMapper.java @@ -29,7 +29,6 @@ package org.alfresco.rest.api.search.impl; import static org.alfresco.rest.api.search.impl.StoreMapper.DELETED; import static org.alfresco.rest.api.search.impl.StoreMapper.LIVE_NODES; import static org.alfresco.rest.api.search.impl.StoreMapper.VERSIONS; -import com.sun.javafx.font.Metrics; import org.alfresco.repo.search.impl.lucene.SolrJSONResultSet; import org.alfresco.repo.search.impl.solr.facet.facetsresponse.GenericBucket; import org.alfresco.repo.search.impl.solr.facet.facetsresponse.GenericFacetResponse; @@ -322,6 +321,9 @@ public class ResultMapper Map>> facetInterval = solrResultSet.getFacetIntervals(); facets.addAll(getGenericFacetsForIntervals(facetInterval, searchQuery)); + + Map>> facetRanges = solrResultSet.getFacetRanges(); + facets.addAll(getGenericFacetsForRanges(facetRanges, searchQuery)); List stats = getFieldStats(searchRequestContext, solrResultSet.getStats()); List pimped = getPivots(searchRequestContext, solrResultSet.getPivotFacets(), stats); @@ -473,7 +475,32 @@ public class ResultMapper } return Collections.emptyList(); } - + /** + * Transforms the facet range response into generic facet response. + * @param facetFields + * @param searchQuery + * @return GenericFacetResponse + */ + protected static List getGenericFacetsForRanges(Map>> facetFields, SearchQuery searchQuery) + { + List ffcs = new ArrayList<>(facetFields.size()); + if (facetFields != null && !facetFields.isEmpty()) + { + for (Entry>> facet:facetFields.entrySet()) + { + if (facet.getValue() != null && !facet.getValue().isEmpty()) + { + List buckets = new ArrayList<>(); + facet.getValue().forEach(action -> buckets.add( + new GenericBucket(action.getFirst(), null, null , + new HashSet(Arrays.asList(new SimpleMetric(METRIC_TYPE.count,String.valueOf(action.getSecond())))), + null))); + ffcs.add(new GenericFacetResponse(FACET_TYPE.range, facet.getKey(), buckets)); + } + } + } + return ffcs; + } /** * Returns generic faceting responses for Intervals * @param facetFields diff --git a/source/java/org/alfresco/rest/api/search/impl/SearchMapper.java b/source/java/org/alfresco/rest/api/search/impl/SearchMapper.java index 72580c2d2d..78b68690ca 100644 --- a/source/java/org/alfresco/rest/api/search/impl/SearchMapper.java +++ b/source/java/org/alfresco/rest/api/search/impl/SearchMapper.java @@ -51,6 +51,7 @@ import org.alfresco.service.cmr.search.Interval; import org.alfresco.service.cmr.search.IntervalParameters; import org.alfresco.service.cmr.search.IntervalSet; import org.alfresco.service.cmr.search.LimitBy; +import org.alfresco.service.cmr.search.RangeParameters; import org.alfresco.service.cmr.search.SearchParameters; import org.alfresco.service.cmr.search.SearchParameters.FieldFacet; import org.alfresco.service.cmr.search.SearchParameters.FieldFacetMethod; @@ -510,7 +511,24 @@ public class SearchMapper } sp.setInterval(facetIntervals); } - + /** + * Sets the Range Parameters object on search parameters + * @param sp SearchParameters + * @param rangeParams RangeParameters + */ + public void fromFacetRange(SearchParameters sp, RangeParameters rangeParams) + { + if(rangeParams != null) + { + ParameterCheck.mandatory("facetRange", rangeParams); + ParameterCheck.mandatory("field ", rangeParams.getField()); + ParameterCheck.mandatory("facet range start ", rangeParams.getStart()); + ParameterCheck.mandatory("facet range end ", rangeParams.getEnd()); + ParameterCheck.mandatory("facet range gap ", rangeParams.getGap()); + sp.setRange(rangeParams); + } + + } public void fromPivot(SearchParameters sp, List stats, FacetFields facetFields, List pivots, SearchRequestContext searchRequestContext) { if (facetFields != null && pivots != null && !pivots.isEmpty()) diff --git a/source/java/org/alfresco/rest/api/search/model/SearchQuery.java b/source/java/org/alfresco/rest/api/search/model/SearchQuery.java index 802766fb94..dfb6210bd3 100644 --- a/source/java/org/alfresco/rest/api/search/model/SearchQuery.java +++ b/source/java/org/alfresco/rest/api/search/model/SearchQuery.java @@ -29,6 +29,7 @@ package org.alfresco.rest.api.search.model; import org.alfresco.rest.framework.resource.parameters.Paging; import org.alfresco.service.cmr.search.GeneralHighlightParameters; import org.alfresco.service.cmr.search.IntervalParameters; +import org.alfresco.service.cmr.search.RangeParameters; import org.alfresco.service.cmr.search.StatsRequestParameters; import org.codehaus.jackson.annotate.JsonCreator; import org.codehaus.jackson.annotate.JsonProperty; @@ -60,9 +61,10 @@ public class SearchQuery private final boolean includeRequest; private final List pivots; private final List stats; + private final RangeParameters facetRange; public static final SearchQuery EMPTY = new SearchQuery(null, null, null, null, null, null, - null,null, null, null, null,null, null, null, null, null, null, null); + null,null, null, null, null,null, null, null, null, null, null, null,null); @JsonCreator public SearchQuery(@JsonProperty("query") Query query, @@ -82,7 +84,8 @@ public class SearchQuery @JsonProperty("highlight")GeneralHighlightParameters highlight, @JsonProperty("facetIntervals")IntervalParameters facetIntervals, @JsonProperty("pivots") List pivots, - @JsonProperty("stats") List stats) + @JsonProperty("stats") List stats, + @JsonProperty("facetRange") RangeParameters facetRange) { this.query = query; this.includeRequest = includeRequest==null?false:includeRequest; @@ -102,6 +105,7 @@ public class SearchQuery this.facetIntervals = facetIntervals; this.pivots = pivots; this.stats = stats; + this.facetRange = facetRange; } public Query getQuery() @@ -192,4 +196,10 @@ public class SearchQuery { return stats; } + + public RangeParameters getFacetRange() + { + return facetRange; + } + } diff --git a/source/test-java/org/alfresco/rest/api/search/ResultMapperTests.java b/source/test-java/org/alfresco/rest/api/search/ResultMapperTests.java index 6a84c70b06..fbfc0b357f 100644 --- a/source/test-java/org/alfresco/rest/api/search/ResultMapperTests.java +++ b/source/test-java/org/alfresco/rest/api/search/ResultMapperTests.java @@ -117,7 +117,7 @@ public class ResultMapperTests + "\"facet_counts\":{\"facet_queries\":{\"small\":0,\"large\":0,\"xtra small\":3,\"xtra large\":0,\"medium\":8,\"XX large\":0}," + "\"facet_fields\":{\"content.size\":[\"Big\",8,\"Brown\",3,\"Fox\",5,\"Jumped\",2,\"somewhere\",3]}," +"\"facet_dates\":{}," - +"\"facet_ranges\":{}," + +"\"facet_ranges\":{\"content.size\": {\"counts\": [\"0\",4,\"100\",6,\"200\",3],\"gap\": 100,\"start\": 0,\"end\": 300}}," +"\"facet_pivot\":{\"creator,modifier\":[{\"field\":\"creator\",\"count\":7,\"pivot\":[{\"field\":\"modifier\",\"count\":3,\"value\":\"mjackson\"},{\"field\":\"modifier\",\"count\":4,\"value\":\"admin\"}],\"value\":\"mjackson\"}]}," +"\"facet_intervals\":{\"creator\":{\"last\":4,\"first\":0},\"TheCreated\":{\"earlier\":5,\"lastYear\":0,\"currentYear\":854}}" + "}," @@ -320,8 +320,8 @@ public class ResultMapperTests assertEquals("great", searchContext.getRequest().getQuery().getUserQuery()); //Pivot - assertEquals(5, searchContext.getFacets().size()); - GenericFacetResponse pivotFacet = searchContext.getFacets().get(2); + assertEquals(6, searchContext.getFacets().size()); + GenericFacetResponse pivotFacet = searchContext.getFacets().get(3); assertEquals(FACET_TYPE.pivot,pivotFacet.getType()); assertEquals("creator",pivotFacet.getLabel()); assertEquals(2, pivotFacet.getBuckets().size()); @@ -348,7 +348,7 @@ public class ResultMapperTests assertEquals("{count=4}",metrics[0].getValue().toString()); //Stats - GenericFacetResponse statsFacet = searchContext.getFacets().get(3); + GenericFacetResponse statsFacet = searchContext.getFacets().get(4); assertEquals(FACET_TYPE.stats,statsFacet.getType()); assertEquals("created",statsFacet.getLabel()); Set statsMetrics = statsFacet.getBuckets().get(0).getMetrics(); @@ -362,7 +362,7 @@ public class ResultMapperTests assertTrue(statsMetrics.contains(new SimpleMetric(METRIC_TYPE.sum, 1.458318720769983E15))); assertTrue(statsMetrics.contains(new SimpleMetric(METRIC_TYPE.stddev, 5.6250677994522545E10))); - statsFacet = searchContext.getFacets().get(4); + statsFacet = searchContext.getFacets().get(5); assertEquals("numericLabel",statsFacet.getLabel()); statsMetrics = statsFacet.getBuckets().get(0).getMetrics(); assertEquals(7,statsMetrics.size()); @@ -459,6 +459,33 @@ public class ResultMapperTests assertEquals(METRIC_TYPE.count,((SimpleMetric) metrics[0]).getType()); assertEquals("854",((SimpleMetric) metrics[0]).getValue().get("count")); } + @Test + public void testRange() throws Exception + { + ResultSet results = mockResultset(Collections.emptyList(),Collections.emptyList()); + SearchQuery searchQuery = helper.searchQueryFromJson(); + SearchRequestContext searchRequest = SearchRequestContext.from(searchQuery); + SearchParameters searchParams = searchMapper.toSearchParameters(EMPTY_PARAMS, searchQuery, searchRequest); + SearchContext searchContext = mapper.toSearchContext((SolrJSONResultSet) results, searchRequest, searchQuery, 0); + + //Numeric facet range + List rangeFacets = searchContext.getFacets().stream() + .filter(f -> f.getType().equals(FACET_TYPE.range)).collect(Collectors.toList()); + assertEquals(1, rangeFacets.size()); + assertEquals(3, rangeFacets.get(0).getBuckets().size()); + assertEquals("content.size",rangeFacets.get(0).getLabel()); + assertEquals("0",rangeFacets.get(0).getBuckets().get(0).getLabel()); + Object[] metrics = rangeFacets.get(0).getBuckets().get(0).getMetrics().toArray(); + assertEquals("4",((SimpleMetric) metrics[0]).getValue().get("count")); + + assertEquals("100",rangeFacets.get(0).getBuckets().get(1).getLabel()); + metrics = rangeFacets.get(0).getBuckets().get(1).getMetrics().toArray(); + assertEquals("6",((SimpleMetric) metrics[0]).getValue().get("count")); + + assertEquals("200",rangeFacets.get(0).getBuckets().get(2).getLabel()); + metrics = rangeFacets.get(0).getBuckets().get(2).getMetrics().toArray(); + assertEquals("3",((SimpleMetric) metrics[0]).getValue().get("count")); + } @Test /** diff --git a/source/test-java/org/alfresco/rest/api/search/SearchMapperTests.java b/source/test-java/org/alfresco/rest/api/search/SearchMapperTests.java index d90c06a49f..f9ec510fdb 100644 --- a/source/test-java/org/alfresco/rest/api/search/SearchMapperTests.java +++ b/source/test-java/org/alfresco/rest/api/search/SearchMapperTests.java @@ -59,6 +59,7 @@ import org.alfresco.service.cmr.search.Interval; import org.alfresco.service.cmr.search.IntervalParameters; import org.alfresco.service.cmr.search.IntervalSet; import org.alfresco.service.cmr.search.LimitBy; +import org.alfresco.service.cmr.search.RangeParameters; import org.alfresco.service.cmr.search.SearchParameters; import org.alfresco.service.cmr.search.SearchParameters.FieldFacet; import org.alfresco.service.cmr.search.SearchService; @@ -797,16 +798,31 @@ public class SearchMapperTests searchMapper.fromFacetIntervals(searchParameters, intervalParameters); assertEquals(searchParameters.getInterval(), intervalParameters); } - + + @Test + public void facetRange() + { + SearchParameters searchParameters = new SearchParameters(); + RangeParameters rangeParams = new RangeParameters(null, null, null, null); + try + { + searchMapper.fromFacetRange(searchParameters, rangeParams); + fail(); + } + catch (IllegalArgumentException iae) + { + assertNotNull(iae); + } + rangeParams = new RangeParameters("content.size", "0", "100000", "1000"); + searchMapper.fromFacetRange(searchParameters, rangeParams); + assertEquals(searchParameters.getRange(), rangeParams); + } + private SearchQuery minimalQuery() { Query query = new Query("cmis", "foo", ""); - SearchQuery sq = new SearchQuery(query, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null); + SearchQuery sq = new SearchQuery(query, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,null); return sq; } - @Test - public void facetGroup() - { - - } + } diff --git a/source/test-java/org/alfresco/rest/api/search/SearchQuerySerializerTests.java b/source/test-java/org/alfresco/rest/api/search/SearchQuerySerializerTests.java index 594322cd9e..d55060934d 100644 --- a/source/test-java/org/alfresco/rest/api/search/SearchQuerySerializerTests.java +++ b/source/test-java/org/alfresco/rest/api/search/SearchQuerySerializerTests.java @@ -45,6 +45,7 @@ import org.alfresco.service.cmr.search.FieldHighlightParameters; import org.alfresco.service.cmr.search.Interval; import org.alfresco.service.cmr.search.IntervalParameters; import org.alfresco.service.cmr.search.IntervalSet; +import org.alfresco.service.cmr.search.RangeParameters; import org.junit.BeforeClass; import org.junit.Test; @@ -170,6 +171,10 @@ public class SearchQuerySerializerTests assertEquals(1,searchQuery.getStats().size()); assertEquals("cm:creator",searchQuery.getStats().get(0).getField()); assertEquals("mylabel",searchQuery.getStats().get(0).getLabel()); + //Range Facet + RangeParameters range = searchQuery.getFacetRange(); + assertNotNull(range); + } @Test diff --git a/source/test-java/org/alfresco/rest/api/search/SerializerTestHelper.java b/source/test-java/org/alfresco/rest/api/search/SerializerTestHelper.java index 578baa9836..24f9507e86 100644 --- a/source/test-java/org/alfresco/rest/api/search/SerializerTestHelper.java +++ b/source/test-java/org/alfresco/rest/api/search/SerializerTestHelper.java @@ -64,6 +64,7 @@ public class SerializerTestHelper implements RequestReader + "\"facetFields\": {\"facets\": [{\"field\": \"cm:creator\",\"prefix\": \"myquery2\",\"sort\": \"COUNT\",\"missing\": \"false\"}, {\"field\": \"modifier\",\"label\": \"mylabel\",\"method\": \"FC\",\"mincount\": \"5\"}, {\"field\": \"owner\",\"label\": \"ownerLabel\"}]}," + "\"facetQueries\": [{\"query\": \"cm:created:bob\",\"label\": \"small\"}]," + "\"pivots\": [{\"key\": \"mylabel\"}]," + + "\"facetRange\": {\"field\": \"content.size\",\"facet.range.start\": \"0\",\"facet.range.end\": \"300\",\"facet.range.gap\": \"100\"}," + "\"facetIntervals\": {\"sets\": [{ \"label\": \"king\", \"start\": \"1\", \"end\": \"2\",\"startInclusive\": true,\"endInclusive\": false}]" + ",\"intervals\": [{\"field\": \"cm:creator\",\"label\": \"creator\"," + "\"sets\": [{\"label\": \"last\",\"start\": \"a\",\"end\": \"b\",\"startInclusive\": false}]"