restalfrescosolr4faceted-search

Alfresco API to run faceted search


I'm using Alfresco community 5.x version and I'm wondering if There are REST or any other remote alfresco apis to be able to run Faceted search.
I've seen some Restful apis to administer/manage some aspects of Faceted search viz : http://docs.alfresco.com/community5.0/references/RESTful-Facet.html
However no public APIs to run a faceted search.

I did notice that alfresco share fires the following against the core alfresco service to run its faceted search; but could not find any notes/docs related to that -

http://alfresco.mycompany.com/alfresco/s/slingshot/search
?facetFields={http://www.alfresco.org/model/content/1.0}creator,
{http://www.alfresco.org/model/content/1.0}content.mimetype,
{http://www.alfresco.org/model/content/1.0}created,
{http://www.alfresco.org/model/content/1.0}content.size,
{http://www.alfresco.org/model/content/1.0}modifier,
{http://www.alfresco.org/model/content/1.0}modified
&filters=
&term=wal
&tag=
&startIndex=0
&sort=
&site=
&rootNode=alfresco://company/home
&repo=false
&query=
&pageSize=25
&maxResults=0
&noCache=1455504682131
&spellcheck=true&

We have API based integration with Alfresco in our custom internal applications and don't use Alfresco Share. I'm not sure if I should be using the above url or not. Any suggestions on this?

Thanks!

Alfresco Version: 5.0.d


Solution

  • I finally figured out how to implement and integrate the faceted search into a custom UI. the same also works with share.

    1. create model in model manager (no hyphens)
      • Indexing attribute:
        • String: list of values whole match
        • Date, Number: enhanced search
    2. For each type define the layout design - w/o this you wont be able to change type in share at least.
    3. In share/search manager create filters/facets for fields you're interested in
    4. Add a custom *context.xml to define a bean with your custom FacetQueryProvider implementation. inject that into the facet.solrFacetHelper bean
    5. The custom FacetQueryProvider e.g. DollarAmountDisplayHandler basically provides facet queries based on the dollar amount buckets bean in the *context.xml, those will then be passed to solr.
    6. Jar up the FacetQueryProvider implementation and copy to tomcat/lib directory.

    Custom-solr-facets-context.xml

    <?xml version='1.0' encoding='UTF-8'?>
    <!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
    
    <beans>
    <bean id="facet.dateFacetFields" class="org.springframework.beans.factory.config.SetFactoryBean">
        <property name="sourceSet">
            <set>
                <value>@{http://www.alfresco.org/model/content/1.0}created</value>
                <value>@{http://www.alfresco.org/model/content/1.0}modified</value>
                <value>@{http://www.mycomp.com/model/hono/1.0}invoiceDate</value>
            </set>
        </property>
    </bean>
    
    
    <bean id="facet.dollarAmountBuckets" class="org.springframework.beans.factory.config.MapFactoryBean">
        <property name="sourceMap">
            <map>
                <entry key="[0 TO 1000]" value="$0-$1K" />
                <entry key="[1000 TO 10000]" value="$1K-$10K" />
                <entry key="[10000 TO 100000]" value="$10K-$100K" />
                <entry key="[100000 TO MAX]" value="Above.$100K" />
            </map>
        </property>
    </bean>
    
    <bean id="facet.dollarAmountDisplayHandler" class="com.mycomp.edm.alfresco.extensions.search.solr.facets.handlers.DollarAmountDisplayHandler" parent="baseFacetLabelDisplayHandler" >
        <constructor-arg index="0">
            <set>
                <value>@{http://www.mycomp.com/model/hono/1.0}invoiceAmount</value>
            </set>
        </constructor-arg>
        <constructor-arg index="1">
            <ref bean="facet.dollarAmountBuckets" />
        </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" />
                <ref bean="facet.dollarAmountDisplayHandler" />
            </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>
    

    The model:

    <?xml version="1.0" encoding="UTF-8"?>
    <model xmlns="http://www.alfresco.org/model/dictionary/1.0" name="hon:hono">
    <description>hono model</description>
    <author>amit</author>
    <imports>
        <import uri="http://www.alfresco.org/model/content/1.0" prefix="cm"/>
        <import uri="http://www.alfresco.org/model/dictionary/1.0" prefix="d"/>
    </imports>
    <namespaces>
        <namespace uri="http://www.mycomp.com/model/hono/1.0" prefix="hon"/>
    </namespaces>
    <data-types/>
    <constraints/>
    <types>
        <type name="hon:invoice">
            <title>Invoice</title>
            <description>invoice model</description>
            <parent>cm:content</parent>
            <properties>
                <property name="hon:invoiceNumber">
                    <title>Invoice Number</title>
                    <type>d:int</type>
                    <mandatory>false</mandatory>
                    <index enabled="true">
                        <tokenised>TRUE</tokenised>
                        <facetable>true</facetable>
                    </index>
                </property>
                <property name="hon:invoiceAmount">
                    <title>Invoice Amount</title>
                    <type>d:int</type>
                    <mandatory>false</mandatory>
                    <index enabled="true">
                        <tokenised>TRUE</tokenised>
                        <facetable>true</facetable>
                    </index>
                </property>
                <property name="hon:invoiceDate">
                    <title>Invoice Date</title>
                    <type>d:date</type>
                    <mandatory>false</mandatory>
                    <index enabled="true">
                        <tokenised>TRUE</tokenised>
                        <facetable>true</facetable>
                    </index>
                </property>
                <property name="hon:organizationName">
                    <title>Organization Name</title>
                    <type>d:text</type>
                    <mandatory>false</mandatory>
                    <index enabled="true">
                        <tokenised>FALSE</tokenised>
                        <facetable>true</facetable>
                    </index>
                </property>
                <property name="hon:customerName">
                    <title>Customer Name</title>
                    <type>d:text</type>
                    <mandatory>false</mandatory>
                    <index enabled="true">
                        <tokenised>FALSE</tokenised>
                        <facetable>true</facetable>
                    </index>
                </property>
            </properties>
            <associations/>
            <overrides/>
            <mandatory-aspects/>
        </type>
    </types>
    <aspects/>
    </model>
    

    Facet Query Provider

    package com.mycomp.edm.alfresco.extensions.search.solr.facets.handlers;
    
    import org.alfresco.repo.search.impl.solr.facet.FacetQueryProvider;
    import org.alfresco.repo.search.impl.solr.facet.SolrFacetConfigException;
    import org.alfresco.repo.search.impl.solr.facet.handler.AbstractFacetLabelDisplayHandler;
    import org.alfresco.repo.search.impl.solr.facet.handler.FacetLabel;
    import org.springframework.extensions.surf.util.ParameterCheck;
    
    import java.util.*;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    /**
     * Created by Amit on 2/24/16.
     */
    public class DollarAmountDisplayHandler 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 DollarAmountDisplayHandler(Set<String> facetQueryFields, LinkedHashMap<String, String> dollarValueBucketMap)
        {
            System.out.println("instantiating bean DollarAmountDisplayHandler");
            ParameterCheck.mandatory("facetQueryFields", facetQueryFields);
            ParameterCheck.mandatory("dollarValueBucketMap", dollarValueBucketMap);
    
            this.supportedFieldFacets = Collections.unmodifiableSet(facetQueryFields);
    
            facetLabelMap = new HashMap<>(dollarValueBucketMap.size());
            Map<String, List<String>> facetQueries = new LinkedHashMap<>(facetQueryFields.size());
    
            for (String facetQueryField : facetQueryFields)
            {
                List<String> queries = new ArrayList<>();
                int index = 0;
                for (Map.Entry<String, String> bucket : dollarValueBucketMap.entrySet())
                {
                    String sizeRange = bucket.getKey().trim();
                    Matcher matcher = SIZE_RANGE_PATTERN.matcher(sizeRange);
                    if (!matcher.find())
                    {
                        throw new SolrFacetConfigException(
                                "Invalid dollar value range. Example of a valid size range is: [0 TO 1000]");
                    }
                    // build the facet query. e.g. {http://www.mycomp.com/model/hono/1.0}invoiceAmount:[0 TO 1000]
                    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);
            System.out.println("Bean DollarAmountDisplayHandler instantiated");
    
        }
    
        @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;
        }
    }