Merged HEAD-BUG-FIX (4.3/Cloud) to HEAD (4.3/Cloud)

70675: Merged WAT1 (4.3/Cloud) to HEAD-BUG-FIX (4.3/Cloud)
      68557: ACE-1265: added Created date, Modified date, and Content size bucketing. Also, refactored the facet display label implementation.


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@70906 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
David Draper
2014-05-19 12:48:13 +00:00
parent 00ef38d6e8
commit 4d920b21e9
12 changed files with 665 additions and 84 deletions

View File

@@ -348,4 +348,10 @@ public class CMISResultSetImpl implements CMISResultSet, Serializable
}
throw new IllegalStateException();
}
@Override
public Map<String, Integer> getFacetQueries()
{
return Collections.emptyMap();
}
}

View File

@@ -353,4 +353,10 @@ public class CMISResultSet implements ResultSetSPI<CMISResultSetRow, CMISResultS
}
throw new IllegalStateException();
}
@Override
public Map<String, Integer> getFacetQueries()
{
return Collections.emptyMap();
}
}

View File

@@ -26,14 +26,17 @@ import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.management.subsystems.SwitchableApplicationContextFactory;
import org.alfresco.repo.model.Repository;
import org.alfresco.repo.search.impl.solr.facet.SolrFacetHelper;
import org.alfresco.repo.search.impl.solr.facet.SolrFacetHelper.FacetLabelDisplayHandler;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
@@ -48,6 +51,7 @@ import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.util.ISO9075;
import org.alfresco.util.Pair;
import org.alfresco.util.PropertyCheck;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
@@ -56,6 +60,7 @@ import org.dom4j.io.SAXReader;
import org.jaxen.saxpath.base.XPathReader;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Scriptable;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.extensions.surf.util.ParameterCheck;
/**
@@ -71,7 +76,7 @@ import org.springframework.extensions.surf.util.ParameterCheck;
*
* @author Kevin Roast
*/
public class Search extends BaseScopableProcessorExtension
public class Search extends BaseScopableProcessorExtension implements InitializingBean
{
private static Log logger = LogFactory.getLog(Search.class);
@@ -85,7 +90,18 @@ public class Search extends BaseScopableProcessorExtension
protected Repository repository;
private SwitchableApplicationContextFactory searchSubsystem;
/** Solr facet helper */
private SolrFacetHelper solrFacetHelper;
@Override
public void afterPropertiesSet() throws Exception
{
PropertyCheck.mandatory(this, "services", services);
this.solrFacetHelper = new SolrFacetHelper(services);
}
/**
* Set the default store reference
*
@@ -694,6 +710,12 @@ public class Search extends BaseScopableProcessorExtension
{
sp.addFieldFacet(new FieldFacet("@" + field));
}
List<String> facetQueries = solrFacetHelper.getFacetQueries();
for (String fq : facetQueries)
{
sp.addFacetQuery(fq);
}
}
// error handling opions
@@ -905,15 +927,47 @@ public class Search extends BaseScopableProcessorExtension
if (f.getSecond() > 0)
{
String facetValue = f.getFirst();
Field field = getFieldType(ff.getField());
String label = (field == null) ? facetValue : field.getLabel(services, facetValue);
FacetLabelDisplayHandler handler = solrFacetHelper.getDisplayHandler(ff.getField());
String label = (handler == null) ? facetValue : handler.getDisplayLabel(facetValue).getSecond();
facets.add(new ScriptFacetResult(facetValue, label, f.getSecond()));
}
}
// store facet results per field
facetMeta.put(ff.getField(), facets);
}
Set<Entry<String, Integer>> facetQueries = results.getFacetQueries().entrySet();
Map<String, List<ScriptFacetResult>> facetQueryMeta = new HashMap<>(facetQueries.size());
for(Entry<String, Integer> entry : facetQueries)
{
// ignore zero hit facet queries
if (entry.getValue() > 0)
{
String key = entry.getKey();
// for example the key could be: {!afts}@{http://www.alfresco.org/model/content/1.0}created:[2013-10-29 TO 2014-04-29]
// qName => @{http://www.alfresco.org/model/content/1.0}created
// 7 => {!afts}
String qName = key.substring(7, key.lastIndexOf(':'));
// Retrieve the previous facet queries
List<ScriptFacetResult> fqs = facetQueryMeta.get(qName);
if (fqs == null)
{
fqs = new ArrayList<>();
}
FacetLabelDisplayHandler handler = solrFacetHelper.getDisplayHandler(qName);
Pair<String, String> valueLabelPair = (handler == null) ? new Pair<String, String>(qName,
key.substring(qName.length(), key.length())) : handler.getDisplayLabel(key);
fqs.add(new ScriptFacetResult(valueLabelPair.getFirst(), valueLabelPair.getSecond(), entry.getValue()));
// store facet query results per field
facetQueryMeta.put(qName, fqs);
}
}
meta.put("facets", facetMeta);
meta.put("facetQueries", facetQueryMeta);
}
catch (Throwable err)
{
@@ -961,83 +1015,4 @@ public class Search extends BaseScopableProcessorExtension
public String column;
public boolean asc;
}
/**
* @author Jamal Kaabi-Mofrad
*/
private enum Field
{
CREATOR("creator.__"), MODIFIER("modifier.__"), MIMETYPE("content.mimetype")
{
@Override
/*Package access level*/
String getLabel(ServiceRegistry services, String facetValue)
{
MimetypeService mimetypeService = services.getMimetypeService();
Map<String, String> mimetypes = mimetypeService.getDisplaysByMimetype();
String displayName = mimetypes.get(facetValue);
return displayName == null ? facetValue : displayName.trim();
}
};
private Field(String facetField)
{
this.facetField = facetField;
}
private String facetField;
private String getFacetField()
{
return facetField;
}
/**
* Default implementation which will return the full user name from
* the facetValue, if the facetValue represent a userID
*
* @param services the ServiceRegistry
* @param facetValue the facet value
* @return the full user name. If the user doesn't exist then, the
* {@code facetValue} will be returned.
*/
/*Package access level*/
String getLabel(ServiceRegistry services, String facetValue)
{
String name = null;
final NodeRef personRef = services.getPersonService().getPersonOrNull(facetValue);
if (personRef != null)
{
final NodeService nodeService = services.getNodeService();
final String firstName = (String) nodeService.getProperty(personRef, ContentModel.PROP_FIRSTNAME);
final String lastName = (String) nodeService.getProperty(personRef, ContentModel.PROP_LASTNAME);
name = (firstName != null ? firstName + " " : "") + (lastName != null ? lastName : "");
}
return name == null ? facetValue : name.trim();
}
}
/**
* Gets the facet field.
*
* @param facetField the facet field value
* @return the Field type
*/
private Field getFieldType(String facetField)
{
if (facetField == null)
{
return null;
}
for (Field val : Field.values())
{
if (facetField.endsWith(val.getFacetField()))
{
return val;
}
}
return null;
}
}

