mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
- Refactored facet display handlers
- Changed date buckets implementation to use Solr Date math - Added Site title display handler as well as a test for it - Reverted back Neil’s work to inject the "special" facet IDs (SITE, TAG etc) from the solr-facets-context.xml as I re-wrote the SolrFacetHelper class. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@85946 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -113,6 +113,12 @@
|
||||
<property name="repositoryHelper">
|
||||
<ref bean="repositoryHelper"/>
|
||||
</property>
|
||||
<property name="solrFacetHelper">
|
||||
<ref bean="facet.solrFacetHelper"/>
|
||||
</property>
|
||||
<property name="facetLabelDisplayHandlerRegistry">
|
||||
<ref bean="facet.facetLabelDisplayHandlerRegistry"/>
|
||||
</property>
|
||||
<property name="storeUrl">
|
||||
<value>${spaces.store}</value>
|
||||
</property>
|
||||
|
@@ -43,4 +43,118 @@
|
||||
<value>${solr_facets.root}</value>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- Facet Label Display Handler Registry -->
|
||||
<bean id="facet.facetLabelDisplayHandlerRegistry" class="org.alfresco.repo.search.impl.solr.facet.handler.FacetLabelDisplayHandlerRegistry" />
|
||||
|
||||
<!-- Abstract bean, defining base definition for all facet label display handlers -->
|
||||
<bean id="baseFacetLabelDisplayHandler" class="org.alfresco.repo.search.impl.solr.facet.handler.AbstractFacetLabelDisplayHandler"
|
||||
abstract="true" init-method="register">
|
||||
<property name="registry">
|
||||
<ref bean="facet.facetLabelDisplayHandlerRegistry" />
|
||||
</property>
|
||||
<property name="serviceRegistry">
|
||||
<ref bean="ServiceRegistry" />
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="facet.mimetypeDisplayHandler" class="org.alfresco.repo.search.impl.solr.facet.handler.MimetypeDisplayHandler" parent="baseFacetLabelDisplayHandler" >
|
||||
<constructor-arg>
|
||||
<set>
|
||||
<value>@{http://www.alfresco.org/model/content/1.0}content.mimetype</value>
|
||||
</set>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
<bean id="facet.userNameDisplayHandler" class="org.alfresco.repo.search.impl.solr.facet.handler.UserNameDisplayHandler" parent="baseFacetLabelDisplayHandler" >
|
||||
<constructor-arg>
|
||||
<set>
|
||||
<value>@{http://www.alfresco.org/model/content/1.0}creator</value>
|
||||
<value>@{http://www.alfresco.org/model/content/1.0}modifier</value>
|
||||
</set>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
<bean id="facet.siteTitleDisplayHandler" class="org.alfresco.repo.search.impl.solr.facet.handler.SiteTitleDisplayHandler" parent="baseFacetLabelDisplayHandler" >
|
||||
<constructor-arg>
|
||||
<set>
|
||||
<value>SITE</value>
|
||||
</set>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
<bean id="facet.contentSizeBucketsDisplayHandler" class="org.alfresco.repo.search.impl.solr.facet.handler.ContentSizeBucketsDisplayHandler" parent="baseFacetLabelDisplayHandler" >
|
||||
<constructor-arg index="0">
|
||||
<set>
|
||||
<value>@{http://www.alfresco.org/model/content/1.0}content.size</value>
|
||||
</set>
|
||||
</constructor-arg>
|
||||
<constructor-arg index="1">
|
||||
<bean class="org.springframework.beans.factory.config.MapFactoryBean">
|
||||
<property name="targetMapClass">
|
||||
<value>java.util.LinkedHashMap</value>
|
||||
</property>
|
||||
<property name="sourceMap">
|
||||
<map>
|
||||
<entry key="[0 TO 10240]" value="faceted-search.size.0-10KB.label" />
|
||||
<entry key="[10240 TO 102400]" value="faceted-search.size.10-100KB.label" />
|
||||
<entry key="[102400 TO 1048576]" value="faceted-search.size.100KB-1MB.label" />
|
||||
<entry key="[1048576 TO 16777216]" value="faceted-search.size.1-16MB.label" />
|
||||
<entry key="[16777216 TO 134217728]" value="faceted-search.size.16-128MB.label" />
|
||||
<entry key="[134217728 TO MAX]" value="faceted-search.size.over128.label" />
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
<bean id="facet.dateBucketsDisplayHandler" class="org.alfresco.repo.search.impl.solr.facet.handler.DateBucketsDisplayHandler" parent="baseFacetLabelDisplayHandler" >
|
||||
<constructor-arg index="0">
|
||||
<set>
|
||||
<value>@{http://www.alfresco.org/model/content/1.0}created</value>
|
||||
<value>@{http://www.alfresco.org/model/content/1.0}modified</value>
|
||||
</set>
|
||||
</constructor-arg>
|
||||
<constructor-arg index="1">
|
||||
<bean class="org.springframework.beans.factory.config.MapFactoryBean">
|
||||
<property name="targetMapClass">
|
||||
<value>java.util.LinkedHashMap</value>
|
||||
</property>
|
||||
<property name="sourceMap">
|
||||
<map>
|
||||
<!-- Bucket => yesterday TO today -->
|
||||
<entry key="[NOW/DAY-1DAY TO NOW/DAY+1DAY]" value="faceted-search.date.one-day.label" />
|
||||
<!-- Bucket => Last week TO today -->
|
||||
<entry key="[NOW/DAY-7DAYS TO NOW/DAY+1DAY]" value="faceted-search.date.one-week.label" />
|
||||
<!-- Bucket => Last month TO today -->
|
||||
<entry key="[NOW/DAY-1MONTH TO NOW/DAY+1DAY]" value="faceted-search.date.one-month.label" />
|
||||
<!-- Bucket => Last 6 months TO today -->
|
||||
<entry key="[NOW/DAY-6MONTHS TO NOW/DAY+1DAY]" value="faceted-search.date.six-months.label" />
|
||||
<!-- Bucket => Last year TO today -->
|
||||
<entry key="[NOW/DAY-1YEAR TO NOW/DAY+1DAY]" value="faceted-search.date.one-year.label" />
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
<bean id="facet.solrFacetHelper" class="org.alfresco.repo.search.impl.solr.facet.SolrFacetHelper" >
|
||||
<constructor-arg>
|
||||
<list>
|
||||
<ref bean="facet.contentSizeBucketsDisplayHandler" />
|
||||
<ref bean="facet.dateBucketsDisplayHandler" />
|
||||
</list>
|
||||
</constructor-arg>
|
||||
<property name="specialFacetIds">
|
||||
<set>
|
||||
<value>SITE</value>
|
||||
<value>TAG</value>
|
||||
<value>ANCESTOR</value>
|
||||
<value>PARENT</value>
|
||||
<value>ASPECT</value>
|
||||
<value>TYPE</value>
|
||||
<value>OWNER</value>
|
||||
</set>
|
||||
</property>
|
||||
</bean>
|
||||
</beans>
|
@@ -15,41 +15,41 @@ default.cm\:content.mimetype.scope=ALL
|
||||
default.cm\:content.mimetype.scopedSites=
|
||||
default.cm\:content.mimetype.isEnabled=true
|
||||
|
||||
# Field-Facet-Qname => cm:description.__
|
||||
default.cm\:description.__.filterID=filter_description
|
||||
default.cm\:description.__.displayName=faceted-search.facet-menu.facet.description
|
||||
default.cm\:description.__.displayControl=alfresco/search/FacetFilters
|
||||
default.cm\:description.__.maxFilters=5
|
||||
default.cm\:description.__.hitThreshold=1
|
||||
default.cm\:description.__.minFilterValueLength=4
|
||||
default.cm\:description.__.sortBy=DESCENDING
|
||||
default.cm\:description.__.scope=ALL
|
||||
default.cm\:description.__.scopedSites=
|
||||
default.cm\:description.__.isEnabled=false
|
||||
# Field-Facet-Qname => cm:description
|
||||
default.cm\:description.filterID=filter_description
|
||||
default.cm\:description.displayName=faceted-search.facet-menu.facet.description
|
||||
default.cm\:description.displayControl=alfresco/search/FacetFilters
|
||||
default.cm\:description.maxFilters=5
|
||||
default.cm\:description.hitThreshold=1
|
||||
default.cm\:description.minFilterValueLength=4
|
||||
default.cm\:description.sortBy=DESCENDING
|
||||
default.cm\:description.scope=ALL
|
||||
default.cm\:description.scopedSites=
|
||||
default.cm\:description.isEnabled=false
|
||||
|
||||
# Field-Facet-Qname => cm:creator.__.u
|
||||
default.cm\:creator.__.u.filterID=filter_creator
|
||||
default.cm\:creator.__.u.displayName=faceted-search.facet-menu.facet.creator
|
||||
default.cm\:creator.__.u.displayControl=alfresco/search/FacetFilters
|
||||
default.cm\:creator.__.u.maxFilters=5
|
||||
default.cm\:creator.__.u.hitThreshold=1
|
||||
default.cm\:creator.__.u.minFilterValueLength=4
|
||||
default.cm\:creator.__.u.sortBy=ALPHABETICALLY
|
||||
default.cm\:creator.__.u.scope=ALL
|
||||
default.cm\:creator.__.u.scopedSites=
|
||||
default.cm\:creator.__.u.isEnabled=true
|
||||
# Field-Facet-Qname => cm:creator
|
||||
default.cm\:creator.filterID=filter_creator
|
||||
default.cm\:creator.displayName=faceted-search.facet-menu.facet.creator
|
||||
default.cm\:creator.displayControl=alfresco/search/FacetFilters
|
||||
default.cm\:creator.maxFilters=5
|
||||
default.cm\:creator.hitThreshold=1
|
||||
default.cm\:creator.minFilterValueLength=4
|
||||
default.cm\:creator.sortBy=ALPHABETICALLY
|
||||
default.cm\:creator.scope=ALL
|
||||
default.cm\:creator.scopedSites=
|
||||
default.cm\:creator.isEnabled=true
|
||||
|
||||
# Field-Facet-Qname => cm:modifier.__.u
|
||||
default.cm\:modifier.__.u.filterID=filter_modifier
|
||||
default.cm\:modifier.__.u.displayName=faceted-search.facet-menu.facet.modifier
|
||||
default.cm\:modifier.__.u.displayControl=alfresco/search/FacetFilters
|
||||
default.cm\:modifier.__.u.maxFilters=5
|
||||
default.cm\:modifier.__.u.hitThreshold=1
|
||||
default.cm\:modifier.__.u.minFilterValueLength=4
|
||||
default.cm\:modifier.__.u.sortBy=ALPHABETICALLY
|
||||
default.cm\:modifier.__.u.scope=ALL
|
||||
default.cm\:modifier.__.u.scopedSites=
|
||||
default.cm\:modifier.__.u.isEnabled=true
|
||||
# Field-Facet-Qname => cm:modifier
|
||||
default.cm\:modifier.filterID=filter_modifier
|
||||
default.cm\:modifier.displayName=faceted-search.facet-menu.facet.modifier
|
||||
default.cm\:modifier.displayControl=alfresco/search/FacetFilters
|
||||
default.cm\:modifier.maxFilters=5
|
||||
default.cm\:modifier.hitThreshold=1
|
||||
default.cm\:modifier.minFilterValueLength=4
|
||||
default.cm\:modifier.sortBy=ALPHABETICALLY
|
||||
default.cm\:modifier.scope=ALL
|
||||
default.cm\:modifier.scopedSites=
|
||||
default.cm\:modifier.isEnabled=true
|
||||
|
||||
# Field-Facet-Qname => cm:created
|
||||
default.cm\:created.filterID=filter_created
|
||||
@@ -62,7 +62,6 @@ default.cm\:created.sortBy=ALPHABETICALLY
|
||||
default.cm\:created.scope=ALL
|
||||
default.cm\:created.scopedSites=
|
||||
default.cm\:created.isEnabled=true
|
||||
default.cm\:created.EXTRA-PROP.blockIncludeFacetRequest=true
|
||||
|
||||
# Field-Facet-Qname => cm:modified
|
||||
default.cm\:modified.filterID=filter_modified
|
||||
@@ -75,7 +74,6 @@ default.cm\:modified.sortBy=ALPHABETICALLY
|
||||
default.cm\:modified.scope=ALL
|
||||
default.cm\:modified.scopedSites=
|
||||
default.cm\:modified.isEnabled=true
|
||||
default.cm\:modified.EXTRA-PROP.blockIncludeFacetRequest=true
|
||||
|
||||
# Field-Facet-Qname => cm:content.size
|
||||
default.cm\:content.size.filterID=filter_content_size
|
||||
@@ -88,4 +86,3 @@ default.cm\:content.size.sortBy=ALPHABETICALLY
|
||||
default.cm\:content.size.scope=ALL
|
||||
default.cm\:content.size.scopedSites=
|
||||
default.cm\:content.size.isEnabled=true
|
||||
default.cm\:content.size.EXTRA-PROP.blockIncludeFacetRequest=true
|
||||
|
@@ -34,8 +34,9 @@ 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.FacetLabel;
|
||||
import org.alfresco.repo.search.impl.solr.facet.SolrFacetHelper.FacetLabelDisplayHandler;
|
||||
import org.alfresco.repo.search.impl.solr.facet.handler.FacetLabel;
|
||||
import org.alfresco.repo.search.impl.solr.facet.handler.FacetLabelDisplayHandler;
|
||||
import org.alfresco.repo.search.impl.solr.facet.handler.FacetLabelDisplayHandlerRegistry;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.repository.ContentReader;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
@@ -96,12 +97,14 @@ public class Search extends BaseScopableProcessorExtension implements Initializi
|
||||
/** Solr facet helper */
|
||||
private SolrFacetHelper solrFacetHelper;
|
||||
|
||||
private FacetLabelDisplayHandlerRegistry facetLabelDisplayHandlerRegistry;
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception
|
||||
{
|
||||
PropertyCheck.mandatory(this, "services", services);
|
||||
this.solrFacetHelper = new SolrFacetHelper(services);
|
||||
PropertyCheck.mandatory(this, "solrFacetHelper", solrFacetHelper);
|
||||
PropertyCheck.mandatory(this, "facetLabelDisplayHandlerRegistry", facetLabelDisplayHandlerRegistry);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -146,6 +149,20 @@ public class Search extends BaseScopableProcessorExtension implements Initializi
|
||||
|
||||
// JavaScript API
|
||||
|
||||
/**
|
||||
* @param solrFacetHelper the solrFacetHelper to set
|
||||
*/
|
||||
public void setSolrFacetHelper(SolrFacetHelper solrFacetHelper)
|
||||
{
|
||||
this.solrFacetHelper = solrFacetHelper;
|
||||
}
|
||||
/**
|
||||
* @param facetLabelDisplayHandlerRegistry the facetLabelDisplayHandlerRegistry to set
|
||||
*/
|
||||
public void setFacetLabelDisplayHandlerRegistry(FacetLabelDisplayHandlerRegistry facetLabelDisplayHandlerRegistry)
|
||||
{
|
||||
this.facetLabelDisplayHandlerRegistry = facetLabelDisplayHandlerRegistry;
|
||||
}
|
||||
public String getSearchSubsystem()
|
||||
{
|
||||
return (searchSubsystem == null) ? "" : searchSubsystem.getCurrentSourceBeanName();
|
||||
@@ -716,6 +733,14 @@ public class Search extends BaseScopableProcessorExtension implements Initializi
|
||||
if (facets != null)
|
||||
{
|
||||
for (String field: facets)
|
||||
{
|
||||
final String modifiedField = "@" + field;
|
||||
if (solrFacetHelper.hasFacetQueries(modifiedField))
|
||||
{
|
||||
List<String> facetQueries = solrFacetHelper.getFacetQueries(modifiedField);
|
||||
addFacetQuery(sp, field, facetQueries, query);
|
||||
}
|
||||
else
|
||||
{
|
||||
final FieldFacet fieldFacet;
|
||||
if (solrFacetHelper.isSpecialFacetId(field))
|
||||
@@ -724,24 +749,10 @@ public class Search extends BaseScopableProcessorExtension implements Initializi
|
||||
}
|
||||
else
|
||||
{
|
||||
fieldFacet = new FieldFacet("@" + field);
|
||||
fieldFacet = new FieldFacet(modifiedField);
|
||||
}
|
||||
sp.addFieldFacet(fieldFacet);
|
||||
}
|
||||
|
||||
List<String> facetQueries = null;
|
||||
// Workaround for ACE-1605
|
||||
if (query.indexOf("created:") < 0 && query.indexOf("modified:") < 0)
|
||||
{
|
||||
facetQueries = solrFacetHelper.getDefaultFacetQueries();
|
||||
}
|
||||
else
|
||||
{
|
||||
facetQueries = solrFacetHelper.createFacetQueriesFromSearchQuery(query);
|
||||
}
|
||||
for (String fq : facetQueries)
|
||||
{
|
||||
sp.addFacetQuery(fq);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -954,7 +965,7 @@ public class Search extends BaseScopableProcessorExtension implements Initializi
|
||||
if (f.getSecond() > 0)
|
||||
{
|
||||
String facetValue = f.getFirst();
|
||||
FacetLabelDisplayHandler handler = solrFacetHelper.getDisplayHandler(ff.getField());
|
||||
FacetLabelDisplayHandler handler = facetLabelDisplayHandlerRegistry.getDisplayHandler(ff.getField());
|
||||
String label = (handler == null) ? facetValue : handler.getDisplayLabel(facetValue).getLabel();
|
||||
|
||||
facets.add(new ScriptFacetResult(facetValue, label, -1, f.getSecond()));
|
||||
@@ -979,22 +990,22 @@ public class Search extends BaseScopableProcessorExtension implements Initializi
|
||||
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]
|
||||
// for example the key could be: {!afts}@{http://www.alfresco.org/model/content/1.0}created:[NOW/DAY-1DAY TO NOW/DAY+1DAY]
|
||||
// qName => @{http://www.alfresco.org/model/content/1.0}created
|
||||
// 7 => {!afts}
|
||||
String qName = key.substring(7, key.lastIndexOf(':'));
|
||||
key = key.substring(7);
|
||||
String qName = key.substring(0, key.lastIndexOf(':'));
|
||||
|
||||
// Retrieve the previous facet queries
|
||||
List<ScriptFacetResult> fqs = facetMeta.get(qName);
|
||||
if (fqs == null)
|
||||
{
|
||||
// Shouldn't be here
|
||||
throw new AlfrescoRuntimeException("Field facet [" + qName + "] has"
|
||||
+ " not been registered with SolrFacetHelper.BUCKETED_FIELD_FACETS.");
|
||||
fqs = new ArrayList<>();
|
||||
logger.info("Field facet [" + key + "] has not been registered.");
|
||||
}
|
||||
FacetLabelDisplayHandler handler = solrFacetHelper.getDisplayHandler(qName);
|
||||
FacetLabel facetLabel = (handler == null) ? new FacetLabel(qName, key.substring(qName.length(),
|
||||
key.length()), -1) : handler.getDisplayLabel(key);
|
||||
// Get the handler for this qName
|
||||
FacetLabelDisplayHandler handler = facetLabelDisplayHandlerRegistry.getDisplayHandler(qName);
|
||||
FacetLabel facetLabel = (handler == null) ? new FacetLabel(key, key, -1) : handler.getDisplayLabel(key);
|
||||
|
||||
fqs.add(new ScriptFacetResult(facetLabel.getValue(), facetLabel.getLabel(), facetLabel.getLabelIndex(), entry.getValue()));
|
||||
}
|
||||
@@ -1037,6 +1048,33 @@ public class Search extends BaseScopableProcessorExtension implements Initializi
|
||||
return new Pair<Object[], Map<String,Object>>(res, meta);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds facet queries to the {@code SearchParameters}
|
||||
*
|
||||
* @param sp the SearchParameters
|
||||
* @param field the requested field facet
|
||||
* @param facetQueries list of generated facet queries
|
||||
* @param query the requested search query
|
||||
*/
|
||||
protected void addFacetQuery(SearchParameters sp, String field, List<String> facetQueries, String query)
|
||||
{
|
||||
// Workaround for ACE-1605
|
||||
if (query.indexOf(field) < 0)
|
||||
{
|
||||
for (String fq : facetQueries)
|
||||
{
|
||||
sp.addFacetQuery(fq);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
String fq = solrFacetHelper.createFacetQueriesFromSearchQuery(field, query);
|
||||
if (fq != null)
|
||||
{
|
||||
sp.addFacetQuery(fq);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Search sort column
|
||||
|
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A contract for classes which need to create a set of predefined facet queries.
|
||||
*
|
||||
* @author Jamal Kaabi-Mofrad
|
||||
* @since 5.0
|
||||
*/
|
||||
public interface FacetQueryProvider
|
||||
{
|
||||
|
||||
/**
|
||||
* Gets the created facet queries
|
||||
*
|
||||
* @return read-only map of facet queries or an empty map.
|
||||
*/
|
||||
public Map<String, List<String>> getFacetQueries();
|
||||
}
|
@@ -16,273 +16,104 @@
|
||||
* 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.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
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 java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
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.alfresco.util.PropertyCheck;
|
||||
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
|
||||
* A helper class for facet queries.
|
||||
*
|
||||
* @author Jamal Kaabi-Mofrad
|
||||
* @since 5.0
|
||||
*/
|
||||
// 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_FIELD_FACET_QUERY = FQ_NS_PREFIX + "created";
|
||||
private static final String MODIFIED_FIELD_FACET_QUERY = FQ_NS_PREFIX + "modified";
|
||||
private static final String CONTENT_SIZE_FIELD_FACET_QUERY = FQ_NS_PREFIX + "content.size";
|
||||
private final Map<String, List<String>> facetQueries;
|
||||
|
||||
// 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";
|
||||
|
||||
// Positive-look-behind RegEx.
|
||||
// E.g. pattern-input => {http://www.alfresco.org/model/content/1.0}created:("2014-04-07".."2014-05-07")
|
||||
// the matcher-output => 2014-04-07".."2014-05-07
|
||||
/** Pattern to search for created date */
|
||||
private static final Pattern CREATED_DATE_PATTERN = Pattern.compile("(?<=created:\\(\")(\\d{4}-\\d{2}-\\d{2})(\"..\")(\\d{4}-\\d{2}-\\d{2})");
|
||||
|
||||
/** Pattern to search for modified date */
|
||||
private static final Pattern MODIFIED_DATE_PATTERN = Pattern.compile("(?<=modified:\\(\")(\\d{4}-\\d{2}-\\d{2})(\"..\")(\\d{4}-\\d{2}-\\d{2})");
|
||||
|
||||
/** Content size buckets */
|
||||
private static final List<String> CONTENT_SIZE_BUCKETS = new ArrayList<>(6);
|
||||
static
|
||||
{
|
||||
CONTENT_SIZE_BUCKETS.add("0 TO " + TINY);
|
||||
CONTENT_SIZE_BUCKETS.add(TINY + " TO " + SMALL);
|
||||
CONTENT_SIZE_BUCKETS.add(SMALL + " TO " + MEDIUM);
|
||||
CONTENT_SIZE_BUCKETS.add(MEDIUM + " TO " + LARGE);
|
||||
CONTENT_SIZE_BUCKETS.add(LARGE + " TO " + HUGE);
|
||||
CONTENT_SIZE_BUCKETS.add(HUGE + " TO MAX");
|
||||
}
|
||||
|
||||
/** Field facet buckets */
|
||||
private static final Set<String> BUCKETED_FIELD_FACETS = new HashSet<>(3);
|
||||
static
|
||||
{
|
||||
BUCKETED_FIELD_FACETS.add(CREATED_FIELD_FACET_QUERY);
|
||||
BUCKETED_FIELD_FACETS.add(MODIFIED_FIELD_FACET_QUERY);
|
||||
BUCKETED_FIELD_FACETS.add(CONTENT_SIZE_FIELD_FACET_QUERY);
|
||||
}
|
||||
|
||||
/** These facet IDs are recognised by SOLR and can be used directly within facetted searches. */
|
||||
private final List<String> specialFacetIds = Arrays.asList(new String[] {
|
||||
"SITE", "TAG", "ANCESTOR",
|
||||
"PARENT", "ASPECT", "TYPE", "OWNER" });
|
||||
|
||||
/** 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;
|
||||
/** These facet IDs are recognised by SOLR and can be used directly within faceted searches. */
|
||||
private Set<String> specialFacetIds = Collections.emptySet();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param serviceRegistry
|
||||
*/
|
||||
public SolrFacetHelper(ServiceRegistry serviceRegistry)
|
||||
public SolrFacetHelper(List<FacetQueryProvider> facetQueryProviders)
|
||||
{
|
||||
this.fqDateCache = new BucketsCache<>(new FacetQueryParamDateBuckets());
|
||||
this.displayHandlers = new HashMap<>(6);
|
||||
PropertyCheck.mandatory(this, "facetQueryProviders", facetQueryProviders);
|
||||
|
||||
UserNameDisplayHandler userNameDisplayHandler = new UserNameDisplayHandler(serviceRegistry);
|
||||
MimetypeDisplayHandler mimetypeDisplayHandler = new MimetypeDisplayHandler(serviceRegistry);
|
||||
DateBucketsDisplayHandler dateBucketsDisplayHandler = new DateBucketsDisplayHandler();
|
||||
ContentSizeBucketsDisplayHandler contentSizeBucketsDisplayHandler = new ContentSizeBucketsDisplayHandler();
|
||||
facetQueries = new LinkedHashMap<>();
|
||||
for (FacetQueryProvider queryProvider : facetQueryProviders)
|
||||
{
|
||||
for (Entry<String, List<String>> entry : queryProvider.getFacetQueries().entrySet())
|
||||
{
|
||||
facetQueries.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.displayHandlers.put("@{http://www.alfresco.org/model/content/1.0}creator.__.u", userNameDisplayHandler);
|
||||
this.displayHandlers.put("@{http://www.alfresco.org/model/content/1.0}modifier.__.u", userNameDisplayHandler);
|
||||
this.displayHandlers.put("@{http://www.alfresco.org/model/content/1.0}content.mimetype", mimetypeDisplayHandler);
|
||||
this.displayHandlers.put(CREATED_FIELD_FACET_QUERY, dateBucketsDisplayHandler);
|
||||
this.displayHandlers.put(MODIFIED_FIELD_FACET_QUERY, dateBucketsDisplayHandler);
|
||||
this.displayHandlers.put(CONTENT_SIZE_FIELD_FACET_QUERY, contentSizeBucketsDisplayHandler);
|
||||
public void setSpecialFacetIds(Set<String> ids)
|
||||
{
|
||||
this.specialFacetIds = ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the 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>
|
||||
* Gets the 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> getDefaultFacetQueries()
|
||||
{
|
||||
List<String> facetQueries = new ArrayList<>();
|
||||
List<String> dateBuckets = getDateBuckets();
|
||||
|
||||
// Created and Modified dates facet queries
|
||||
for (String bucket : dateBuckets)
|
||||
Collection<List<String>> queries = facetQueries.values();
|
||||
List<String> list = new ArrayList<String>();
|
||||
for (List<String> q : queries)
|
||||
{
|
||||
facetQueries.add(CREATED_FIELD_FACET_QUERY + ":[" + bucket + ']');
|
||||
facetQueries.add(MODIFIED_FIELD_FACET_QUERY + ":[" + bucket + ']');
|
||||
list.addAll(q);
|
||||
}
|
||||
|
||||
// Content size facet query
|
||||
for (String bucket : CONTENT_SIZE_BUCKETS)
|
||||
{
|
||||
facetQueries.add(CONTENT_SIZE_FIELD_FACET_QUERY + ":[" + bucket + ']');
|
||||
}
|
||||
|
||||
return facetQueries;
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates <i>Created</i> and <i>Modified</i> facet queries by trying to
|
||||
* extract the date range from the Created and/or Modified filter(s) within
|
||||
* the search query. If either of the <i>Created</i> or <i>Modified</i>
|
||||
* filter is missing from the search query, the default set of facet queries
|
||||
* will be created for the missing date filter. Also, creates the default
|
||||
* <i>Content.Size</i> facet queries.
|
||||
* Whether the specified field is defined as a <i>facet.query</i> or not
|
||||
*
|
||||
* @return list of facet queries
|
||||
* @param facetField
|
||||
* @return true if the facet is <i>facet.query</i>, false otherwise
|
||||
*/
|
||||
// ACE-1605
|
||||
public List<String> createFacetQueriesFromSearchQuery(String searchQuery)
|
||||
public boolean hasFacetQueries(String facetField)
|
||||
{
|
||||
String createdDateRange = extractDateRange(searchQuery, CREATED_DATE_PATTERN);
|
||||
String modifiedDateRange = extractDateRange(searchQuery, MODIFIED_DATE_PATTERN);
|
||||
|
||||
if (createdDateRange == null && modifiedDateRange == null)
|
||||
{
|
||||
return getDefaultFacetQueries();
|
||||
}
|
||||
|
||||
List<String> facetQueries = new ArrayList<>();
|
||||
List<String> dateBuckets = getDateBuckets();
|
||||
|
||||
if (createdDateRange != null && modifiedDateRange != null)
|
||||
{
|
||||
// Add the Created and Modified dates facet queries
|
||||
facetQueries.add(CREATED_FIELD_FACET_QUERY + ":[" + createdDateRange + ']');
|
||||
facetQueries.add(MODIFIED_FIELD_FACET_QUERY + ":[" + modifiedDateRange + ']');
|
||||
}
|
||||
else if (createdDateRange == null)
|
||||
{
|
||||
// As Created date is null, add all the the predefined created buckets.
|
||||
for (String bucket : dateBuckets)
|
||||
{
|
||||
facetQueries.add(CREATED_FIELD_FACET_QUERY + ":[" + bucket + ']');
|
||||
}
|
||||
// We can be sure, that modifiedDateRange is not null (see the first 'if' statement).
|
||||
facetQueries.add(MODIFIED_FIELD_FACET_QUERY + ":[" + modifiedDateRange + ']');
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we are here, it means, Modified date is null, hence, add
|
||||
// all the the predefined modified buckets.
|
||||
for (String bucket : dateBuckets)
|
||||
{
|
||||
facetQueries.add(MODIFIED_FIELD_FACET_QUERY + ":[" + bucket + ']');
|
||||
}
|
||||
facetQueries.add(CREATED_FIELD_FACET_QUERY + ":[" + createdDateRange + ']');
|
||||
}
|
||||
|
||||
// Always add the content size facet query
|
||||
for (String bucket : CONTENT_SIZE_BUCKETS)
|
||||
{
|
||||
facetQueries.add(CONTENT_SIZE_FIELD_FACET_QUERY + ":[" + bucket + ']');
|
||||
}
|
||||
|
||||
return facetQueries;
|
||||
return facetQueries.containsKey(facetField);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the date range that will match against the pattern from the search query
|
||||
*
|
||||
* @param searchQuery the string input
|
||||
* @param pattern the compiled representation of a RegEx
|
||||
* @return the date range or null, if there is no match. An example of the
|
||||
* date range string representation is: 2014-04-28 TO 2014-04-29
|
||||
* Gets all the defined facet queries for the specified field
|
||||
* @param facetField the requested field
|
||||
* @return an unmodifiable list of facet queries, or null if none found
|
||||
*/
|
||||
private String extractDateRange(String searchQuery, Pattern pattern)
|
||||
public List<String> getFacetQueries(String facetField)
|
||||
{
|
||||
String dateRange = null;
|
||||
Matcher matcher = pattern.matcher(searchQuery);
|
||||
if (matcher.find())
|
||||
List<String> queries = facetQueries.get(facetField);
|
||||
if (queries == null)
|
||||
{
|
||||
dateRange = matcher.group();
|
||||
// E.g. dateRange => 2014-04-28".."2014-04-29
|
||||
return null;
|
||||
}
|
||||
|
||||
return (dateRange == null) ? null : dateRange.replace("\"..\"", " TO ");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the predefined date buckets from the cache
|
||||
*
|
||||
* @return list of date ranges. An example of the date range string
|
||||
* representation is: 2014-04-28 TO 2014-04-29
|
||||
*/
|
||||
private List<String> getDateBuckets()
|
||||
{
|
||||
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());
|
||||
}
|
||||
return dateBuckets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the appropriate facet display label handler
|
||||
*
|
||||
* @param qName the field facet 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);
|
||||
return Collections.unmodifiableList(queries);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -292,9 +123,50 @@ public class SolrFacetHelper
|
||||
*/
|
||||
public Set<String> getBucketedFieldFacets()
|
||||
{
|
||||
return Collections.unmodifiableSet(BUCKETED_FIELD_FACETS);
|
||||
return Collections.unmodifiableSet(facetQueries.keySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a facet query by trying to extract the date range from the the
|
||||
* search query.
|
||||
*
|
||||
* @return the facet query, or null if the date range cannot be extracted
|
||||
*/
|
||||
// workaround for https://issues.alfresco.com/jira/browse/ACE-1605
|
||||
public String createFacetQueriesFromSearchQuery(String field, String searchQuery)
|
||||
{
|
||||
if (field == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
try
|
||||
{
|
||||
if (field.startsWith("@"))
|
||||
{
|
||||
field = field.substring(1);
|
||||
}
|
||||
String escapedField = searchQuery.substring(searchQuery.indexOf(field));
|
||||
|
||||
String dateRange = escapedField.substring(field.length() + 2, escapedField.indexOf(")")).trim();
|
||||
// E.g. dateRange => "NOW/DAY-7DAYS".."NOW/DAY+1DAY"
|
||||
|
||||
dateRange = dateRange.replace("\"..\"", " TO ");
|
||||
// remove the date-range quotations marks
|
||||
dateRange = dateRange.replace("\"", "");
|
||||
|
||||
// the processed dateRange will be, for example, NOW/DAY-7DAY TO NOW/DAY+1DAY
|
||||
dateRange = (dateRange == null) ? null : field + ":[" + dateRange + "]";
|
||||
|
||||
return "@" + dateRange;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.warn("Couldn’t extract " + field + " date range from the search query." + e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Is the specified facet ID part of the list of "specials" which are
|
||||
* handled by our SOLR service as is?
|
||||
@@ -303,440 +175,4 @@ public class SolrFacetHelper
|
||||
{
|
||||
return specialFacetIds.contains(facetId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates Date buckets. The dates are in ISO8601 format (yyyy-MM-dd)
|
||||
*
|
||||
* @return list of date ranges. An example of the date range string
|
||||
* representation is: 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, insertion index)>}
|
||||
*/
|
||||
private static Map<String, Pair<String, Integer>> makeDateBucketsDisplayLabel(LocalDate date)
|
||||
{
|
||||
List<String> dateBuckets = makeDateBuckets(date);
|
||||
Map<String, Pair<String, Integer>> 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), new Pair<String, Integer>("faceted-search.date.one-day.label", 0));
|
||||
bucketDisplayName.put(dateBuckets.get(1), new Pair<String, Integer>("faceted-search.date.one-week.label", 1));
|
||||
bucketDisplayName.put(dateBuckets.get(2), new Pair<String, Integer>("faceted-search.date.one-month.label", 2));
|
||||
bucketDisplayName.put(dateBuckets.get(3), new Pair<String, Integer>("faceted-search.date.six-months.label", 3));
|
||||
bucketDisplayName.put(dateBuckets.get(4), new Pair<String, Integer>("faceted-search.date.one-year.label", 4));
|
||||
|
||||
return bucketDisplayName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates display name for the Content size buckets.
|
||||
*
|
||||
* @return Map of {@literal <size range, (display label key, insertion index)>}
|
||||
*/
|
||||
private static Map<String, Pair<String, Integer>> makeContentSizeBucketsDisplayLabel()
|
||||
{
|
||||
Map<String, Pair<String, Integer>> bucketDisplayName = new HashMap<>(6);
|
||||
|
||||
if (CONTENT_SIZE_BUCKETS.size() != 6)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("Content size buckets size does not match the bucket display label size!");
|
||||
}
|
||||
|
||||
bucketDisplayName.put(CONTENT_SIZE_BUCKETS.get(0), new Pair<String, Integer>("faceted-search.size.0-10KB.label", 0));
|
||||
bucketDisplayName.put(CONTENT_SIZE_BUCKETS.get(1), new Pair<String, Integer>("faceted-search.size.10-100KB.label", 1));
|
||||
bucketDisplayName.put(CONTENT_SIZE_BUCKETS.get(2), new Pair<String, Integer>("faceted-search.size.100KB-1MB.label", 2));
|
||||
bucketDisplayName.put(CONTENT_SIZE_BUCKETS.get(3), new Pair<String, Integer>("faceted-search.size.1-16MB.label", 3));
|
||||
bucketDisplayName.put(CONTENT_SIZE_BUCKETS.get(4), new Pair<String, Integer>("faceted-search.size.16-128MB.label", 4));
|
||||
bucketDisplayName.put(CONTENT_SIZE_BUCKETS.get(5), new Pair<String, Integer>("faceted-search.size.over128.label", 5));
|
||||
|
||||
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)
|
||||
{
|
||||
throw 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, Pair<String, Integer>>>
|
||||
{
|
||||
@Override
|
||||
public Map<String, Pair<String, Integer>> 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, Pair<String, Integer>>>
|
||||
{
|
||||
@Override
|
||||
public Map<String, Pair<String, Integer>> 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
|
||||
{
|
||||
FacetLabel getDisplayLabel(String value);
|
||||
}
|
||||
|
||||
/**
|
||||
* A class to encapsulate the result of the facet label display handler
|
||||
*
|
||||
* @author Jamal Kaabi-Mofrad
|
||||
*/
|
||||
public static class FacetLabel
|
||||
{
|
||||
private final String value;
|
||||
private final String label;
|
||||
private final int labelIndex;
|
||||
|
||||
/**
|
||||
* @param value
|
||||
* @param label
|
||||
* @param labelIndex
|
||||
*/
|
||||
public FacetLabel(String value, String label, int labelIndex)
|
||||
{
|
||||
this.value = value;
|
||||
this.label = label;
|
||||
this.labelIndex = labelIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the original facet value or a new modified value
|
||||
*
|
||||
* @return the original facet value or a new modified value
|
||||
*/
|
||||
public String getValue()
|
||||
{
|
||||
return this.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the facet display label
|
||||
*
|
||||
* @return the label
|
||||
*/
|
||||
public String getLabel()
|
||||
{
|
||||
return this.label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the label index to be used for sorting. The index only relevant
|
||||
* to to Date and Size facets.
|
||||
*
|
||||
* @return the index or -1, if it isn't relevant to the facet label
|
||||
*/
|
||||
public int getLabelIndex()
|
||||
{
|
||||
return this.labelIndex;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((this.label == null) ? 0 : this.label.hashCode());
|
||||
result = prime * result + this.labelIndex;
|
||||
result = prime * result + ((this.value == null) ? 0 : this.value.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (!(obj instanceof FacetLabel))
|
||||
return false;
|
||||
FacetLabel other = (FacetLabel) obj;
|
||||
if (this.label == null)
|
||||
{
|
||||
if (other.label != null)
|
||||
return false;
|
||||
}
|
||||
else if (!this.label.equals(other.label))
|
||||
return false;
|
||||
if (this.labelIndex != other.labelIndex)
|
||||
return false;
|
||||
if (this.value == null)
|
||||
{
|
||||
if (other.value != null)
|
||||
return false;
|
||||
}
|
||||
else if (!this.value.equals(other.value))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 FacetLabel 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 FacetLabel(value, name == null ? value : name.trim(), -1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 FacetLabel getDisplayLabel(String value)
|
||||
{
|
||||
Map<String, String> mimetypes = mimetypeService.getDisplaysByMimetype();
|
||||
String displayName = mimetypes.get(value);
|
||||
return new FacetLabel(value, displayName == null ? value : displayName.trim(), -1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, Pair<String, Integer>>> cache = new BucketsCache<>(
|
||||
new FacetQueryResultDateBuckets());
|
||||
|
||||
@Override
|
||||
public FacetLabel getDisplayLabel(String value)
|
||||
{
|
||||
Map<String, Pair<String, Integer>> 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 = lowerUpperDates[0] + "\"..\"" + lowerUpperDates[1];
|
||||
Pair<String, Integer> labelIndexPair = dateBuckets.get(dateRange);
|
||||
return new FacetLabel(newValue, labelIndexPair.getFirst(), labelIndexPair.getSecond());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, Pair<String, Integer>>> cache = new BucketsCache<>(
|
||||
new FacetQueryResultContentSizeBuckets());
|
||||
|
||||
@Override
|
||||
public FacetLabel getDisplayLabel(String value)
|
||||
{
|
||||
String sizeRange = value.substring(value.indexOf('[') + 1, value.length() - 1);
|
||||
String[] lowerUppperSize = sizeRange.split("\\sTO\\s");
|
||||
|
||||
Map<String, Pair<String, Integer>> 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 = lowerUppperSize[0] + "\"..\"" + lowerUppperSize[1];
|
||||
Pair<String, Integer> labelIndexPair = sizeBuckets.get(sizeRange);
|
||||
return new FacetLabel(newValue, labelIndexPair.getFirst(), labelIndexPair.getSecond());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* 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.handler;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.util.PropertyCheck;
|
||||
|
||||
/**
|
||||
* A support class for facet label display handlers.
|
||||
*
|
||||
* @author Jamal Kaabi-Mofrad
|
||||
* @since 5.0
|
||||
*/
|
||||
public abstract class AbstractFacetLabelDisplayHandler implements FacetLabelDisplayHandler
|
||||
{
|
||||
protected ServiceRegistry serviceRegistry;
|
||||
protected Set<String> supportedFieldFacets;
|
||||
private FacetLabelDisplayHandlerRegistry registry;
|
||||
|
||||
/**
|
||||
* Registers this instance of the facet handler with the registry. This will
|
||||
* call the {@link #init()} method and then register if the registry is available.
|
||||
*
|
||||
*/
|
||||
public final void register()
|
||||
{
|
||||
init();
|
||||
|
||||
for (String fieldFacet : supportedFieldFacets)
|
||||
{
|
||||
registry.addDisplayHandler(fieldFacet, this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected void init()
|
||||
{
|
||||
PropertyCheck.mandatory(this, "registry", registry);
|
||||
PropertyCheck.mandatory(this, "serviceRegistry", serviceRegistry);
|
||||
PropertyCheck.mandatory(this, "supportedFieldFacets", supportedFieldFacets);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param supportedFieldFacets the supportedFieldFacets to set
|
||||
*/
|
||||
public void setSupportedFieldFacets(Set<String> supportedFieldFacets)
|
||||
{
|
||||
this.supportedFieldFacets = supportedFieldFacets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the service registry
|
||||
*
|
||||
* @param services the service registry
|
||||
*/
|
||||
public void setServiceRegistry(ServiceRegistry serviceRegistry)
|
||||
{
|
||||
this.serviceRegistry = serviceRegistry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the registry to register with
|
||||
*
|
||||
* @param registry a metadata extracter registry
|
||||
*/
|
||||
public void setRegistry(FacetLabelDisplayHandlerRegistry registry)
|
||||
{
|
||||
this.registry = registry;
|
||||
}
|
||||
}
|
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* 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.handler;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.repo.search.impl.solr.facet.FacetQueryProvider;
|
||||
import org.alfresco.repo.search.impl.solr.facet.SolrFacetConfigException;
|
||||
import org.springframework.extensions.surf.util.ParameterCheck;
|
||||
|
||||
/**
|
||||
* A simple handler to get the appropriate display label for the content size buckets.
|
||||
*
|
||||
* @author Jamal Kaabi-Mofrad
|
||||
* @since 5.0
|
||||
*/
|
||||
public class ContentSizeBucketsDisplayHandler extends AbstractFacetLabelDisplayHandler implements FacetQueryProvider
|
||||
{
|
||||
private static final Pattern SIZE_RANGE_PATTERN = Pattern.compile("(\\[\\d+\\sTO\\s(\\d+|MAX)\\])");
|
||||
|
||||
private final Map<String, FacetLabel> facetLabelMap;
|
||||
private final Map<String, List<String>> facetQueriesMap;
|
||||
|
||||
public ContentSizeBucketsDisplayHandler(Set<String> facetQueryFields, LinkedHashMap<String, String> sizeBucketsMap)
|
||||
{
|
||||
ParameterCheck.mandatory("facetQueryFields", facetQueryFields);
|
||||
ParameterCheck.mandatory("sizeBucketsMap", sizeBucketsMap);
|
||||
|
||||
this.supportedFieldFacets = Collections.unmodifiableSet(facetQueryFields);
|
||||
|
||||
facetLabelMap = new HashMap<>(sizeBucketsMap.size());
|
||||
Map<String, List<String>> facetQueries = new LinkedHashMap<>(facetQueryFields.size());
|
||||
|
||||
for (String facetQueryField : facetQueryFields)
|
||||
{
|
||||
List<String> queries = new ArrayList<>();
|
||||
int index = 0;
|
||||
for (Entry<String, String> bucket : sizeBucketsMap.entrySet())
|
||||
{
|
||||
String sizeRange = bucket.getKey().trim();
|
||||
Matcher matcher = SIZE_RANGE_PATTERN.matcher(sizeRange);
|
||||
if (!matcher.find())
|
||||
{
|
||||
throw new SolrFacetConfigException(
|
||||
"Invalid size range. Example of a valid size range is: [0 TO 1024]");
|
||||
}
|
||||
// build the facet query. e.g. {http://www.alfresco.org/model/content/1.0}content.size:[0 TO 1024]
|
||||
String facetQuery = facetQueryField + ':' + sizeRange;
|
||||
queries.add(facetQuery);
|
||||
|
||||
// indexOf('[') => 1
|
||||
String sizeRangeQuery = sizeRange.substring(1, sizeRange.length() - 1);
|
||||
sizeRangeQuery = sizeRangeQuery.replaceFirst("\\sTO\\s", "\"..\"");
|
||||
facetLabelMap.put(facetQuery, new FacetLabel(sizeRangeQuery, bucket.getValue(), index++));
|
||||
}
|
||||
facetQueries.put(facetQueryField, queries);
|
||||
}
|
||||
this.facetQueriesMap = Collections.unmodifiableMap(facetQueries);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FacetLabel getDisplayLabel(String value)
|
||||
{
|
||||
FacetLabel facetLabel = facetLabelMap.get(value);
|
||||
return (facetLabel == null) ? new FacetLabel(value, value, -1) : facetLabel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<String>> getFacetQueries()
|
||||
{
|
||||
return this.facetQueriesMap;
|
||||
}
|
||||
}
|
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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.handler;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.alfresco.repo.search.impl.solr.facet.FacetQueryProvider;
|
||||
import org.alfresco.repo.search.impl.solr.facet.SolrFacetConfigException;
|
||||
import org.springframework.extensions.surf.util.ParameterCheck;
|
||||
|
||||
/**
|
||||
* A simple handler to get the appropriate display label for the date buckets.
|
||||
*
|
||||
* @author Jamal Kaabi-Mofrad
|
||||
* @since 5.0
|
||||
*/
|
||||
public class DateBucketsDisplayHandler extends AbstractFacetLabelDisplayHandler implements FacetQueryProvider
|
||||
{
|
||||
private static final Pattern DATE_RANGE_PATTERN = Pattern.compile("(\\[\\w+\\S+\\sTO\\s(\\w+\\S+)\\])");
|
||||
|
||||
private final Map<String, FacetLabel> facetLabelMap;
|
||||
private final Map<String, List<String>> facetQueriesMap;
|
||||
|
||||
public DateBucketsDisplayHandler(Set<String> facetQueryFields, LinkedHashMap<String, String> dateBucketsMap)
|
||||
{
|
||||
ParameterCheck.mandatory("facetQueryFields", facetQueryFields);
|
||||
ParameterCheck.mandatory("dateBucketsMap", dateBucketsMap);
|
||||
|
||||
this.supportedFieldFacets = Collections.unmodifiableSet(facetQueryFields);
|
||||
|
||||
facetLabelMap = new HashMap<>(dateBucketsMap.size());
|
||||
Map<String, List<String>> facetQueries = new LinkedHashMap<>(facetQueryFields.size());
|
||||
|
||||
for (String facetQueryField : facetQueryFields)
|
||||
{
|
||||
List<String> queries = new ArrayList<>();
|
||||
int index = 0;
|
||||
for (Entry<String, String> bucket : dateBucketsMap.entrySet())
|
||||
{
|
||||
String dateRange = bucket.getKey().trim();
|
||||
Matcher matcher = DATE_RANGE_PATTERN.matcher(dateRange);
|
||||
if (!matcher.find())
|
||||
{
|
||||
throw new SolrFacetConfigException(
|
||||
"Invalid date range. Example of a valid date range is: '[NOW/DAY-1DAY TO NOW/DAY+1DAY]'");
|
||||
}
|
||||
// build the facet query. e.g. {http://www.alfresco.org/model/content/1.0}created:[NOW/DAY-1DAY TO NOW/DAY+1DAY]
|
||||
String facetQuery = facetQueryField + ':' + dateRange;
|
||||
queries.add(facetQuery);
|
||||
|
||||
// indexOf('[') => 1
|
||||
String dateRangeQuery = dateRange.substring(1, dateRange.length() - 1);
|
||||
dateRangeQuery = dateRangeQuery.replaceFirst("\\sTO\\s", "\"..\"");
|
||||
facetLabelMap.put(facetQuery, new FacetLabel(dateRangeQuery, bucket.getValue(), index++));
|
||||
}
|
||||
facetQueries.put(facetQueryField, queries);
|
||||
}
|
||||
this.facetQueriesMap = Collections.unmodifiableMap(facetQueries);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FacetLabel getDisplayLabel(String value)
|
||||
{
|
||||
FacetLabel facetLabel = facetLabelMap.get(value);
|
||||
return (facetLabel == null) ? new FacetLabel(value, value, -1) : facetLabel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<String>> getFacetQueries()
|
||||
{
|
||||
return this.facetQueriesMap;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* 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.handler;
|
||||
|
||||
/**
|
||||
* A class to encapsulate the result of the facet label display handler.
|
||||
*
|
||||
* @author Jamal Kaabi-Mofrad
|
||||
* @since 5.0
|
||||
*/
|
||||
public class FacetLabel
|
||||
{
|
||||
private final String value;
|
||||
private final String label;
|
||||
private final int labelIndex;
|
||||
|
||||
/**
|
||||
* @param value
|
||||
* @param label
|
||||
* @param labelIndex
|
||||
*/
|
||||
public FacetLabel(String value, String label, int labelIndex)
|
||||
{
|
||||
this.value = value;
|
||||
this.label = label;
|
||||
this.labelIndex = labelIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the original facet value or a new modified value
|
||||
*
|
||||
* @return the original facet value or a new modified value
|
||||
*/
|
||||
public String getValue()
|
||||
{
|
||||
return this.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the facet display label
|
||||
*
|
||||
* @return the label
|
||||
*/
|
||||
public String getLabel()
|
||||
{
|
||||
return this.label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the label index to be used for sorting. The index only relevant to
|
||||
* to Date and Size facets.
|
||||
*
|
||||
* @return the index or -1, if it isn't relevant to the facet label
|
||||
*/
|
||||
public int getLabelIndex()
|
||||
{
|
||||
return this.labelIndex;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((this.label == null) ? 0 : this.label.hashCode());
|
||||
result = prime * result + this.labelIndex;
|
||||
result = prime * result + ((this.value == null) ? 0 : this.value.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (!(obj instanceof FacetLabel))
|
||||
return false;
|
||||
FacetLabel other = (FacetLabel) obj;
|
||||
if (this.label == null)
|
||||
{
|
||||
if (other.label != null)
|
||||
return false;
|
||||
}
|
||||
else if (!this.label.equals(other.label))
|
||||
return false;
|
||||
if (this.labelIndex != other.labelIndex)
|
||||
return false;
|
||||
if (this.value == null)
|
||||
{
|
||||
if (other.value != null)
|
||||
return false;
|
||||
}
|
||||
else if (!this.value.equals(other.value))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.handler;
|
||||
|
||||
|
||||
/**
|
||||
* An interface for Solr facet value and facet query result display label handler.
|
||||
*
|
||||
* @author Jamal Kaabi-Mofrad
|
||||
* @since 5.0
|
||||
*/
|
||||
public interface FacetLabelDisplayHandler
|
||||
{
|
||||
/**
|
||||
* Gets the user friendly display label for the returned facet value
|
||||
*
|
||||
* @param value the facet value
|
||||
* @return user friendly display label or the original value, if there is no result
|
||||
*/
|
||||
public FacetLabel getDisplayLabel(String value);
|
||||
}
|
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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.handler;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
/**
|
||||
* A registry which holds and provides the appropriate display handler for a
|
||||
* particular facet field.
|
||||
*
|
||||
* @author Jamal Kaabi-Mofrad
|
||||
* @since 5.0
|
||||
*/
|
||||
public class FacetLabelDisplayHandlerRegistry
|
||||
{
|
||||
private final ConcurrentMap<String, FacetLabelDisplayHandler> registry;
|
||||
|
||||
public FacetLabelDisplayHandlerRegistry()
|
||||
{
|
||||
this.registry = new ConcurrentHashMap<String, FacetLabelDisplayHandler>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an instance of {@code FacetLabelDisplayHandler} with the
|
||||
* specified field facet.
|
||||
*
|
||||
* @param fieldFacet the field facet
|
||||
* @param displayHandler the display handler
|
||||
*/
|
||||
public void addDisplayHandler(String fieldFacet, FacetLabelDisplayHandler displayHandler)
|
||||
{
|
||||
registry.putIfAbsent(fieldFacet, displayHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the display handler.
|
||||
*
|
||||
* @param fieldFacet the field facet to perform the lookup
|
||||
* @return the display handler or null if none found
|
||||
*/
|
||||
public FacetLabelDisplayHandler getDisplayHandler(String fieldFacet)
|
||||
{
|
||||
return registry.get(fieldFacet);
|
||||
}
|
||||
}
|
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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.handler;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.extensions.surf.util.ParameterCheck;
|
||||
|
||||
/**
|
||||
* A simple handler to get the Mimetype display label.
|
||||
*
|
||||
* @author Jamal Kaabi-Mofrad
|
||||
* @since 5.0
|
||||
*/
|
||||
public class MimetypeDisplayHandler extends AbstractFacetLabelDisplayHandler
|
||||
{
|
||||
|
||||
public MimetypeDisplayHandler(Set<String> supportedFieldFacets)
|
||||
{
|
||||
ParameterCheck.mandatory("supportedFieldFacets", supportedFieldFacets);
|
||||
|
||||
this.supportedFieldFacets = Collections.unmodifiableSet(new HashSet<>(supportedFieldFacets));
|
||||
}
|
||||
|
||||
@Override
|
||||
public FacetLabel getDisplayLabel(String value)
|
||||
{
|
||||
Map<String, String> mimetypes = serviceRegistry.getMimetypeService().getDisplaysByMimetype();
|
||||
String displayName = mimetypes.get(value);
|
||||
return new FacetLabel(value, displayName == null ? value : displayName.trim(), -1);
|
||||
}
|
||||
}
|
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.handler;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.service.cmr.site.SiteInfo;
|
||||
import org.alfresco.service.cmr.site.SiteService;
|
||||
import org.springframework.extensions.surf.util.ParameterCheck;
|
||||
|
||||
/**
|
||||
* A simple handler to get the site title from the site short name.
|
||||
*
|
||||
* @author Jamal Kaabi-Mofrad
|
||||
* @since 5.0
|
||||
*/
|
||||
public class SiteTitleDisplayHandler extends AbstractFacetLabelDisplayHandler
|
||||
{
|
||||
|
||||
public SiteTitleDisplayHandler(Set<String> supportedFieldFacets)
|
||||
{
|
||||
ParameterCheck.mandatory("supportedFieldFacets", supportedFieldFacets);
|
||||
|
||||
this.supportedFieldFacets = Collections.unmodifiableSet(new HashSet<>(supportedFieldFacets));
|
||||
}
|
||||
|
||||
@Override
|
||||
public FacetLabel getDisplayLabel(String value)
|
||||
{
|
||||
SiteService siteService = serviceRegistry.getSiteService();
|
||||
SiteInfo siteInfo = siteService.getSite(value);
|
||||
String title = siteInfo != null ? siteInfo.getTitle() : value;
|
||||
return new FacetLabel(value, title, -1);
|
||||
}
|
||||
}
|
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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.handler;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.springframework.extensions.surf.util.ParameterCheck;
|
||||
|
||||
/**
|
||||
* A simple handler to get the full user name from the userID.
|
||||
*
|
||||
* @author Jamal Kaabi-Mofrad
|
||||
* @since 5.0
|
||||
*/
|
||||
public class UserNameDisplayHandler extends AbstractFacetLabelDisplayHandler
|
||||
{
|
||||
|
||||
public UserNameDisplayHandler(Set<String> supportedFieldFacets)
|
||||
{
|
||||
ParameterCheck.mandatory("supportedFieldFacets", supportedFieldFacets);
|
||||
|
||||
this.supportedFieldFacets = Collections.unmodifiableSet(new HashSet<>(supportedFieldFacets));
|
||||
}
|
||||
|
||||
@Override
|
||||
public FacetLabel getDisplayLabel(String value)
|
||||
{
|
||||
String name = null;
|
||||
|
||||
final NodeRef personRef = serviceRegistry.getPersonService().getPersonOrNull(value);
|
||||
if (personRef != null)
|
||||
{
|
||||
NodeService nodeService = serviceRegistry.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 new FacetLabel(value, name == null ? value : name.trim(), -1);
|
||||
}
|
||||
}
|
@@ -133,7 +133,7 @@ public class SolrFacetConfigTest
|
||||
|
||||
// See if the overrides worked
|
||||
SolrFacetProperties creatorFP = defaultProps.get("test_filter_creator");
|
||||
assertEquals("Incorrect QNAME", "{http://www.alfresco.org/model/content/1.0}creator.__.u", creatorFP.getFacetQName().toString());
|
||||
assertEquals("Incorrect QNAME", "{http://www.alfresco.org/model/content/1.0}creator", creatorFP.getFacetQName().toString());
|
||||
|
||||
String msg = "The value has not been overridden with the value from the custom properties";
|
||||
assertEquals(msg, 10, creatorFP.getMaxFilters());
|
||||
@@ -160,7 +160,7 @@ public class SolrFacetConfigTest
|
||||
config.onBootstrap(applicationEvent);
|
||||
|
||||
SolrFacetProperties creatorFP = config.getDefaultFacets().get("test_filter_creator");
|
||||
assertEquals("Incorrect QNAME", "{http://www.alfresco.org/model/content/1.0}creator.__.u", creatorFP.getFacetQName().toString());
|
||||
assertEquals("Incorrect QNAME", "{http://www.alfresco.org/model/content/1.0}creator", creatorFP.getFacetQName().toString());
|
||||
assertEquals(10, creatorFP.getMaxFilters());
|
||||
assertEquals(5, creatorFP.getHitThreshold());
|
||||
assertEquals(14, creatorFP.getMinFilterValueLength());
|
||||
@@ -175,7 +175,7 @@ public class SolrFacetConfigTest
|
||||
config.onBootstrap(applicationEvent);
|
||||
|
||||
creatorFP = config.getDefaultFacets().get("test_filter_creator");
|
||||
assertEquals("Incorrect QNAME", "{http://www.alfresco.org/model/content/1.0}creator.__.u", creatorFP.getFacetQName().toString());
|
||||
assertEquals("Incorrect QNAME", "{http://www.alfresco.org/model/content/1.0}creator", creatorFP.getFacetQName().toString());
|
||||
assertEquals(5, creatorFP.getMaxFilters());
|
||||
assertEquals(1, creatorFP.getHitThreshold());
|
||||
assertEquals(4, creatorFP.getMinFilterValueLength());
|
||||
|
@@ -21,32 +21,36 @@ package org.alfresco.repo.search.impl.solr.facet;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.alfresco.repo.search.impl.solr.facet.SolrFacetHelper.FacetLabel;
|
||||
|
||||
import org.alfresco.repo.search.impl.solr.facet.handler.FacetLabel;
|
||||
import org.alfresco.repo.search.impl.solr.facet.handler.FacetLabelDisplayHandler;
|
||||
import org.alfresco.repo.search.impl.solr.facet.handler.FacetLabelDisplayHandlerRegistry;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.util.ApplicationContextHelper;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.junit.*;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* This class contains tests for the class <code>{@link SolrFacetHelper}</code>.
|
||||
* This class contains tests for the class <code>{@link SolrFacetHelper}</code> and <code>{@link FacetLabelDisplayHandler}</code>.
|
||||
*
|
||||
* @author Jamal Kaabi-Mofrad
|
||||
* @since 5.0
|
||||
*/
|
||||
public class SolrFacetHelperTest
|
||||
public class SolrFacetQueriesDisplayHandlersTest
|
||||
{
|
||||
private static ApplicationContext context;
|
||||
private static SolrFacetHelper helper;
|
||||
private static FacetLabelDisplayHandlerRegistry displayHandlerRegistry;
|
||||
|
||||
@BeforeClass
|
||||
public static void initStaticData() throws Exception
|
||||
{
|
||||
context = ApplicationContextHelper.getApplicationContext();
|
||||
ServiceRegistry serviceRegistry = (ServiceRegistry) context.getBean("ServiceRegistry");
|
||||
helper = new SolrFacetHelper(serviceRegistry);
|
||||
|
||||
helper = (SolrFacetHelper) context.getBean("facet.solrFacetHelper");
|
||||
displayHandlerRegistry = (FacetLabelDisplayHandlerRegistry) context.getBean("facet.facetLabelDisplayHandlerRegistry");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -76,85 +80,44 @@ public class SolrFacetHelperTest
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the List<String> createFacetQueriesFromSearchQuery(String) method test.
|
||||
* Run the String createFacetQueriesFromSearchQuery(String) method test.
|
||||
*
|
||||
* @throws Exception
|
||||
*
|
||||
*/
|
||||
@Test
|
||||
public void testCreateFacetQueriesFromSearchQuery() throws Exception
|
||||
public void testCreateFacetQueryFromSearchQuery() throws Exception
|
||||
{
|
||||
String searchQueryWithCreatedDate = "query=(test AND ({http://www.alfresco.org/model/content/1.0}created:(\"2014-05-30\"..\"2014-06-06\" ))"
|
||||
String searchQueryWithCreatedDate = "query=(test AND ({http://www.alfresco.org/model/content/1.0}created:(\"NOW/DAY-7DAYS\"..\"NOW/DAY+1DAY\" ))"
|
||||
+ " AND (+TYPE:\"cm:content\" OR +TYPE:\"cm:folder\")) AND -TYPE:\"cm:thumbnail\" AND"
|
||||
+ " -TYPE:\"cm:failedThumbnail\" AND -TYPE:\"cm:rating\" AND -TYPE:\"st:site\" AND"
|
||||
+ " -ASPECT:\"st:siteContainer\" AND -ASPECT:\"sys:hidden\" AND"
|
||||
+ " -cm:creator:system, stores=[workspace://SpacesStore]";
|
||||
|
||||
List<String> result = helper.createFacetQueriesFromSearchQuery(searchQueryWithCreatedDate);
|
||||
String result = helper.createFacetQueriesFromSearchQuery("{http://www.alfresco.org/model/content/1.0}created", searchQueryWithCreatedDate);
|
||||
assertNotNull(result);
|
||||
assertEquals("@{http://www.alfresco.org/model/content/1.0}created:[NOW/DAY-7DAYS TO NOW/DAY+1DAY]", result);
|
||||
|
||||
LocalDate currentDate = LocalDate.now();
|
||||
String nowStr = " TO " + currentDate.toString();
|
||||
String yesterday = currentDate.minusDays(1).toString() + nowStr;
|
||||
String lastWeek = currentDate.minusWeeks(1).toString() + nowStr;
|
||||
String lastMonth = currentDate.minusMonths(1).toString() + nowStr;
|
||||
String last6Months = currentDate.minusMonths(6).toString() + nowStr;
|
||||
String lastYear = currentDate.minusYears(1).toString() + nowStr;
|
||||
|
||||
// As the created date has been specified in the search, we don't create
|
||||
// the rest of the buckets for the created date facet.
|
||||
assertEquals(12, result.size());
|
||||
|
||||
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}created:[2014-05-30 TO 2014-06-06]"));
|
||||
|
||||
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}modified:[" + yesterday + "]"));
|
||||
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}modified:[" + lastWeek + "]"));
|
||||
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}modified:[" + lastMonth + "]"));
|
||||
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}modified:[" + last6Months + "]"));
|
||||
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}modified:[" + lastYear + "]"));
|
||||
|
||||
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}content.size:[0 TO 10240]"));
|
||||
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}content.size:[10240 TO 102400]"));
|
||||
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}content.size:[102400 TO 1048576]"));
|
||||
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}content.size:[1048576 TO 16777216]"));
|
||||
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}content.size:[16777216 TO 134217728]"));
|
||||
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}content.size:[134217728 TO MAX]"));
|
||||
|
||||
String searchQueryWithCreatedAndModifiedDate = "query=(test AND ({http://www.alfresco.org/model/content/1.0}created:(\"2014-05-30\"..\"2014-06-06\" ) AND AND ({http://www.alfresco.org/model/content/1.0}modified:(\"2014-05-30\"..\"2014-05-31\" ))"
|
||||
String searchQueryWithCreatedAndModifiedDate = "query=(test AND ({http://www.alfresco.org/model/content/1.0}created:(\"NOW/DAY-7DAYS\"..\"NOW/DAY+1DAY\" ) AND ({http://www.alfresco.org/model/content/1.0}modified:(\"NOW/DAY-1DAY\"..\"NOW/DAY+1DAY\" ))"
|
||||
+ " AND (+TYPE:\"cm:content\" OR +TYPE:\"cm:folder\")) AND -TYPE:\"cm:thumbnail\" AND"
|
||||
+ " -TYPE:\"cm:failedThumbnail\" AND -TYPE:\"cm:rating\" AND -TYPE:\"st:site\" AND"
|
||||
+ " -ASPECT:\"st:siteContainer\" AND -ASPECT:\"sys:hidden\" AND"
|
||||
+ " -cm:creator:system, stores=[workspace://SpacesStore]";
|
||||
|
||||
result = helper.createFacetQueriesFromSearchQuery(searchQueryWithCreatedAndModifiedDate);
|
||||
String[] fields = { "{http://www.alfresco.org/model/content/1.0}created", "{http://www.alfresco.org/model/content/1.0}modified" };
|
||||
|
||||
result = helper.createFacetQueriesFromSearchQuery(fields[0], searchQueryWithCreatedAndModifiedDate);
|
||||
assertNotNull(result);
|
||||
assertEquals("@{http://www.alfresco.org/model/content/1.0}created:[NOW/DAY-7DAYS TO NOW/DAY+1DAY]", result);
|
||||
|
||||
currentDate = LocalDate.now();
|
||||
nowStr = " TO " + currentDate.toString();
|
||||
yesterday = currentDate.minusDays(1).toString() + nowStr;
|
||||
lastWeek = currentDate.minusWeeks(1).toString() + nowStr;
|
||||
lastMonth = currentDate.minusMonths(1).toString() + nowStr;
|
||||
last6Months = currentDate.minusMonths(6).toString() + nowStr;
|
||||
lastYear = currentDate.minusYears(1).toString() + nowStr;
|
||||
result = helper.createFacetQueriesFromSearchQuery(fields[1], searchQueryWithCreatedAndModifiedDate);
|
||||
assertNotNull(result);
|
||||
assertEquals("@{http://www.alfresco.org/model/content/1.0}modified:[NOW/DAY-1DAY TO NOW/DAY+1DAY]", result);
|
||||
|
||||
// As the created and modified dates have been specified in the search,
|
||||
// we don't create the rest of the buckets for the created and modified date facets.
|
||||
assertEquals(8, result.size());
|
||||
|
||||
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}created:[2014-05-30 TO 2014-06-06]"));
|
||||
|
||||
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}modified:[2014-05-30 TO 2014-05-31]"));
|
||||
|
||||
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}content.size:[0 TO 10240]"));
|
||||
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}content.size:[10240 TO 102400]"));
|
||||
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}content.size:[102400 TO 1048576]"));
|
||||
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}content.size:[1048576 TO 16777216]"));
|
||||
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}content.size:[16777216 TO 134217728]"));
|
||||
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}content.size:[134217728 TO MAX]"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the Set<String> getBucketedFieldFacets() method test.
|
||||
* Run the List<String> getBucketedFieldFacets() method test.
|
||||
*
|
||||
* @throws Exception
|
||||
*
|
||||
@@ -181,27 +144,19 @@ public class SolrFacetHelperTest
|
||||
{
|
||||
List<String> result = helper.getDefaultFacetQueries();
|
||||
|
||||
LocalDate currentDate = LocalDate.now();
|
||||
String nowStr = " TO " + currentDate.toString();
|
||||
String yesterday = currentDate.minusDays(1).toString() + nowStr;
|
||||
String lastWeek = currentDate.minusWeeks(1).toString() + nowStr;
|
||||
String lastMonth = currentDate.minusMonths(1).toString() + nowStr;
|
||||
String last6Months =currentDate.minusMonths(6).toString() + nowStr;
|
||||
String lastYear = currentDate.minusYears(1).toString() + nowStr;
|
||||
|
||||
assertNotNull(result);
|
||||
assertEquals(16, result.size());
|
||||
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}created:[" + yesterday + "]"));
|
||||
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}created:[" + lastWeek + "]"));
|
||||
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}created:[" + lastMonth + "]"));
|
||||
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}created:[" + last6Months + "]"));
|
||||
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}created:[" + lastYear + "]"));
|
||||
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}created:[NOW/DAY-1DAY TO NOW/DAY+1DAY]"));
|
||||
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}created:[NOW/DAY-7DAYS TO NOW/DAY+1DAY]"));
|
||||
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}created:[NOW/DAY-1MONTH TO NOW/DAY+1DAY]"));
|
||||
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}created:[NOW/DAY-6MONTHS TO NOW/DAY+1DAY]"));
|
||||
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}created:[NOW/DAY-1YEAR TO NOW/DAY+1DAY]"));
|
||||
|
||||
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}modified:[" + yesterday + "]"));
|
||||
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}modified:[" + lastWeek + "]"));
|
||||
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}modified:[" + lastMonth + "]"));
|
||||
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}modified:[" + last6Months + "]"));
|
||||
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}modified:[" + lastYear + "]"));
|
||||
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}modified:[NOW/DAY-1DAY TO NOW/DAY+1DAY]"));
|
||||
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}modified:[NOW/DAY-7DAYS TO NOW/DAY+1DAY]"));
|
||||
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}modified:[NOW/DAY-1MONTH TO NOW/DAY+1DAY]"));
|
||||
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}modified:[NOW/DAY-6MONTHS TO NOW/DAY+1DAY]"));
|
||||
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}modified:[NOW/DAY-1YEAR TO NOW/DAY+1DAY]"));
|
||||
|
||||
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}content.size:[0 TO 10240]"));
|
||||
assertTrue(result.contains("@{http://www.alfresco.org/model/content/1.0}content.size:[10240 TO 102400]"));
|
||||
@@ -212,16 +167,14 @@ public class SolrFacetHelperTest
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the SolrFacetHelper.FacetLabelDisplayHandler getDisplayHandler(String) method test.
|
||||
* User name display handler test.
|
||||
*
|
||||
* @throws Exception
|
||||
*
|
||||
*/
|
||||
@Test
|
||||
public void testGetUserNameDisplayHandler() throws Exception
|
||||
{
|
||||
// Username handler
|
||||
SolrFacetHelper.FacetLabelDisplayHandler userNameHandler = helper.getDisplayHandler("@{http://www.alfresco.org/model/content/1.0}creator.__.u");
|
||||
FacetLabelDisplayHandler userNameHandler = displayHandlerRegistry.getDisplayHandler("@{http://www.alfresco.org/model/content/1.0}creator");
|
||||
assertNotNull(userNameHandler);
|
||||
String randomUserName = "randomUserName" + System.currentTimeMillis();
|
||||
FacetLabel name = userNameHandler.getDisplayLabel(randomUserName);
|
||||
@@ -233,7 +186,7 @@ public class SolrFacetHelperTest
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the SolrFacetHelper.FacetLabelDisplayHandler getDisplayHandler(String) method test.
|
||||
* MimeType display handler test.
|
||||
*
|
||||
* @throws Exception
|
||||
*
|
||||
@@ -242,7 +195,7 @@ public class SolrFacetHelperTest
|
||||
public void testGetMimetypeDisplayHandler() throws Exception
|
||||
{
|
||||
// Mimetype handler
|
||||
SolrFacetHelper.FacetLabelDisplayHandler mimeTypeHandler = helper.getDisplayHandler("@{http://www.alfresco.org/model/content/1.0}content.mimetype");
|
||||
FacetLabelDisplayHandler mimeTypeHandler = displayHandlerRegistry.getDisplayHandler("@{http://www.alfresco.org/model/content/1.0}content.mimetype");
|
||||
assertNotNull(mimeTypeHandler);
|
||||
FacetLabel mimetype = mimeTypeHandler.getDisplayLabel("someMimetype123");
|
||||
assertNotNull(mimetype);
|
||||
@@ -253,54 +206,46 @@ public class SolrFacetHelperTest
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the SolrFacetHelper.FacetLabelDisplayHandler getDisplayHandler(String) method test.
|
||||
* Created date buckets display handler test.
|
||||
*
|
||||
* @throws Exception
|
||||
*
|
||||
*/
|
||||
@Test
|
||||
public void testGetDateBucketsDisplayHandler() throws Exception
|
||||
public void testGetCreatedDateBucketsDisplayHandler() throws Exception
|
||||
{
|
||||
// Date buckets handler
|
||||
SolrFacetHelper.FacetLabelDisplayHandler dateBucketeHandler = helper.getDisplayHandler("@{http://www.alfresco.org/model/content/1.0}created");
|
||||
final String createdDateField = "@{http://www.alfresco.org/model/content/1.0}created";
|
||||
FacetLabelDisplayHandler dateBucketeHandler = displayHandlerRegistry.getDisplayHandler(createdDateField);
|
||||
assertNotNull(dateBucketeHandler);
|
||||
|
||||
LocalDate currentDate = LocalDate.now();
|
||||
String nowStr = " TO " + currentDate.toString();
|
||||
String yesterday = '[' + currentDate.minusDays(1).toString() + nowStr + ']';
|
||||
String lastWeek = '[' + currentDate.minusWeeks(1).toString() + nowStr + ']';
|
||||
String lastMonth = '[' + currentDate.minusMonths(1).toString() + nowStr + ']';
|
||||
String last6Months = '[' + currentDate.minusMonths(6).toString() + nowStr + ']';
|
||||
String lastYear = '[' + currentDate.minusYears(1).toString() + nowStr + ']';
|
||||
|
||||
FacetLabel dateLabel = dateBucketeHandler.getDisplayLabel(yesterday);
|
||||
FacetLabel dateLabel = dateBucketeHandler.getDisplayLabel(createdDateField+":[NOW/DAY-1DAY TO NOW/DAY+1DAY]");
|
||||
assertNotNull(dateLabel);
|
||||
assertEquals("faceted-search.date.one-day.label", dateLabel.getLabel());
|
||||
assertEquals("Yesterday date bucket should have a sorting index of 0.", 0, dateLabel.getLabelIndex());
|
||||
|
||||
dateLabel = dateBucketeHandler.getDisplayLabel(lastWeek);
|
||||
dateLabel = dateBucketeHandler.getDisplayLabel(createdDateField+":[NOW/DAY-7DAYS TO NOW/DAY+1DAY]");
|
||||
assertNotNull(dateLabel);
|
||||
assertEquals("faceted-search.date.one-week.label", dateLabel.getLabel());
|
||||
assertEquals("Last week date bucket should have a sorting index of 1.", 1, dateLabel.getLabelIndex());
|
||||
|
||||
dateLabel = dateBucketeHandler.getDisplayLabel(lastMonth);
|
||||
dateLabel = dateBucketeHandler.getDisplayLabel(createdDateField+":[NOW/DAY-1MONTH TO NOW/DAY+1DAY]");
|
||||
assertNotNull(dateLabel);
|
||||
assertEquals("faceted-search.date.one-month.label", dateLabel.getLabel());
|
||||
assertEquals("Last month date bucket should have a sorting index of 2.", 2, dateLabel.getLabelIndex());
|
||||
|
||||
dateLabel = dateBucketeHandler.getDisplayLabel(last6Months);
|
||||
dateLabel = dateBucketeHandler.getDisplayLabel(createdDateField+":[NOW/DAY-6MONTHS TO NOW/DAY+1DAY]");
|
||||
assertNotNull(dateLabel);
|
||||
assertEquals("faceted-search.date.six-months.label", dateLabel.getLabel());
|
||||
assertEquals("Last 6 months date bucket should have a sorting index of 3.", 3, dateLabel.getLabelIndex());
|
||||
|
||||
dateLabel = dateBucketeHandler.getDisplayLabel(lastYear);
|
||||
dateLabel = dateBucketeHandler.getDisplayLabel(createdDateField+":[NOW/DAY-1YEAR TO NOW/DAY+1DAY]");
|
||||
assertNotNull(dateLabel);
|
||||
assertEquals("faceted-search.date.one-year.label", dateLabel.getLabel());
|
||||
assertEquals("Last year date bucket should have a sorting index of 4.", 4, dateLabel.getLabelIndex());
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the SolrFacetHelper.FacetLabelDisplayHandler getDisplayHandler(String) method test.
|
||||
* Content size buckets display handler test.
|
||||
*
|
||||
* @throws Exception
|
||||
*
|
||||
@@ -308,8 +253,8 @@ public class SolrFacetHelperTest
|
||||
@Test
|
||||
public void testGetContentSizeBucketsDisplayHandler() throws Exception
|
||||
{
|
||||
// Date buckets handler
|
||||
SolrFacetHelper.FacetLabelDisplayHandler contentSizeBucketeHandler = helper.getDisplayHandler("@{http://www.alfresco.org/model/content/1.0}content.size");
|
||||
final String contentSizeField = "@{http://www.alfresco.org/model/content/1.0}content.size";
|
||||
FacetLabelDisplayHandler contentSizeBucketeHandler = displayHandlerRegistry.getDisplayHandler(contentSizeField);
|
||||
assertNotNull(contentSizeBucketeHandler);
|
||||
|
||||
int KB = 1024;
|
||||
@@ -320,34 +265,56 @@ public class SolrFacetHelperTest
|
||||
int large = 16 * MB;
|
||||
int huge = 128 * MB;
|
||||
|
||||
FacetLabel sizeLabel = contentSizeBucketeHandler.getDisplayLabel("[0 TO " + tiny + "]");
|
||||
|
||||
FacetLabel sizeLabel = contentSizeBucketeHandler.getDisplayLabel(contentSizeField + ":[0 TO " + tiny + "]");
|
||||
assertNotNull(sizeLabel);
|
||||
assertEquals("faceted-search.size.0-10KB.label", sizeLabel.getLabel());
|
||||
assertEquals("0-10KB size bucket should have a sorting index of 0.", 0, sizeLabel.getLabelIndex());
|
||||
|
||||
sizeLabel = contentSizeBucketeHandler.getDisplayLabel("[" + tiny + " TO " + small + "]");
|
||||
sizeLabel = contentSizeBucketeHandler.getDisplayLabel(contentSizeField + ":[" + tiny + " TO " + small + "]");
|
||||
assertNotNull(sizeLabel);
|
||||
assertEquals("faceted-search.size.10-100KB.label", sizeLabel.getLabel());
|
||||
assertEquals("10-100KB size bucket should have a sorting index of 1.", 1, sizeLabel.getLabelIndex());
|
||||
|
||||
sizeLabel = contentSizeBucketeHandler.getDisplayLabel("[" + small + " TO " + medium + "]");
|
||||
sizeLabel = contentSizeBucketeHandler.getDisplayLabel(contentSizeField + ":[" + small + " TO " + medium + "]");
|
||||
assertNotNull(sizeLabel);
|
||||
assertEquals("faceted-search.size.100KB-1MB.label", sizeLabel.getLabel());
|
||||
assertEquals("100KB-1MB size bucket should have a sorting index of 2.", 2, sizeLabel.getLabelIndex());
|
||||
|
||||
sizeLabel = contentSizeBucketeHandler.getDisplayLabel("[" + medium + " TO " + large + "]");
|
||||
sizeLabel = contentSizeBucketeHandler.getDisplayLabel(contentSizeField + ":[" + medium + " TO " + large + "]");
|
||||
assertNotNull(sizeLabel);
|
||||
assertEquals("faceted-search.size.1-16MB.label", sizeLabel.getLabel());
|
||||
assertEquals("1-16MB size bucket should have a sorting index of 3.", 3, sizeLabel.getLabelIndex());
|
||||
|
||||
sizeLabel = contentSizeBucketeHandler.getDisplayLabel("[" + large + " TO " + huge + "]");
|
||||
sizeLabel = contentSizeBucketeHandler.getDisplayLabel(contentSizeField + ":[" + large + " TO " + huge + "]");
|
||||
assertNotNull(sizeLabel);
|
||||
assertEquals("faceted-search.size.16-128MB.label", sizeLabel.getLabel());
|
||||
assertEquals("16-128MB size bucket should have a sorting index of 4.", 4, sizeLabel.getLabelIndex());
|
||||
|
||||
sizeLabel = contentSizeBucketeHandler.getDisplayLabel("[" + huge + " TO MAX]");
|
||||
sizeLabel = contentSizeBucketeHandler.getDisplayLabel(contentSizeField + ":[" + huge + " TO MAX]");
|
||||
assertNotNull(sizeLabel);
|
||||
assertEquals("faceted-search.size.over128.label", sizeLabel.getLabel());
|
||||
assertEquals("over128MB size bucket should have a sorting index of 5.", 5, sizeLabel.getLabelIndex());
|
||||
}
|
||||
|
||||
/**
|
||||
* Site title display handler test.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testGetSiteTitleDisplayHandler() throws Exception
|
||||
{
|
||||
String defaultSiteName= "swsdp";
|
||||
FacetLabelDisplayHandler siteHandler = displayHandlerRegistry.getDisplayHandler("SITE");
|
||||
assertNotNull(siteHandler);
|
||||
|
||||
String randomSiteName = "randomSiteName" + System.currentTimeMillis();
|
||||
FacetLabel name = siteHandler.getDisplayLabel(randomSiteName);
|
||||
assertNotNull(name);
|
||||
assertEquals("There is no site with the name [" + randomSiteName + "], hence, the handler should return the passed-in short name.", randomSiteName, name.getLabel());
|
||||
name = siteHandler.getDisplayLabel(defaultSiteName);
|
||||
assertNotNull(name);
|
||||
assertEquals("Sample: Web Site Design Project", name.getLabel());
|
||||
}
|
||||
}
|
@@ -37,7 +37,7 @@ public class SolrFacetTestSuite extends TestSuite
|
||||
public static Test suite()
|
||||
{
|
||||
TestSuite suite = new TestSuite();
|
||||
suite.addTest(new JUnit4TestAdapter(SolrFacetHelperTest.class));
|
||||
suite.addTest(new JUnit4TestAdapter(SolrFacetQueriesDisplayHandlersTest.class));
|
||||
suite.addTest(new JUnit4TestAdapter(SolrFacetServiceImplTest.class));
|
||||
suite.addTest(new JUnit4TestAdapter(SolrFacetConfigTest.class));
|
||||
|
||||
|
@@ -1,15 +1,15 @@
|
||||
# Overrides test_filter_creator in the /facets/facets-config-sample.properties
|
||||
custom.cm\:creator.__.u.filterID=test_filter_creator
|
||||
custom.cm\:creator.__.u.displayName=faceted-search.facet-menu.facet.creator
|
||||
custom.cm\:creator.__.u.displayControl=alfresco/search/FacetFilters
|
||||
custom.cm\:creator.__.u.maxFilters=10
|
||||
custom.cm\:creator.__.u.hitThreshold=5
|
||||
custom.cm\:creator.__.u.minFilterValueLength=14
|
||||
custom.cm\:creator.__.u.sortBy=ALPHABETICALLY
|
||||
custom.cm\:creator.__.u.scope=ALL
|
||||
custom.cm\:creator.__.u.scopedSites=site1
|
||||
custom.cm\:creator.__.u.index=0
|
||||
custom.cm\:creator.__.u.isEnabled=true
|
||||
custom.cm\:creator.filterID=test_filter_creator
|
||||
custom.cm\:creator.displayName=faceted-search.facet-menu.facet.creator
|
||||
custom.cm\:creator.displayControl=alfresco/search/FacetFilters
|
||||
custom.cm\:creator.maxFilters=10
|
||||
custom.cm\:creator.hitThreshold=5
|
||||
custom.cm\:creator.minFilterValueLength=14
|
||||
custom.cm\:creator.sortBy=ALPHABETICALLY
|
||||
custom.cm\:creator.scope=ALL
|
||||
custom.cm\:creator.scopedSites=site1
|
||||
custom.cm\:creator.index=0
|
||||
custom.cm\:creator.isEnabled=true
|
||||
|
||||
# Add a new Filter
|
||||
# Field-Facet-Qname => cm:description.__
|
||||
|
@@ -1,26 +1,26 @@
|
||||
# Field-Facet-Qname => cm:creator.__.u
|
||||
default.cm\:creator.__.u.filterID=test_filter_creator
|
||||
default.cm\:creator.__.u.displayName=faceted-search.facet-menu.facet.creator
|
||||
default.cm\:creator.__.u.displayControl=alfresco/search/FacetFilters
|
||||
default.cm\:creator.__.u.maxFilters=5
|
||||
default.cm\:creator.__.u.hitThreshold=1
|
||||
default.cm\:creator.__.u.minFilterValueLength=4
|
||||
default.cm\:creator.__.u.sortBy=ALPHABETICALLY
|
||||
default.cm\:creator.__.u.scope=ALL
|
||||
default.cm\:creator.__.u.scopedSites=
|
||||
default.cm\:creator.__.u.isEnabled=true
|
||||
# Field-Facet-Qname => cm:creator
|
||||
default.cm\:creator.filterID=test_filter_creator
|
||||
default.cm\:creator.displayName=faceted-search.facet-menu.facet.creator
|
||||
default.cm\:creator.displayControl=alfresco/search/FacetFilters
|
||||
default.cm\:creator.maxFilters=5
|
||||
default.cm\:creator.hitThreshold=1
|
||||
default.cm\:creator.minFilterValueLength=4
|
||||
default.cm\:creator.sortBy=ALPHABETICALLY
|
||||
default.cm\:creator.scope=ALL
|
||||
default.cm\:creator.scopedSites=
|
||||
default.cm\:creator.isEnabled=true
|
||||
|
||||
# Field-Facet-Qname => cm:modifier.__.u
|
||||
default.cm\:modifier.__.u.filterID=test_filter_modifier
|
||||
default.cm\:modifier.__.u.displayName=faceted-search.facet-menu.facet.modifier
|
||||
default.cm\:modifier.__.u.displayControl=alfresco/search/FacetFilters
|
||||
default.cm\:modifier.__.u.maxFilters=5
|
||||
default.cm\:modifier.__.u.hitThreshold=1
|
||||
default.cm\:modifier.__.u.minFilterValueLength=4
|
||||
default.cm\:modifier.__.u.sortBy=ALPHABETICALLY
|
||||
default.cm\:modifier.__.u.scope=SCOPED_SITES
|
||||
default.cm\:modifier.__.u.scopedSites=
|
||||
default.cm\:modifier.__.u.isEnabled=true
|
||||
# Field-Facet-Qname => cm:modifier
|
||||
default.cm\:modifier.filterID=test_filter_modifier
|
||||
default.cm\:modifier.displayName=faceted-search.facet-menu.facet.modifier
|
||||
default.cm\:modifier.displayControl=alfresco/search/FacetFilters
|
||||
default.cm\:modifier.maxFilters=5
|
||||
default.cm\:modifier.hitThreshold=1
|
||||
default.cm\:modifier.minFilterValueLength=4
|
||||
default.cm\:modifier.sortBy=ALPHABETICALLY
|
||||
default.cm\:modifier.scope=SCOPED_SITES
|
||||
default.cm\:modifier.scopedSites=
|
||||
default.cm\:modifier.isEnabled=true
|
||||
|
||||
# Field-Facet-Qname => cm:content.size
|
||||
default.cm\:content.size.filterID=test_filter_content_size
|
||||
|
Reference in New Issue
Block a user