blob: 16903aa7b71c1b2fb014c626eef184274160d50f [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.solr.analytics.facet;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.apache.solr.analytics.facet.compare.FacetResultsComparator;
import org.apache.solr.analytics.util.AnalyticsResponseHeadings;
import org.apache.solr.common.util.NamedList;
import com.google.common.collect.Iterables;
/**
* A facet that can be sorted by either the facet value or an expression value.
*/
public abstract class SortableFacet extends AnalyticsFacet {
protected FacetSortSpecification sort = null;
protected SortableFacet(String name) {
super(name);
}
@Override
public NamedList<Object> createOldResponse() {
final NamedList<Object> results = new NamedList<>();
// Export each expression in the bucket.
for (FacetBucket bucket : getBuckets()) {
results.add(bucket.getFacetValue(), new NamedList<>(bucket.getResults()));
}
return results;
}
@Override
public Iterable<Map<String,Object>> createResponse() {
final LinkedList<Map<String,Object>> results = new LinkedList<>();
// Export each expression in the bucket.
for (FacetBucket bucket : getBuckets()) {
Map<String, Object> bucketMap = new HashMap<>();
bucketMap.put(AnalyticsResponseHeadings.FACET_VALUE, bucket.getFacetValue());
bucketMap.put(AnalyticsResponseHeadings.RESULTS, bucket.getResults());
results.add(bucketMap);
}
return results;
}
private Iterable<FacetBucket> getBuckets() {
final List<FacetBucket> facetResults = new ArrayList<>();
reductionData.forEach((facetVal, dataCol) -> {
collectionManager.setData(dataCol);
facetResults.add(new FacetBucket(facetVal,expressionCalculator.getResults()));
});
return applyOptions(facetResults);
}
/**
* Apply the sorting options to the given facet results.
*
* @param facetResults to apply sorting options to
* @return the sorted results
*/
@SuppressWarnings({"unchecked", "rawtypes"})
protected Iterable<FacetBucket> applyOptions(List<FacetBucket> facetResults) {
// Sorting the buckets if a sort specification is provided
if (sort == null || facetResults.isEmpty()) {
return facetResults;
}
Comparator comp = sort.getComparator();
Collections.sort(facetResults, comp);
Iterable<FacetBucket> facetResultsIter = facetResults;
// apply the limit
if (sort.getLimit() > 0) {
if (sort.getOffset() > 0) {
facetResultsIter = Iterables.skip(facetResultsIter, sort.getOffset());
}
facetResultsIter = Iterables.limit(facetResultsIter, sort.getLimit());
} else if (sort.getLimit() == 0) {
return new LinkedList<FacetBucket>();
}
return facetResultsIter;
}
/**
* Specifies how to sort the buckets of a sortable facet.
*/
public static class FacetSortSpecification {
private FacetResultsComparator comparator;
protected int limit;
protected int offset;
public FacetSortSpecification(FacetResultsComparator comparator, int limit, int offset) {
this.comparator = comparator;
this.limit = limit;
this.offset = offset;
}
public FacetResultsComparator getComparator() {
return comparator;
}
/**
* Get the maximum number of buckets to be returned.
*
* @return the limit
*/
public int getLimit() {
return limit;
}
/**
* Set the maximum number of buckets to be returned.
*
* @param limit the maximum number of buckets
*/
public void setLimit(int limit) {
this.limit = limit;
}
/**
* Get the first bucket to return, has to be used with the {@code limit} option.
*
* @return the bucket offset
*/
public int getOffset() {
return offset;
}
}
public SortableFacet.FacetSortSpecification getSort() {
return sort;
}
public void setSort(SortableFacet.FacetSortSpecification sort) {
this.sort = sort;
}
public static class FacetBucket {
private final String facetValue;
private final Map<String,Object> expressionResults;
public FacetBucket(String facetValue, Map<String,Object> expressionResults) {
this.facetValue = facetValue;
this.expressionResults = expressionResults;
}
public Object getResult(String expression) {
return expressionResults.get(expression);
}
public Map<String,Object> getResults() {
return expressionResults;
}
public String getFacetValue() {
return facetValue;
}
}
}