mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
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:
@@ -348,4 +348,10 @@ public class CMISResultSetImpl implements CMISResultSet, Serializable
|
|||||||
}
|
}
|
||||||
throw new IllegalStateException();
|
throw new IllegalStateException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Integer> getFacetQueries()
|
||||||
|
{
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -353,4 +353,10 @@ public class CMISResultSet implements ResultSetSPI<CMISResultSetRow, CMISResultS
|
|||||||
}
|
}
|
||||||
throw new IllegalStateException();
|
throw new IllegalStateException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Integer> getFacetQueries()
|
||||||
|
{
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -26,14 +26,17 @@ import java.util.HashMap;
|
|||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.alfresco.error.AlfrescoRuntimeException;
|
import org.alfresco.error.AlfrescoRuntimeException;
|
||||||
import org.alfresco.model.ContentModel;
|
import org.alfresco.model.ContentModel;
|
||||||
import org.alfresco.repo.management.subsystems.SwitchableApplicationContextFactory;
|
import org.alfresco.repo.management.subsystems.SwitchableApplicationContextFactory;
|
||||||
import org.alfresco.repo.model.Repository;
|
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.ServiceRegistry;
|
||||||
import org.alfresco.service.cmr.repository.ContentReader;
|
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.NodeRef;
|
||||||
import org.alfresco.service.cmr.repository.NodeService;
|
import org.alfresco.service.cmr.repository.NodeService;
|
||||||
import org.alfresco.service.cmr.repository.StoreRef;
|
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.service.cmr.security.PermissionService;
|
||||||
import org.alfresco.util.ISO9075;
|
import org.alfresco.util.ISO9075;
|
||||||
import org.alfresco.util.Pair;
|
import org.alfresco.util.Pair;
|
||||||
|
import org.alfresco.util.PropertyCheck;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.dom4j.Document;
|
import org.dom4j.Document;
|
||||||
@@ -56,6 +60,7 @@ import org.dom4j.io.SAXReader;
|
|||||||
import org.jaxen.saxpath.base.XPathReader;
|
import org.jaxen.saxpath.base.XPathReader;
|
||||||
import org.mozilla.javascript.Context;
|
import org.mozilla.javascript.Context;
|
||||||
import org.mozilla.javascript.Scriptable;
|
import org.mozilla.javascript.Scriptable;
|
||||||
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
import org.springframework.extensions.surf.util.ParameterCheck;
|
import org.springframework.extensions.surf.util.ParameterCheck;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -71,7 +76,7 @@ import org.springframework.extensions.surf.util.ParameterCheck;
|
|||||||
*
|
*
|
||||||
* @author Kevin Roast
|
* @author Kevin Roast
|
||||||
*/
|
*/
|
||||||
public class Search extends BaseScopableProcessorExtension
|
public class Search extends BaseScopableProcessorExtension implements InitializingBean
|
||||||
{
|
{
|
||||||
private static Log logger = LogFactory.getLog(Search.class);
|
private static Log logger = LogFactory.getLog(Search.class);
|
||||||
|
|
||||||
@@ -86,6 +91,17 @@ public class Search extends BaseScopableProcessorExtension
|
|||||||
|
|
||||||
private SwitchableApplicationContextFactory searchSubsystem;
|
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
|
* Set the default store reference
|
||||||
*
|
*
|
||||||
@@ -694,6 +710,12 @@ public class Search extends BaseScopableProcessorExtension
|
|||||||
{
|
{
|
||||||
sp.addFieldFacet(new FieldFacet("@" + field));
|
sp.addFieldFacet(new FieldFacet("@" + field));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<String> facetQueries = solrFacetHelper.getFacetQueries();
|
||||||
|
for (String fq : facetQueries)
|
||||||
|
{
|
||||||
|
sp.addFacetQuery(fq);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// error handling opions
|
// error handling opions
|
||||||
@@ -905,15 +927,47 @@ public class Search extends BaseScopableProcessorExtension
|
|||||||
if (f.getSecond() > 0)
|
if (f.getSecond() > 0)
|
||||||
{
|
{
|
||||||
String facetValue = f.getFirst();
|
String facetValue = f.getFirst();
|
||||||
Field field = getFieldType(ff.getField());
|
FacetLabelDisplayHandler handler = solrFacetHelper.getDisplayHandler(ff.getField());
|
||||||
String label = (field == null) ? facetValue : field.getLabel(services, facetValue);
|
String label = (handler == null) ? facetValue : handler.getDisplayLabel(facetValue).getSecond();
|
||||||
|
|
||||||
facets.add(new ScriptFacetResult(facetValue, label, f.getSecond()));
|
facets.add(new ScriptFacetResult(facetValue, label, f.getSecond()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// store facet results per field
|
// store facet results per field
|
||||||
facetMeta.put(ff.getField(), facets);
|
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("facets", facetMeta);
|
||||||
|
meta.put("facetQueries", facetQueryMeta);
|
||||||
}
|
}
|
||||||
catch (Throwable err)
|
catch (Throwable err)
|
||||||
{
|
{
|
||||||
@@ -961,83 +1015,4 @@ public class Search extends BaseScopableProcessorExtension
|
|||||||
public String column;
|
public String column;
|
||||||
public boolean asc;
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -21,6 +21,7 @@ package org.alfresco.repo.search;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||||
import org.alfresco.service.cmr.repository.NodeRef;
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
@@ -121,5 +122,10 @@ public abstract class AbstractResultSet implements ResultSet
|
|||||||
return Collections.<Pair<String, Integer>>emptyList();
|
return Collections.<Pair<String, Integer>>emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Integer> getFacetQueries()
|
||||||
|
{
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -22,6 +22,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||||
import org.alfresco.service.cmr.repository.NodeRef;
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
@@ -164,4 +165,10 @@ public class EmptyResultSet implements ResultSet
|
|||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Integer> getFacetQueries()
|
||||||
|
{
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -23,6 +23,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.alfresco.repo.search.impl.querymodel.Query;
|
import org.alfresco.repo.search.impl.querymodel.Query;
|
||||||
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
||||||
@@ -250,4 +251,10 @@ public class PagingLuceneResultSet implements ResultSet, Serializable
|
|||||||
{
|
{
|
||||||
return wrapped.getNumberFound();
|
return wrapped.getNumberFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Integer> getFacetQueries()
|
||||||
|
{
|
||||||
|
return wrapped.getFacetQueries();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -23,6 +23,7 @@ import java.util.Collections;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.alfresco.repo.domain.node.NodeDAO;
|
import org.alfresco.repo.domain.node.NodeDAO;
|
||||||
import org.alfresco.repo.search.SimpleResultSetMetaData;
|
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 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 NodeDAO nodeDao;
|
||||||
|
|
||||||
private long lastIndexedTxId;
|
private long lastIndexedTxId;
|
||||||
@@ -143,6 +146,16 @@ public class SolrJSONResultSet implements ResultSet
|
|||||||
if(json.has("facet_counts"))
|
if(json.has("facet_counts"))
|
||||||
{
|
{
|
||||||
JSONObject facet_counts = json.getJSONObject("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"))
|
if(facet_counts.has("facet_fields"))
|
||||||
{
|
{
|
||||||
JSONObject facet_fields = facet_counts.getJSONObject("facet_fields");
|
JSONObject facet_fields = facet_counts.getJSONObject("facet_fields");
|
||||||
@@ -391,4 +404,10 @@ public class SolrJSONResultSet implements ResultSet
|
|||||||
{
|
{
|
||||||
return lastIndexedTxId;
|
return lastIndexedTxId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Integer> getFacetQueries()
|
||||||
|
{
|
||||||
|
return Collections.unmodifiableMap(facetQueries);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -23,7 +23,6 @@ import java.io.IOException;
|
|||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
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
|
// end of field factes
|
||||||
|
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -20,6 +20,7 @@ package org.alfresco.repo.search.results;
|
|||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||||
import org.alfresco.service.cmr.repository.NodeRef;
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
@@ -156,6 +157,12 @@ public class ResultSetSPIWrapper<ROW extends ResultSetRow, MD extends ResultSetM
|
|||||||
return wrapped.getFieldFacet(field);
|
return wrapped.getFieldFacet(field);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Integer> getFacetQueries()
|
||||||
|
{
|
||||||
|
return wrapped.getFacetQueries();
|
||||||
|
}
|
||||||
|
|
||||||
private static class WrappedIterator<ROW extends ResultSetRow> implements Iterator<ResultSetRow>
|
private static class WrappedIterator<ROW extends ResultSetRow> implements Iterator<ResultSetRow>
|
||||||
{
|
{
|
||||||
private Iterator<ROW> wrapped;
|
private Iterator<ROW> wrapped;
|
||||||
|
@@ -26,6 +26,7 @@ import java.util.Comparator;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.alfresco.repo.search.SearcherException;
|
import org.alfresco.repo.search.SearcherException;
|
||||||
import org.alfresco.repo.search.impl.lucene.LuceneResultSetRow;
|
import org.alfresco.repo.search.impl.lucene.LuceneResultSetRow;
|
||||||
@@ -933,4 +934,10 @@ public class SortedResultSet implements ResultSet
|
|||||||
return resultSet.getNumberFound();
|
return resultSet.getNumberFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Integer> getFacetQueries()
|
||||||
|
{
|
||||||
|
return resultSet.getFacetQueries();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -23,6 +23,7 @@ import java.util.BitSet;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.ListIterator;
|
import java.util.ListIterator;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.alfresco.repo.search.ResultSetRowIterator;
|
import org.alfresco.repo.search.ResultSetRowIterator;
|
||||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||||
@@ -336,4 +337,10 @@ public class FilteringResultSet extends ACLEntryAfterInvocationProvider implemen
|
|||||||
{
|
{
|
||||||
return inclusionMask.cardinality();
|
return inclusionMask.cardinality();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Integer> getFacetQueries()
|
||||||
|
{
|
||||||
|
return unfiltered.getFacetQueries();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user