View File

@@ -21,6 +21,7 @@ package org.alfresco.repo.search;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
@@ -121,5 +122,10 @@ public abstract class AbstractResultSet implements ResultSet
return Collections.<Pair<String, Integer>>emptyList();
}
@Override
public Map<String, Integer> getFacetQueries()
{
return Collections.emptyMap();
}
}

View File

@@ -22,6 +22,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
@@ -164,4 +165,10 @@ public class EmptyResultSet implements ResultSet
{
return 0;
}
@Override
public Map<String, Integer> getFacetQueries()
{
return Collections.emptyMap();
}
}

View File

@@ -23,6 +23,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.alfresco.repo.search.impl.querymodel.Query;
import org.alfresco.service.cmr.dictionary.DictionaryService;
@@ -250,4 +251,10 @@ public class PagingLuceneResultSet implements ResultSet, Serializable
{
return wrapped.getNumberFound();
}
@Override
public Map<String, Integer> getFacetQueries()
{
return wrapped.getFacetQueries();
}
}

View File

@@ -23,6 +23,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.alfresco.repo.domain.node.NodeDAO;
import org.alfresco.repo.search.SimpleResultSetMetaData;
@@ -72,6 +73,8 @@ public class SolrJSONResultSet implements ResultSet
private HashMap<String, List<Pair<String, Integer>>> fieldFacets = new HashMap<String, List<Pair<String, Integer>>>(1);
private Map<String, Integer> facetQueries = new HashMap<String, Integer>();
private NodeDAO nodeDao;
private long lastIndexedTxId;
@@ -143,6 +146,16 @@ public class SolrJSONResultSet implements ResultSet
if(json.has("facet_counts"))
{
JSONObject facet_counts = json.getJSONObject("facet_counts");
if(facet_counts.has("facet_queries"))
{
JSONObject facet_queries = facet_counts.getJSONObject("facet_queries");
for(Iterator it = facet_queries.keys(); it.hasNext(); /**/)
{
String fq = (String) it.next();
Integer count =Integer.parseInt(facet_queries.getString(fq));
facetQueries.put(fq, count);
}
}
if(facet_counts.has("facet_fields"))
{
JSONObject facet_fields = facet_counts.getJSONObject("facet_fields");
@@ -391,4 +404,10 @@ public class SolrJSONResultSet implements ResultSet
{
return lastIndexedTxId;
}
@Override
public Map<String, Integer> getFacetQueries()
{
return Collections.unmodifiableMap(facetQueries);
}
}

View File

@@ -23,7 +23,6 @@ import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
@@ -348,6 +347,10 @@ public class SolrQueryHTTPClient implements BeanFactoryAware
}
}
for(String facetQuery : searchParameters.getFacetQueries())
{
url.append("&facet.query=").append(encoder.encode("{!afts}"+facetQuery, "UTF-8"));
}
}
// end of field factes

