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">
|
<property name="repositoryHelper">
|
||||||
<ref bean="repositoryHelper"/>
|
<ref bean="repositoryHelper"/>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="solrFacetHelper">
|
||||||
|
<ref bean="facet.solrFacetHelper"/>
|
||||||
|
</property>
|
||||||
|
<property name="facetLabelDisplayHandlerRegistry">
|
||||||
|
<ref bean="facet.facetLabelDisplayHandlerRegistry"/>
|
||||||
|
</property>
|
||||||
<property name="storeUrl">
|
<property name="storeUrl">
|
||||||
<value>${spaces.store}</value>
|
<value>${spaces.store}</value>
|
||||||
</property>
|
</property>
|
||||||
|
@@ -43,4 +43,118 @@
|
|||||||
<value>${solr_facets.root}</value>
|
<value>${solr_facets.root}</value>
|
||||||
</property>
|
</property>
|
||||||
</bean>
|
</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>
|
</beans>
|
@@ -15,41 +15,41 @@ default.cm\:content.mimetype.scope=ALL
|
|||||||
default.cm\:content.mimetype.scopedSites=
|
default.cm\:content.mimetype.scopedSites=
|
||||||
default.cm\:content.mimetype.isEnabled=true
|
default.cm\:content.mimetype.isEnabled=true
|
||||||
|
|
||||||
# Field-Facet-Qname => cm:description.__
|
# Field-Facet-Qname => cm:description
|
||||||
default.cm\:description.__.filterID=filter_description
|
default.cm\:description.filterID=filter_description
|
||||||
default.cm\:description.__.displayName=faceted-search.facet-menu.facet.description
|
default.cm\:description.displayName=faceted-search.facet-menu.facet.description
|
||||||
default.cm\:description.__.displayControl=alfresco/search/FacetFilters
|
default.cm\:description.displayControl=alfresco/search/FacetFilters
|
||||||
default.cm\:description.__.maxFilters=5
|
default.cm\:description.maxFilters=5
|
||||||
default.cm\:description.__.hitThreshold=1
|
default.cm\:description.hitThreshold=1
|
||||||
default.cm\:description.__.minFilterValueLength=4
|
default.cm\:description.minFilterValueLength=4
|
||||||
default.cm\:description.__.sortBy=DESCENDING
|
default.cm\:description.sortBy=DESCENDING
|
||||||
default.cm\:description.__.scope=ALL
|
default.cm\:description.scope=ALL
|
||||||
default.cm\:description.__.scopedSites=
|
default.cm\:description.scopedSites=
|
||||||
default.cm\:description.__.isEnabled=false
|
default.cm\:description.isEnabled=false
|
||||||
|
|
||||||
# Field-Facet-Qname => cm:creator.__.u
|
# Field-Facet-Qname => cm:creator
|
||||||
default.cm\:creator.__.u.filterID=filter_creator
|
default.cm\:creator.filterID=filter_creator
|
||||||
default.cm\:creator.__.u.displayName=faceted-search.facet-menu.facet.creator
|
default.cm\:creator.displayName=faceted-search.facet-menu.facet.creator
|
||||||
default.cm\:creator.__.u.displayControl=alfresco/search/FacetFilters
|
default.cm\:creator.displayControl=alfresco/search/FacetFilters
|
||||||
default.cm\:creator.__.u.maxFilters=5
|
default.cm\:creator.maxFilters=5
|
||||||
default.cm\:creator.__.u.hitThreshold=1
|
default.cm\:creator.hitThreshold=1
|
||||||
default.cm\:creator.__.u.minFilterValueLength=4
|
default.cm\:creator.minFilterValueLength=4
|
||||||
default.cm\:creator.__.u.sortBy=ALPHABETICALLY
|
default.cm\:creator.sortBy=ALPHABETICALLY
|
||||||
default.cm\:creator.__.u.scope=ALL
|
default.cm\:creator.scope=ALL
|
||||||
default.cm\:creator.__.u.scopedSites=
|
default.cm\:creator.scopedSites=
|
||||||
default.cm\:creator.__.u.isEnabled=true
|
default.cm\:creator.isEnabled=true
|
||||||
|
|
||||||
# Field-Facet-Qname => cm:modifier.__.u
|
# Field-Facet-Qname => cm:modifier
|
||||||
default.cm\:modifier.__.u.filterID=filter_modifier
|
default.cm\:modifier.filterID=filter_modifier
|
||||||
default.cm\:modifier.__.u.displayName=faceted-search.facet-menu.facet.modifier
|
default.cm\:modifier.displayName=faceted-search.facet-menu.facet.modifier
|
||||||
default.cm\:modifier.__.u.displayControl=alfresco/search/FacetFilters
|
default.cm\:modifier.displayControl=alfresco/search/FacetFilters
|
||||||
default.cm\:modifier.__.u.maxFilters=5
|
default.cm\:modifier.maxFilters=5
|
||||||
default.cm\:modifier.__.u.hitThreshold=1
|
default.cm\:modifier.hitThreshold=1
|
||||||
default.cm\:modifier.__.u.minFilterValueLength=4
|
default.cm\:modifier.minFilterValueLength=4
|
||||||
default.cm\:modifier.__.u.sortBy=ALPHABETICALLY
|
default.cm\:modifier.sortBy=ALPHABETICALLY
|
||||||
default.cm\:modifier.__.u.scope=ALL
|
default.cm\:modifier.scope=ALL
|
||||||
default.cm\:modifier.__.u.scopedSites=
|
default.cm\:modifier.scopedSites=
|
||||||
default.cm\:modifier.__.u.isEnabled=true
|
default.cm\:modifier.isEnabled=true
|
||||||
|
|
||||||
# Field-Facet-Qname => cm:created
|
# Field-Facet-Qname => cm:created
|
||||||
default.cm\:created.filterID=filter_created
|
default.cm\:created.filterID=filter_created
|
||||||
@@ -62,7 +62,6 @@ default.cm\:created.sortBy=ALPHABETICALLY
|
|||||||
default.cm\:created.scope=ALL
|
default.cm\:created.scope=ALL
|
||||||
default.cm\:created.scopedSites=
|
default.cm\:created.scopedSites=
|
||||||
default.cm\:created.isEnabled=true
|
default.cm\:created.isEnabled=true
|
||||||
default.cm\:created.EXTRA-PROP.blockIncludeFacetRequest=true
|
|
||||||
|
|
||||||
# Field-Facet-Qname => cm:modified
|
# Field-Facet-Qname => cm:modified
|
||||||
default.cm\:modified.filterID=filter_modified
|
default.cm\:modified.filterID=filter_modified
|
||||||
@@ -75,7 +74,6 @@ default.cm\:modified.sortBy=ALPHABETICALLY
|
|||||||
default.cm\:modified.scope=ALL
|
default.cm\:modified.scope=ALL
|
||||||
default.cm\:modified.scopedSites=
|
default.cm\:modified.scopedSites=
|
||||||
default.cm\:modified.isEnabled=true
|
default.cm\:modified.isEnabled=true
|
||||||
default.cm\:modified.EXTRA-PROP.blockIncludeFacetRequest=true
|
|
||||||
|
|
||||||
# Field-Facet-Qname => cm:content.size
|
# Field-Facet-Qname => cm:content.size
|
||||||
default.cm\:content.size.filterID=filter_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.scope=ALL
|
||||||
default.cm\:content.size.scopedSites=
|
default.cm\:content.size.scopedSites=
|
||||||
default.cm\:content.size.isEnabled=true
|
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.management.subsystems.SwitchableApplicationContextFactory;
|
||||||
import org.alfresco.repo.model.Repository;
|
import org.alfresco.repo.model.Repository;
|
||||||
import org.alfresco.repo.search.impl.solr.facet.SolrFacetHelper;
|
import org.alfresco.repo.search.impl.solr.facet.SolrFacetHelper;
|
||||||
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.SolrFacetHelper.FacetLabelDisplayHandler;
|
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.ServiceRegistry;
|
||||||
import org.alfresco.service.cmr.repository.ContentReader;
|
import org.alfresco.service.cmr.repository.ContentReader;
|
||||||
import org.alfresco.service.cmr.repository.NodeRef;
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
@@ -96,12 +97,14 @@ public class Search extends BaseScopableProcessorExtension implements Initializi
|
|||||||
/** Solr facet helper */
|
/** Solr facet helper */
|
||||||
private SolrFacetHelper solrFacetHelper;
|
private SolrFacetHelper solrFacetHelper;
|
||||||
|
|
||||||
|
private FacetLabelDisplayHandlerRegistry facetLabelDisplayHandlerRegistry;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterPropertiesSet() throws Exception
|
public void afterPropertiesSet() throws Exception
|
||||||
{
|
{
|
||||||
PropertyCheck.mandatory(this, "services", services);
|
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
|
// 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()
|
public String getSearchSubsystem()
|
||||||
{
|
{
|
||||||
return (searchSubsystem == null) ? "" : searchSubsystem.getCurrentSourceBeanName();
|
return (searchSubsystem == null) ? "" : searchSubsystem.getCurrentSourceBeanName();
|
||||||
@@ -716,6 +733,14 @@ public class Search extends BaseScopableProcessorExtension implements Initializi
|
|||||||
if (facets != null)
|
if (facets != null)
|
||||||
{
|
{
|
||||||
for (String field: facets)
|
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;
|
final FieldFacet fieldFacet;
|
||||||
if (solrFacetHelper.isSpecialFacetId(field))
|
if (solrFacetHelper.isSpecialFacetId(field))
|
||||||
@@ -724,24 +749,10 @@ public class Search extends BaseScopableProcessorExtension implements Initializi
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fieldFacet = new FieldFacet("@" + field);
|
fieldFacet = new FieldFacet(modifiedField);
|
||||||
}
|
}
|
||||||
sp.addFieldFacet(fieldFacet);
|
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)
|
if (f.getSecond() > 0)
|
||||||
{
|
{
|
||||||
String facetValue = f.getFirst();
|
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();
|
String label = (handler == null) ? facetValue : handler.getDisplayLabel(facetValue).getLabel();
|
||||||
|
|
||||||
facets.add(new ScriptFacetResult(facetValue, label, -1, f.getSecond()));
|
facets.add(new ScriptFacetResult(facetValue, label, -1, f.getSecond()));
|
||||||
@@ -979,22 +990,22 @@ public class Search extends BaseScopableProcessorExtension implements Initializi
|
|||||||
if (entry.getValue() > 0)
|
if (entry.getValue() > 0)
|
||||||
{
|
{
|
||||||
String key = entry.getKey();
|
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
|
// qName => @{http://www.alfresco.org/model/content/1.0}created
|
||||||
// 7 => {!afts}
|
// 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
|
// Retrieve the previous facet queries
|
||||||
List<ScriptFacetResult> fqs = facetMeta.get(qName);
|
List<ScriptFacetResult> fqs = facetMeta.get(qName);
|
||||||
if (fqs == null)
|
if (fqs == null)
|
||||||
{
|
{
|
||||||
// Shouldn't be here
|
fqs = new ArrayList<>();
|
||||||
throw new AlfrescoRuntimeException("Field facet [" + qName + "] has"
|
logger.info("Field facet [" + key + "] has not been registered.");
|
||||||
+ " not been registered with SolrFacetHelper.BUCKETED_FIELD_FACETS.");
|
|
||||||
}
|
}
|
||||||
FacetLabelDisplayHandler handler = solrFacetHelper.getDisplayHandler(qName);
|
// Get the handler for this qName
|
||||||
FacetLabel facetLabel = (handler == null) ? new FacetLabel(qName, key.substring(qName.length(),
|
FacetLabelDisplayHandler handler = facetLabelDisplayHandlerRegistry.getDisplayHandler(qName);
|
||||||
key.length()), -1) : handler.getDisplayLabel(key);
|
FacetLabel facetLabel = (handler == null) ? new FacetLabel(key, key, -1) : handler.getDisplayLabel(key);
|
||||||
|
|
||||||
fqs.add(new ScriptFacetResult(facetLabel.getValue(), facetLabel.getLabel(), facetLabel.getLabelIndex(), entry.getValue()));
|
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);
|
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
|
* 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
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.alfresco.repo.search.impl.solr.facet;
|
package org.alfresco.repo.search.impl.solr.facet;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
import java.util.Set;
|
import 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.util.PropertyCheck;
|
||||||
import org.alfresco.model.ContentModel;
|
|
||||||
import org.alfresco.service.ServiceRegistry;
|
|
||||||
import org.alfresco.service.cmr.repository.MimetypeService;
|
|
||||||
import org.alfresco.service.cmr.repository.NodeRef;
|
|
||||||
import org.alfresco.service.cmr.repository.NodeService;
|
|
||||||
import org.alfresco.service.cmr.security.PersonService;
|
|
||||||
import org.alfresco.util.Pair;
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
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.
|
* A helper class for facet queries.
|
||||||
* <p>
|
|
||||||
* Notice: probably this class or most of its functionalities will be removed
|
|
||||||
* when we upgrade to Solr 4
|
|
||||||
*
|
*
|
||||||
* @author Jamal Kaabi-Mofrad
|
* @author Jamal Kaabi-Mofrad
|
||||||
|
* @since 5.0
|
||||||
*/
|
*/
|
||||||
// TODO use Solr4 date math for date buckets...
|
|
||||||
public class SolrFacetHelper
|
public class SolrFacetHelper
|
||||||
{
|
{
|
||||||
private static Log logger = LogFactory.getLog(SolrFacetHelper.class);
|
private static Log logger = LogFactory.getLog(SolrFacetHelper.class);
|
||||||
|
|
||||||
private static final String FQ_NS_PREFIX = "@{http://www.alfresco.org/model/content/1.0}";
|
private final Map<String, List<String>> facetQueries;
|
||||||
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";
|
|
||||||
|
|
||||||
// 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";
|
/** These facet IDs are recognised by SOLR and can be used directly within faceted searches. */
|
||||||
|
private Set<String> specialFacetIds = Collections.emptySet();
|
||||||
// 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;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
* @param serviceRegistry
|
* @param serviceRegistry
|
||||||
*/
|
*/
|
||||||
public SolrFacetHelper(ServiceRegistry serviceRegistry)
|
public SolrFacetHelper(List<FacetQueryProvider> facetQueryProviders)
|
||||||
{
|
{
|
||||||
this.fqDateCache = new BucketsCache<>(new FacetQueryParamDateBuckets());
|
PropertyCheck.mandatory(this, "facetQueryProviders", facetQueryProviders);
|
||||||
this.displayHandlers = new HashMap<>(6);
|
|
||||||
|
|
||||||
UserNameDisplayHandler userNameDisplayHandler = new UserNameDisplayHandler(serviceRegistry);
|
facetQueries = new LinkedHashMap<>();
|
||||||
MimetypeDisplayHandler mimetypeDisplayHandler = new MimetypeDisplayHandler(serviceRegistry);
|
for (FacetQueryProvider queryProvider : facetQueryProviders)
|
||||||
DateBucketsDisplayHandler dateBucketsDisplayHandler = new DateBucketsDisplayHandler();
|
{
|
||||||
ContentSizeBucketsDisplayHandler contentSizeBucketsDisplayHandler = new ContentSizeBucketsDisplayHandler();
|
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);
|
public void setSpecialFacetIds(Set<String> ids)
|
||||||
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.specialFacetIds = ids;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the predefined set of facet queries. Currently the facet queries are:
|
* Gets the predefined set of facet queries. Currently the facet queries
|
||||||
* <li>Created date buckets</li>
|
* are: <li>Created date buckets</li> <li>Modified date buckets</li> <li>
|
||||||
* <li>Modified date buckets</li>
|
* Content size buckets</li>
|
||||||
* <li>Content size buckets</li>
|
|
||||||
*
|
*
|
||||||
* @return list of facet queries
|
* @return list of facet queries
|
||||||
*/
|
*/
|
||||||
public List<String> getDefaultFacetQueries()
|
public List<String> getDefaultFacetQueries()
|
||||||
{
|
{
|
||||||
List<String> facetQueries = new ArrayList<>();
|
Collection<List<String>> queries = facetQueries.values();
|
||||||
List<String> dateBuckets = getDateBuckets();
|
List<String> list = new ArrayList<String>();
|
||||||
|
for (List<String> q : queries)
|
||||||
// Created and Modified dates facet queries
|
|
||||||
for (String bucket : dateBuckets)
|
|
||||||
{
|
{
|
||||||
facetQueries.add(CREATED_FIELD_FACET_QUERY + ":[" + bucket + ']');
|
list.addAll(q);
|
||||||
facetQueries.add(MODIFIED_FIELD_FACET_QUERY + ":[" + bucket + ']');
|
|
||||||
}
|
}
|
||||||
|
return list;
|
||||||
// Content size facet query
|
|
||||||
for (String bucket : CONTENT_SIZE_BUCKETS)
|
|
||||||
{
|
|
||||||
facetQueries.add(CONTENT_SIZE_FIELD_FACET_QUERY + ":[" + bucket + ']');
|
|
||||||
}
|
|
||||||
|
|
||||||
return facetQueries;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates <i>Created</i> and <i>Modified</i> facet queries by trying to
|
* Whether the specified field is defined as a <i>facet.query</i> or not
|
||||||
* 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.
|
|
||||||
*
|
*
|
||||||
* @return list of facet queries
|
* @param facetField
|
||||||
|
* @return true if the facet is <i>facet.query</i>, false otherwise
|
||||||
*/
|
*/
|
||||||
// ACE-1605
|
public boolean hasFacetQueries(String facetField)
|
||||||
public List<String> createFacetQueriesFromSearchQuery(String searchQuery)
|
|
||||||
{
|
{
|
||||||
String createdDateRange = extractDateRange(searchQuery, CREATED_DATE_PATTERN);
|
return facetQueries.containsKey(facetField);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the date range that will match against the pattern from the search query
|
* Gets all the defined facet queries for the specified field
|
||||||
*
|
* @param facetField the requested field
|
||||||
* @param searchQuery the string input
|
* @return an unmodifiable list of facet queries, or null if none found
|
||||||
* @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
|
|
||||||
*/
|
*/
|
||||||
private String extractDateRange(String searchQuery, Pattern pattern)
|
public List<String> getFacetQueries(String facetField)
|
||||||
{
|
{
|
||||||
String dateRange = null;
|
List<String> queries = facetQueries.get(facetField);
|
||||||
Matcher matcher = pattern.matcher(searchQuery);
|
if (queries == null)
|
||||||
if (matcher.find())
|
|
||||||
{
|
{
|
||||||
dateRange = matcher.group();
|
return null;
|
||||||
// E.g. dateRange => 2014-04-28".."2014-04-29
|
|
||||||
}
|
}
|
||||||
|
return Collections.unmodifiableList(queries);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -292,9 +123,50 @@ public class SolrFacetHelper
|
|||||||
*/
|
*/
|
||||||
public Set<String> getBucketedFieldFacets()
|
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
|
* Is the specified facet ID part of the list of "specials" which are
|
||||||
* handled by our SOLR service as is?
|
* handled by our SOLR service as is?
|
||||||
@@ -303,440 +175,4 @@ public class SolrFacetHelper
|
|||||||
{
|
{
|
||||||
return specialFacetIds.contains(facetId);
|
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
|
// See if the overrides worked
|
||||||
SolrFacetProperties creatorFP = defaultProps.get("test_filter_creator");
|
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";
|
String msg = "The value has not been overridden with the value from the custom properties";
|
||||||
assertEquals(msg, 10, creatorFP.getMaxFilters());
|
assertEquals(msg, 10, creatorFP.getMaxFilters());
|
||||||
@@ -160,7 +160,7 @@ public class SolrFacetConfigTest
|
|||||||
config.onBootstrap(applicationEvent);
|
config.onBootstrap(applicationEvent);
|
||||||
|
|
||||||
SolrFacetProperties creatorFP = config.getDefaultFacets().get("test_filter_creator");
|
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(10, creatorFP.getMaxFilters());
|
||||||
assertEquals(5, creatorFP.getHitThreshold());
|
assertEquals(5, creatorFP.getHitThreshold());
|
||||||
assertEquals(14, creatorFP.getMinFilterValueLength());
|
assertEquals(14, creatorFP.getMinFilterValueLength());
|
||||||
@@ -175,7 +175,7 @@ public class SolrFacetConfigTest
|
|||||||
config.onBootstrap(applicationEvent);
|
config.onBootstrap(applicationEvent);
|
||||||
|
|
||||||
creatorFP = config.getDefaultFacets().get("test_filter_creator");
|
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(5, creatorFP.getMaxFilters());
|
||||||
assertEquals(1, creatorFP.getHitThreshold());
|
assertEquals(1, creatorFP.getHitThreshold());
|
||||||
assertEquals(4, creatorFP.getMinFilterValueLength());
|
assertEquals(4, creatorFP.getMinFilterValueLength());
|
||||||
|
@@ -21,32 +21,36 @@ package org.alfresco.repo.search.impl.solr.facet;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
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.repo.security.authentication.AuthenticationUtil;
|
||||||
import org.alfresco.service.ServiceRegistry;
|
|
||||||
import org.alfresco.util.ApplicationContextHelper;
|
import org.alfresco.util.ApplicationContextHelper;
|
||||||
import org.joda.time.LocalDate;
|
|
||||||
import org.junit.*;
|
import org.junit.*;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
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
|
* @author Jamal Kaabi-Mofrad
|
||||||
|
* @since 5.0
|
||||||
*/
|
*/
|
||||||
public class SolrFacetHelperTest
|
public class SolrFacetQueriesDisplayHandlersTest
|
||||||
{
|
{
|
||||||
private static ApplicationContext context;
|
private static ApplicationContext context;
|
||||||
private static SolrFacetHelper helper;
|
private static SolrFacetHelper helper;
|
||||||
|
private static FacetLabelDisplayHandlerRegistry displayHandlerRegistry;
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void initStaticData() throws Exception
|
public static void initStaticData() throws Exception
|
||||||
{
|
{
|
||||||
context = ApplicationContextHelper.getApplicationContext();
|
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
|
* @throws Exception
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@Test
|
@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"
|
+ " 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"
|
+ " -TYPE:\"cm:failedThumbnail\" AND -TYPE:\"cm:rating\" AND -TYPE:\"st:site\" AND"
|
||||||
+ " -ASPECT:\"st:siteContainer\" AND -ASPECT:\"sys:hidden\" AND"
|
+ " -ASPECT:\"st:siteContainer\" AND -ASPECT:\"sys:hidden\" AND"
|
||||||
+ " -cm:creator:system, stores=[workspace://SpacesStore]";
|
+ " -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);
|
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 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\" ))"
|
||||||
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\" ))"
|
|
||||||
+ " AND (+TYPE:\"cm:content\" OR +TYPE:\"cm:folder\")) AND -TYPE:\"cm:thumbnail\" AND"
|
+ " 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"
|
+ " -TYPE:\"cm:failedThumbnail\" AND -TYPE:\"cm:rating\" AND -TYPE:\"st:site\" AND"
|
||||||
+ " -ASPECT:\"st:siteContainer\" AND -ASPECT:\"sys:hidden\" AND"
|
+ " -ASPECT:\"st:siteContainer\" AND -ASPECT:\"sys:hidden\" AND"
|
||||||
+ " -cm:creator:system, stores=[workspace://SpacesStore]";
|
+ " -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);
|
assertNotNull(result);
|
||||||
|
assertEquals("@{http://www.alfresco.org/model/content/1.0}created:[NOW/DAY-7DAYS TO NOW/DAY+1DAY]", result);
|
||||||
|
|
||||||
currentDate = LocalDate.now();
|
result = helper.createFacetQueriesFromSearchQuery(fields[1], searchQueryWithCreatedAndModifiedDate);
|
||||||
nowStr = " TO " + currentDate.toString();
|
assertNotNull(result);
|
||||||
yesterday = currentDate.minusDays(1).toString() + nowStr;
|
assertEquals("@{http://www.alfresco.org/model/content/1.0}modified:[NOW/DAY-1DAY TO NOW/DAY+1DAY]", result);
|
||||||
lastWeek = currentDate.minusWeeks(1).toString() + nowStr;
|
|
||||||
lastMonth = currentDate.minusMonths(1).toString() + nowStr;
|
|
||||||
last6Months = currentDate.minusMonths(6).toString() + nowStr;
|
|
||||||
lastYear = currentDate.minusYears(1).toString() + nowStr;
|
|
||||||
|
|
||||||
// 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
|
* @throws Exception
|
||||||
*
|
*
|
||||||
@@ -181,27 +144,19 @@ public class SolrFacetHelperTest
|
|||||||
{
|
{
|
||||||
List<String> result = helper.getDefaultFacetQueries();
|
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);
|
assertNotNull(result);
|
||||||
assertEquals(16, result.size());
|
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:[NOW/DAY-1DAY TO NOW/DAY+1DAY]"));
|
||||||
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:[NOW/DAY-7DAYS TO NOW/DAY+1DAY]"));
|
||||||
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:[NOW/DAY-1MONTH TO NOW/DAY+1DAY]"));
|
||||||
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:[NOW/DAY-6MONTHS TO NOW/DAY+1DAY]"));
|
||||||
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-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:[NOW/DAY-1DAY TO NOW/DAY+1DAY]"));
|
||||||
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:[NOW/DAY-7DAYS TO NOW/DAY+1DAY]"));
|
||||||
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:[NOW/DAY-1MONTH TO NOW/DAY+1DAY]"));
|
||||||
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:[NOW/DAY-6MONTHS TO NOW/DAY+1DAY]"));
|
||||||
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-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:[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:[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
|
* @throws Exception
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testGetUserNameDisplayHandler() throws Exception
|
public void testGetUserNameDisplayHandler() throws Exception
|
||||||
{
|
{
|
||||||
// Username handler
|
FacetLabelDisplayHandler userNameHandler = displayHandlerRegistry.getDisplayHandler("@{http://www.alfresco.org/model/content/1.0}creator");
|
||||||
SolrFacetHelper.FacetLabelDisplayHandler userNameHandler = helper.getDisplayHandler("@{http://www.alfresco.org/model/content/1.0}creator.__.u");
|
|
||||||
assertNotNull(userNameHandler);
|
assertNotNull(userNameHandler);
|
||||||
String randomUserName = "randomUserName" + System.currentTimeMillis();
|
String randomUserName = "randomUserName" + System.currentTimeMillis();
|
||||||
FacetLabel name = userNameHandler.getDisplayLabel(randomUserName);
|
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
|
* @throws Exception
|
||||||
*
|
*
|
||||||
@@ -242,7 +195,7 @@ public class SolrFacetHelperTest
|
|||||||
public void testGetMimetypeDisplayHandler() throws Exception
|
public void testGetMimetypeDisplayHandler() throws Exception
|
||||||
{
|
{
|
||||||
// Mimetype handler
|
// 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);
|
assertNotNull(mimeTypeHandler);
|
||||||
FacetLabel mimetype = mimeTypeHandler.getDisplayLabel("someMimetype123");
|
FacetLabel mimetype = mimeTypeHandler.getDisplayLabel("someMimetype123");
|
||||||
assertNotNull(mimetype);
|
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
|
* @throws Exception
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testGetDateBucketsDisplayHandler() throws Exception
|
public void testGetCreatedDateBucketsDisplayHandler() throws Exception
|
||||||
{
|
{
|
||||||
// Date buckets handler
|
final String createdDateField = "@{http://www.alfresco.org/model/content/1.0}created";
|
||||||
SolrFacetHelper.FacetLabelDisplayHandler dateBucketeHandler = helper.getDisplayHandler("@{http://www.alfresco.org/model/content/1.0}created");
|
FacetLabelDisplayHandler dateBucketeHandler = displayHandlerRegistry.getDisplayHandler(createdDateField);
|
||||||
assertNotNull(dateBucketeHandler);
|
assertNotNull(dateBucketeHandler);
|
||||||
|
|
||||||
LocalDate currentDate = LocalDate.now();
|
FacetLabel dateLabel = dateBucketeHandler.getDisplayLabel(createdDateField+":[NOW/DAY-1DAY TO NOW/DAY+1DAY]");
|
||||||
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);
|
|
||||||
assertNotNull(dateLabel);
|
assertNotNull(dateLabel);
|
||||||
assertEquals("faceted-search.date.one-day.label", dateLabel.getLabel());
|
assertEquals("faceted-search.date.one-day.label", dateLabel.getLabel());
|
||||||
assertEquals("Yesterday date bucket should have a sorting index of 0.", 0, dateLabel.getLabelIndex());
|
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);
|
assertNotNull(dateLabel);
|
||||||
assertEquals("faceted-search.date.one-week.label", dateLabel.getLabel());
|
assertEquals("faceted-search.date.one-week.label", dateLabel.getLabel());
|
||||||
assertEquals("Last week date bucket should have a sorting index of 1.", 1, dateLabel.getLabelIndex());
|
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);
|
assertNotNull(dateLabel);
|
||||||
assertEquals("faceted-search.date.one-month.label", dateLabel.getLabel());
|
assertEquals("faceted-search.date.one-month.label", dateLabel.getLabel());
|
||||||
assertEquals("Last month date bucket should have a sorting index of 2.", 2, dateLabel.getLabelIndex());
|
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);
|
assertNotNull(dateLabel);
|
||||||
assertEquals("faceted-search.date.six-months.label", dateLabel.getLabel());
|
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());
|
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);
|
assertNotNull(dateLabel);
|
||||||
assertEquals("faceted-search.date.one-year.label", dateLabel.getLabel());
|
assertEquals("faceted-search.date.one-year.label", dateLabel.getLabel());
|
||||||
assertEquals("Last year date bucket should have a sorting index of 4.", 4, dateLabel.getLabelIndex());
|
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
|
* @throws Exception
|
||||||
*
|
*
|
||||||
@@ -308,8 +253,8 @@ public class SolrFacetHelperTest
|
|||||||
@Test
|
@Test
|
||||||
public void testGetContentSizeBucketsDisplayHandler() throws Exception
|
public void testGetContentSizeBucketsDisplayHandler() throws Exception
|
||||||
{
|
{
|
||||||
// Date buckets handler
|
final String contentSizeField = "@{http://www.alfresco.org/model/content/1.0}content.size";
|
||||||
SolrFacetHelper.FacetLabelDisplayHandler contentSizeBucketeHandler = helper.getDisplayHandler("@{http://www.alfresco.org/model/content/1.0}content.size");
|
FacetLabelDisplayHandler contentSizeBucketeHandler = displayHandlerRegistry.getDisplayHandler(contentSizeField);
|
||||||
assertNotNull(contentSizeBucketeHandler);
|
assertNotNull(contentSizeBucketeHandler);
|
||||||
|
|
||||||
int KB = 1024;
|
int KB = 1024;
|
||||||
@@ -320,34 +265,56 @@ public class SolrFacetHelperTest
|
|||||||
int large = 16 * MB;
|
int large = 16 * MB;
|
||||||
int huge = 128 * MB;
|
int huge = 128 * MB;
|
||||||
|
|
||||||
FacetLabel sizeLabel = contentSizeBucketeHandler.getDisplayLabel("[0 TO " + tiny + "]");
|
|
||||||
|
FacetLabel sizeLabel = contentSizeBucketeHandler.getDisplayLabel(contentSizeField + ":[0 TO " + tiny + "]");
|
||||||
assertNotNull(sizeLabel);
|
assertNotNull(sizeLabel);
|
||||||
assertEquals("faceted-search.size.0-10KB.label", sizeLabel.getLabel());
|
assertEquals("faceted-search.size.0-10KB.label", sizeLabel.getLabel());
|
||||||
assertEquals("0-10KB size bucket should have a sorting index of 0.", 0, sizeLabel.getLabelIndex());
|
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);
|
assertNotNull(sizeLabel);
|
||||||
assertEquals("faceted-search.size.10-100KB.label", sizeLabel.getLabel());
|
assertEquals("faceted-search.size.10-100KB.label", sizeLabel.getLabel());
|
||||||
assertEquals("10-100KB size bucket should have a sorting index of 1.", 1, sizeLabel.getLabelIndex());
|
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);
|
assertNotNull(sizeLabel);
|
||||||
assertEquals("faceted-search.size.100KB-1MB.label", sizeLabel.getLabel());
|
assertEquals("faceted-search.size.100KB-1MB.label", sizeLabel.getLabel());
|
||||||
assertEquals("100KB-1MB size bucket should have a sorting index of 2.", 2, sizeLabel.getLabelIndex());
|
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);
|
assertNotNull(sizeLabel);
|
||||||
assertEquals("faceted-search.size.1-16MB.label", sizeLabel.getLabel());
|
assertEquals("faceted-search.size.1-16MB.label", sizeLabel.getLabel());
|
||||||
assertEquals("1-16MB size bucket should have a sorting index of 3.", 3, sizeLabel.getLabelIndex());
|
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);
|
assertNotNull(sizeLabel);
|
||||||
assertEquals("faceted-search.size.16-128MB.label", sizeLabel.getLabel());
|
assertEquals("faceted-search.size.16-128MB.label", sizeLabel.getLabel());
|
||||||
assertEquals("16-128MB size bucket should have a sorting index of 4.", 4, sizeLabel.getLabelIndex());
|
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);
|
assertNotNull(sizeLabel);
|
||||||
assertEquals("faceted-search.size.over128.label", sizeLabel.getLabel());
|
assertEquals("faceted-search.size.over128.label", sizeLabel.getLabel());
|
||||||
assertEquals("over128MB size bucket should have a sorting index of 5.", 5, sizeLabel.getLabelIndex());
|
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()
|
public static Test suite()
|
||||||
{
|
{
|
||||||
TestSuite suite = new TestSuite();
|
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(SolrFacetServiceImplTest.class));
|
||||||
suite.addTest(new JUnit4TestAdapter(SolrFacetConfigTest.class));
|
suite.addTest(new JUnit4TestAdapter(SolrFacetConfigTest.class));
|
||||||
|
|
||||||
|
@@ -1,15 +1,15 @@
|
|||||||
# Overrides test_filter_creator in the /facets/facets-config-sample.properties
|
# Overrides test_filter_creator in the /facets/facets-config-sample.properties
|
||||||
custom.cm\:creator.__.u.filterID=test_filter_creator
|
custom.cm\:creator.filterID=test_filter_creator
|
||||||
custom.cm\:creator.__.u.displayName=faceted-search.facet-menu.facet.creator
|
custom.cm\:creator.displayName=faceted-search.facet-menu.facet.creator
|
||||||
custom.cm\:creator.__.u.displayControl=alfresco/search/FacetFilters
|
custom.cm\:creator.displayControl=alfresco/search/FacetFilters
|
||||||
custom.cm\:creator.__.u.maxFilters=10
|
custom.cm\:creator.maxFilters=10
|
||||||
custom.cm\:creator.__.u.hitThreshold=5
|
custom.cm\:creator.hitThreshold=5
|
||||||
custom.cm\:creator.__.u.minFilterValueLength=14
|
custom.cm\:creator.minFilterValueLength=14
|
||||||
custom.cm\:creator.__.u.sortBy=ALPHABETICALLY
|
custom.cm\:creator.sortBy=ALPHABETICALLY
|
||||||
custom.cm\:creator.__.u.scope=ALL
|
custom.cm\:creator.scope=ALL
|
||||||
custom.cm\:creator.__.u.scopedSites=site1
|
custom.cm\:creator.scopedSites=site1
|
||||||
custom.cm\:creator.__.u.index=0
|
custom.cm\:creator.index=0
|
||||||
custom.cm\:creator.__.u.isEnabled=true
|
custom.cm\:creator.isEnabled=true
|
||||||
|
|
||||||
# Add a new Filter
|
# Add a new Filter
|
||||||
# Field-Facet-Qname => cm:description.__
|
# Field-Facet-Qname => cm:description.__
|
||||||
|
@@ -1,26 +1,26 @@
|
|||||||
# Field-Facet-Qname => cm:creator.__.u
|
# Field-Facet-Qname => cm:creator
|
||||||
default.cm\:creator.__.u.filterID=test_filter_creator
|
default.cm\:creator.filterID=test_filter_creator
|
||||||
default.cm\:creator.__.u.displayName=faceted-search.facet-menu.facet.creator
|
default.cm\:creator.displayName=faceted-search.facet-menu.facet.creator
|
||||||
default.cm\:creator.__.u.displayControl=alfresco/search/FacetFilters
|
default.cm\:creator.displayControl=alfresco/search/FacetFilters
|
||||||
default.cm\:creator.__.u.maxFilters=5
|
default.cm\:creator.maxFilters=5
|
||||||
default.cm\:creator.__.u.hitThreshold=1
|
default.cm\:creator.hitThreshold=1
|
||||||
default.cm\:creator.__.u.minFilterValueLength=4
|
default.cm\:creator.minFilterValueLength=4
|
||||||
default.cm\:creator.__.u.sortBy=ALPHABETICALLY
|
default.cm\:creator.sortBy=ALPHABETICALLY
|
||||||
default.cm\:creator.__.u.scope=ALL
|
default.cm\:creator.scope=ALL
|
||||||
default.cm\:creator.__.u.scopedSites=
|
default.cm\:creator.scopedSites=
|
||||||
default.cm\:creator.__.u.isEnabled=true
|
default.cm\:creator.isEnabled=true
|
||||||
|
|
||||||
# Field-Facet-Qname => cm:modifier.__.u
|
# Field-Facet-Qname => cm:modifier
|
||||||
default.cm\:modifier.__.u.filterID=test_filter_modifier
|
default.cm\:modifier.filterID=test_filter_modifier
|
||||||
default.cm\:modifier.__.u.displayName=faceted-search.facet-menu.facet.modifier
|
default.cm\:modifier.displayName=faceted-search.facet-menu.facet.modifier
|
||||||
default.cm\:modifier.__.u.displayControl=alfresco/search/FacetFilters
|
default.cm\:modifier.displayControl=alfresco/search/FacetFilters
|
||||||
default.cm\:modifier.__.u.maxFilters=5
|
default.cm\:modifier.maxFilters=5
|
||||||
default.cm\:modifier.__.u.hitThreshold=1
|
default.cm\:modifier.hitThreshold=1
|
||||||
default.cm\:modifier.__.u.minFilterValueLength=4
|
default.cm\:modifier.minFilterValueLength=4
|
||||||
default.cm\:modifier.__.u.sortBy=ALPHABETICALLY
|
default.cm\:modifier.sortBy=ALPHABETICALLY
|
||||||
default.cm\:modifier.__.u.scope=SCOPED_SITES
|
default.cm\:modifier.scope=SCOPED_SITES
|
||||||
default.cm\:modifier.__.u.scopedSites=
|
default.cm\:modifier.scopedSites=
|
||||||
default.cm\:modifier.__.u.isEnabled=true
|
default.cm\:modifier.isEnabled=true
|
||||||
|
|
||||||
# Field-Facet-Qname => cm:content.size
|
# Field-Facet-Qname => cm:content.size
|
||||||
default.cm\:content.size.filterID=test_filter_content_size
|
default.cm\:content.size.filterID=test_filter_content_size
|
||||||
|
Reference in New Issue
Block a user