Sorting collapsed results

Background

This article shows how to sort the collapsed results that are returned as a child of the main result for display in the search results template.

Funnelback doesn’t have any built in support for sorting of collapsed results returned as a child to a result and there are some limitations relating to the result sub-set.

Process

If you choose to display the collapsed results within the initial result set (e.g. as a list of sub-results) then you need to be aware of the following.

There currently is no way to get Funnelback to return the set of results in a defined sort order. However you can sort the results using a Groovy hook script.

The collapsed results returned with the result packet are limited to the first N results as defined by collapsed_num_ranks. You’ll only have access to the first N items (for sorting purposes) so ensure this value is set to an appropriate value.

The collapsed results will only include items that match the query term (so if you’re using it to display child pages, then all the children need to match the query).

The following code can be used in a hook_post_process.groovy script to sort the items that are returned as part of the result packet.

if ( transaction.response != null && transaction.response.resultPacket.results != null
        && transaction.response.resultPacket.results.size() > 0 ) {
                  transaction.response.resultPacket.results.each() {
                        if (it.collapsed != null && it.collapsed.results != null && it.collapsed.results.size() > 0) {
                                        Collections.sort(it.collapsed.results, {a, b -> sortCompare(a, b)} as Comparator);
                        }
        }
}

def sortCompare(a, b) {
//Define sort overrides - this sets a sort key to use when doing the alphabetic search.  in the example below an item with 'Custom title - show me first' as the field value will be treated as AAAAA000000 for the purposes of sorting.
    def labelOrderMap = [
                         "Custom title - show me first":"AAAAA000000",
                         "Custom title - show me last":"ZZZZZ00000",
                         ];
    def labela = a.title;
    def labelb = b.title;
    if (labelOrderMap.containsKey(labela)) {
        labela = labelOrderMap[labela];
    }
    if (labelOrderMap.containsKey(labelb)) {
        labelb = labelOrderMap[labelb];
    }
    labela.compareTo(labelb);
}

The following code block can be used in a hook_post_process.groovy script to sort collapsed results based on two metadata values.

if ( transaction.response != null && transaction.response.resultPacket.results != null
        && transaction.response.resultPacket.results.size() > 0 ) {
                  transaction.response.resultPacket.results.each() {
                        //Code block that sorts (in ascending order) collapsed results based on 2 numeric metadata values
                        if (it.collapsed != null && it.collapsed.results != null && it.collapsed.results.size() > 0) {
                                it.collapsed.results.sort{[it.metaData["MinorVersion"], it.metaData["MajorVersion"]]}
                        }
        }
}

When you click on the sorted link it’s possible to apply a sort to the resultant query. Note: to do this you’ll need to use a modified collapsed macro e.g.

<#---

    Generates a link to show the results that were collapsed with this specific result.

    @param defaultLabel Label to use when there's no label for the current collapsing column
    @param labels Text to use for the link. <code>{0}</code> will be replaced by the number of collapsed results. This is a hash where the key is the collapsing column, as a String.

-->
<#macro Collapsed sort defaultLabel="{0} very similar results" labels={}>
    <#if s.result.collapsed??>

        <#assign text = defaultLabel />
        <#if labels[s.result.collapsed.column]??>

            <#assign text = labels[s.result.collapsed.column] />
        </#if>
        <a class="search-collapsed" href="?${QueryString}&amp;s=%3F:${s.result.collapsed.signature}&amp;fmo=on&amp;collapsing=off<#if sort?exists>&amp;sort=${sort?html}</#if>">${text?replace("{0}", s.result.collapsed.count)}</a>
    </#if>
</#macro>