View File

@@ -0,0 +1,531 @@
/*
* Copyright (C) 2005-2014 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.search.impl.solr.facet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.util.Pair;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.joda.time.LocalDate;
/**
* A helper class to overcome the limitation of Solr 1.4 for dealing with facets.
* <p>
* Notice: probably this class or most of its functionalities will be removed
* when we upgrade to Solr 4
*
* @author Jamal Kaabi-Mofrad
*/
// TODO use Solr4 date math for date buckets...
public class SolrFacetHelper
{
private static Log logger = LogFactory.getLog(SolrFacetHelper.class);
private static final String FQ_NS_PREFIX = "@{http://www.alfresco.org/model/content/1.0}";
private static final String CREATED_FACET_QUERY_PREFIX = FQ_NS_PREFIX + "created:";
private static final String MODIFIED_FACET_QUERY_PREFIX = FQ_NS_PREFIX + "modified:";
private static final String CONTENT_SIZE_FACET_QUERY_PREFIX = FQ_NS_PREFIX + "content.size:";
// Content size buckets
private static final int KB = 1024;
private static final int MB = KB * 1024;
private static final int TINY = 10 * KB;
private static final int SMALL = 100 * KB;
private static final int MEDIUM = MB;
private static final int LARGE = 16 * MB;
private static final int HUGE = 128 * MB;
private static final String SIZE_BUCKETS_CACHE_KEY = "sizeBucketsCacheKey";
/** Facet value and facet query display label handlers */
private Map<String, FacetLabelDisplayHandler> displayHandlers;
/** Thread safe cache for storing the Date buckets facet query */
private BucketsCache<LocalDate, List<String>> fqDateCache = null;
/**
* Constructor
*
* @param serviceRegistry
*/
public SolrFacetHelper(ServiceRegistry serviceRegistry)
{
this.fqDateCache = new BucketsCache<>(new FacetQueryParamDateBuckets());
this.displayHandlers = new HashMap<>(6);
UserNameDisplayHandler userNameDisplayHandler = new UserNameDisplayHandler(serviceRegistry);
MimetypeDisplayHandler mimetypeDisplayHandler = new MimetypeDisplayHandler(serviceRegistry);
DateBucketsDisplayHandler createdDateBucketsDisplayHandler = new DateBucketsDisplayHandler("cm:created");
DateBucketsDisplayHandler modifiedDateBucketsDisplayHandler = new DateBucketsDisplayHandler("cm:modified");
ContentSizeBucketsDisplayHandler contentSizeBucketsDisplayHandler = new ContentSizeBucketsDisplayHandler("cm:content.size");
this.displayHandlers.put("@{http://www.alfresco.org/model/content/1.0}creator.__", userNameDisplayHandler);
this.displayHandlers.put("@{http://www.alfresco.org/model/content/1.0}modifier.__", userNameDisplayHandler);
this.displayHandlers.put("@{http://www.alfresco.org/model/content/1.0}content.mimetype", mimetypeDisplayHandler);
this.displayHandlers.put("@{http://www.alfresco.org/model/content/1.0}created", createdDateBucketsDisplayHandler);
this.displayHandlers.put("@{http://www.alfresco.org/model/content/1.0}modified", modifiedDateBucketsDisplayHandler);
this.displayHandlers.put("@{http://www.alfresco.org/model/content/1.0}content.size", contentSizeBucketsDisplayHandler);
}
/**
* Set the facet value and facet query display label handlers.
*
* @param displayHandlers the displayHandlers to set
*/
public void setDisplayHandlers(Map<String, FacetLabelDisplayHandler> displayHandlers)
{
this.displayHandlers = displayHandlers;
}
/**
* Gets predefined set of facet queries. Currently the facet queries are:
* <li>Created date buckets</li>
* <li>Modified date buckets</li>
* <li>Content size buckets</li>
*
* @return list of facet queries
*/
public List<String> getFacetQueries()
{
List<String> facetQueries = new ArrayList<>();
List<String> dateBuckets = null;
try
{
dateBuckets = fqDateCache.getRangeBuckets(LocalDate.now());
}
catch (Exception e)
{
logger.error(
"Error occured while trying to get the date buckets from the cache. Calculating the dates without the cache.", e);
dateBuckets = makeDateBuckets(LocalDate.now());
}
// Created and Modified dates facet queries
for (String bucket : dateBuckets)
{
facetQueries.add(CREATED_FACET_QUERY_PREFIX + '[' + bucket + ']');
facetQueries.add(MODIFIED_FACET_QUERY_PREFIX + '[' + bucket + ']');
}
// Content size facet query
for (String bucket : makeContentSizeBuckets())
{
facetQueries.add(CONTENT_SIZE_FACET_QUERY_PREFIX + '[' + bucket + ']');
}
return facetQueries;
}
/**
* Gets the appropriate facet display label handler
*
* @param qName
* @return the diplayHandler object or null if there is no handler
* registered for the given @{code qName}
*/
public FacetLabelDisplayHandler getDisplayHandler(String qName)
{
return displayHandlers.get(qName);
}
/**
* Creates Date buckets. The dates are in ISO8601 format (yyyy-MM-dd)
*
* @return list of date ranges. e.g. "2014-04-28 TO 2014-04-29"
*/
private static List<String> makeDateBuckets(LocalDate currentDate)
{
List<String> list = new ArrayList<>(5);
String nowStr = " TO " + currentDate.toString();
// Bucket => yesterday TO today
list.add(currentDate.minusDays(1).toString() + nowStr);
// Bucket => Last week TO today
list.add(currentDate.minusWeeks(1).toString() + nowStr);
// Bucket => Last month TO today
list.add(currentDate.minusMonths(1).toString() + nowStr);
// Bucket => Last 6 months TO today
list.add(currentDate.minusMonths(6).toString() + nowStr);
// Bucket => Last year TO today
list.add(currentDate.minusYears(1).toString() + nowStr);
return list;
}
/**
* Creates display name for the Date buckets.
*
* @return Map of {@literal <date range, display label key>}
*/
private static Map<String, String> makeDateBucketsDisplayLabel(LocalDate date)
{
List<String> dateBuckets = makeDateBuckets(date);
Map<String, String> bucketDisplayName = new HashMap<>(5);
if (dateBuckets.size() != 5)
{
throw new AlfrescoRuntimeException("Date buckets size does not match the bucket display label size!");
}
bucketDisplayName.put(dateBuckets.get(0), "faceted-search.date.one-day.label");
bucketDisplayName.put(dateBuckets.get(1), "faceted-search.date.one-week.label");
bucketDisplayName.put(dateBuckets.get(2), "faceted-search.date.one-month.label");
bucketDisplayName.put(dateBuckets.get(3), "faceted-search.date.six-months.label");
bucketDisplayName.put(dateBuckets.get(4), "faceted-search.date.one-year.label");
return bucketDisplayName;
}
/**
* Creates Content size buckets
*
* @return list of size ranges. e.g. "0 TO 1024"
*/
private static List<String> makeContentSizeBuckets()
{
List<String> sizeBuckets = new ArrayList<>(6);
sizeBuckets.add("0 TO " + TINY);
sizeBuckets.add(TINY + " TO " + SMALL);
sizeBuckets.add(SMALL + " TO " + MEDIUM);
sizeBuckets.add(MEDIUM + " TO " + LARGE);
sizeBuckets.add(LARGE + " TO " + HUGE);
sizeBuckets.add(HUGE + " TO MAX");
return sizeBuckets;
}
/**
* Creates display name for the Content size buckets.
*
* @return Map of {@literal <size range, display label key>}
*/
private static Map<String, String> makeContentSizeBucketsDisplayLabel()
{
List<String> sizeBuckets = makeContentSizeBuckets();
Map<String, String> bucketDisplayName = new HashMap<>(6);
if (sizeBuckets.size() != 6)
{
throw new AlfrescoRuntimeException("Content size buckets size does not match the bucket display label size!");
}
bucketDisplayName.put(sizeBuckets.get(0), "faceted-search.size.0-10KB.label");
bucketDisplayName.put(sizeBuckets.get(1), "faceted-search.size.10-100KB.label");
bucketDisplayName.put(sizeBuckets.get(2), "faceted-search.size.100KB-1MB.label");
bucketDisplayName.put(sizeBuckets.get(3), "faceted-search.size.1-16MB.label");
bucketDisplayName.put(sizeBuckets.get(4), "faceted-search.size.16-128MB.label");
bucketDisplayName.put(sizeBuckets.get(5), "faceted-search.size.over128.label");
return bucketDisplayName;
}
/**
* Single value cache for date and size buckets.
*
* @author Jamal Kaabi-Mofrad
*/
private static class BucketsCache<K, V>
{
private final ConcurrentMap<K, Future<V>> cache = new ConcurrentHashMap<>();
private final Buckets<K, V> buckets;
public BucketsCache(Buckets<K, V> buckets)
{
this.buckets = buckets;
}
public V getRangeBuckets(final K arg) throws Exception
{
while (true)
{
Future<V> future = cache.get(arg);
// first checks to see if the buckets computation has been started
if (future == null)
{
Callable<V> result = new Callable<V>()
{
public V call() throws Exception
{
// remove the previous entry
Set<K> keys = cache.keySet();
for (K key : keys)
{
if (!key.equals(arg))
{
cache.remove(key);
}
}
return buckets.compute(arg);
}
};
// If the calculation has been started, creates a
// FutureTask, registers it in the Map, and starts the computation
FutureTask<V> futureTask = new FutureTask<>(result);
future = cache.putIfAbsent(arg, futureTask);
if (future == null)
{
future = futureTask;
futureTask.run();
}
}
try
{
return future.get();
}
catch (CancellationException ce)
{
// Removes cache pollution. If the calculation is cancelled
// or failed. As caching a Future instead of a value creates
// the possibility of cache pollution
cache.remove(arg, future);
}
catch (ExecutionException e)
{
new IllegalStateException(e);
}
}
}
}
/**
* Interface to be implemented by classes that wish to create buckets.
*
* @author Jamal Kaabi-Mofrad
*/
private static interface Buckets<K, V>
{
V compute(K arg) throws Exception;
}
/**
* A simple implementation which creates Date buckets for the facet query.
*
* @author Jamal Kaabi-Mofrad
*/
private static class FacetQueryParamDateBuckets implements Buckets<LocalDate, List<String>>
{
@Override
public List<String> compute(LocalDate localDate) throws Exception
{
return makeDateBuckets(localDate);
}
}
/**
* A simple implementation which creates display label for the Date buckets
* from the facet query result.
*
* @author Jamal Kaabi-Mofrad
*/
private static class FacetQueryResultDateBuckets implements Buckets<LocalDate, Map<String, String>>
{
@Override
public Map<String, String> compute(LocalDate localDate) throws Exception
{
return makeDateBucketsDisplayLabel(localDate);
}
}
/**
* A simple implementation which creates display label for the Content size
* buckets from the facet query result.
*
* @author Jamal Kaabi-Mofrad
*/
private static class FacetQueryResultContentSizeBuckets implements Buckets<String, Map<String, String>>
{
@Override
public Map<String, String> compute(String arg) throws Exception
{
return makeContentSizeBucketsDisplayLabel();
}
}
/**
* Solr facet value and facet query result display label handler
*
* @author Jamal Kaabi-Mofrad
*/
public static interface FacetLabelDisplayHandler
{
Pair<String, String> getDisplayLabel(String value);
}
/**
* A simple handler to get the full user name from the userID
*
* @author Jamal Kaabi-Mofrad
*/
public static class UserNameDisplayHandler implements FacetLabelDisplayHandler
{
private final PersonService personService;
private final NodeService nodeService;
public UserNameDisplayHandler(ServiceRegistry services)
{
this.personService = services.getPersonService();
this.nodeService = services.getNodeService();
}
@Override
public Pair<String, String> getDisplayLabel(String value)
{
String name = null;
final NodeRef personRef = personService.getPersonOrNull(value);
if (personRef != null)
{
final String firstName = (String) nodeService.getProperty(personRef, ContentModel.PROP_FIRSTNAME);
final String lastName = (String) nodeService.getProperty(personRef, ContentModel.PROP_LASTNAME);
name = (firstName != null ? firstName + " " : "") + (lastName != null ? lastName : "");
}
return new Pair<String, String>(value, name == null ? value : name.trim());
}
}
/**
* A simple handler to get the Mimetype display label.
*
* @author Jamal Kaabi-Mofrad
*/
public static class MimetypeDisplayHandler implements FacetLabelDisplayHandler
{
private final MimetypeService mimetypeService;
public MimetypeDisplayHandler(ServiceRegistry services)
{
this.mimetypeService = services.getMimetypeService();
}
@Override
public Pair<String, String> getDisplayLabel(String value)
{
Map<String, String> mimetypes = mimetypeService.getDisplaysByMimetype();
String displayName = mimetypes.get(value);
return new Pair<String, String>(value, displayName == null ? value : displayName.trim());
}
}
/**
* A simple handler to get the appropriate display label for the date buckets.
*
* @author Jamal Kaabi-Mofrad
*/
public static class DateBucketsDisplayHandler implements FacetLabelDisplayHandler
{
private final BucketsCache<LocalDate, Map<String, String>> cache = new BucketsCache<>(
new FacetQueryResultDateBuckets());
private final String fq;
public DateBucketsDisplayHandler(String fq)
{
this.fq = fq;
}
@Override
public Pair<String, String> getDisplayLabel(String value)
{
Map<String, String> dateBuckets = null;
String dateRange = value.substring(value.indexOf('[') + 1, value.length() - 1);
String[] lowerUpperDates = dateRange.split("\\sTO\\s");
LocalDate date = LocalDate.parse(lowerUpperDates[1]);
try
{
dateBuckets = cache.getRangeBuckets(date);
}
catch (Exception e)
{
logger.error(
"Error occurred while trying to get the date buckets from the cache. Calculating the dates without the cache.", e);
dateBuckets = makeDateBucketsDisplayLabel(date);
}
String newValue = fq + ":\"" + lowerUpperDates[0] + "\"..\"" + lowerUpperDates[1] + '"';
String label = dateBuckets.get(dateRange);
return new Pair<String, String>(newValue, label);
}
}
/**
* A simple handler to get the appropriate display label for the content size buckets.
*
* @author Jamal Kaabi-Mofrad
*/
public static class ContentSizeBucketsDisplayHandler implements FacetLabelDisplayHandler
{
private final BucketsCache<String, Map<String, String>> cache = new BucketsCache<>(
new FacetQueryResultContentSizeBuckets());
private final String fq;
public ContentSizeBucketsDisplayHandler(String fq)
{
this.fq = fq;
}
@Override
public Pair<String, String> getDisplayLabel(String value)
{
String sizeRange = value.substring(value.indexOf('[') + 1, value.length() - 1);
String[] lowerUppperSize = sizeRange.split("\\sTO\\s");
Map<String, String> sizeBuckets;
try
{
sizeBuckets = cache.getRangeBuckets(SIZE_BUCKETS_CACHE_KEY);
}
catch (Exception e)
{
logger.error(
"Error occurred while trying to get the content size buckets from the cache. Calculating the size without the cache.", e);
sizeBuckets = makeContentSizeBucketsDisplayLabel();
}
String newValue = fq + ":\"" + lowerUppperSize[0] + "\"..\"" + lowerUppperSize[1] + '"';
String label = sizeBuckets.get(sizeRange);
return new Pair<String, String>(newValue, label);
}
}
}

View File

@@ -20,6 +20,7 @@ package org.alfresco.repo.search.results;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
@@ -156,6 +157,12 @@ public class ResultSetSPIWrapper<ROW extends ResultSetRow, MD extends ResultSetM
return wrapped.getFieldFacet(field);
}
@Override
public Map<String, Integer> getFacetQueries()
{
return wrapped.getFacetQueries();
}
private static class WrappedIterator<ROW extends ResultSetRow> implements Iterator<ResultSetRow>
{
private Iterator<ROW> wrapped;

View File

@@ -26,6 +26,7 @@ import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.alfresco.repo.search.SearcherException;
import org.alfresco.repo.search.impl.lucene.LuceneResultSetRow;
@@ -932,5 +933,11 @@ public class SortedResultSet implements ResultSet
{
return resultSet.getNumberFound();
}
@Override
public Map<String, Integer> getFacetQueries()
{
return resultSet.getFacetQueries();
}
}

View File

@@ -23,6 +23,7 @@ import java.util.BitSet;
import java.util.Collections;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import org.alfresco.repo.search.ResultSetRowIterator;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
@@ -336,4 +337,10 @@ public class FilteringResultSet extends ACLEntryAfterInvocationProvider implemen
{
return inclusionMask.cardinality();
}
@Override
public Map<String, Integer> getFacetQueries()
{
return unfiltered.getFacetQueries();
}
}