Search refinement allows users to search within an existing result set. ATG Search can return refinement results based on settings in a
refineConfig.xml
file.
This file defines which properties of the indexed products to return as possible refinement data. Before returning results, ATG Search generates the possible values for the properties configured in refineConfig.xml
. Thus, the existing query can be then re-submitted with an additional constraint that limits the results to one of the enumerated property values.
See the ATG Search documentation for more information on refinement configuration.
The following is an example of a refineConfig.xml
file that specifies refinement of product searches by manufacturer and category.
<?xml version="1.0" encoding="UTF-8"?> <!-- refineConfig lists out the priority of refinements to attempt --> <!-- if a refinement is unusable (all results have the same property value) --> <!-- then either its children are used or it is ignored if it has no children --> <!-- refineElement represents how to use 1 property for refinement --> <!-- refineElement children are more granular properties to use once the parent is unusable --> <!-- Attributes are: --> <!-- id: unique id --> <!-- label: displayable name of property --> <!-- property: name of property in documents --> <!-- type: type of property --> <!-- range: whether the property values should be aggregated into range values, rather than absolute values --> <!-- desired: for ranges, desired number of property value "buckets" to return --> <!-- min: for ranges, minimum size of a property value "bucket" to return --> <!-- inc: for ranges, minimum size of a property value range --> <refineConfig name="sample-refine-config"> <refineElement id="0" label="Category" property="ancestorCategories.displayName" type="string" range="false" > </refineElement> <refineElement id="1" label="Manufacturer" property="manufacturer.displayName" type="string" range="false" > </refineElement> </refineConfig>
This file defines the results that ATG Search should return as all of the current result values for the ancestorCategories
within the result set and all of the current result values for manufacturer
within the result set.
For example, a search for “brakes” could return the following refinement results.
![](media/image3.png)
When a user clicks on one of the results to narrow the search, the search form can then generate a constraint with the values of the given properties.
The following JSP example demonstrates how to create search refinement options.
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %> <%@ taglib prefix="dspel" uri="http://www.atg.com/taglibs/daf/dspjspELTaglib1_0" %> <dspel:page> <script language="javascript"> /** * Sets the refinement text value and submits the form **/ function refine(type, metaPropertyName, value) { setFormElement('searchForm','newRefinementType',type); setFormElement('searchForm','newRefinementName',metaPropertyName); setFormElement('searchForm','newRefinementValue',value); changePage(0); submitForm('searchForm'); return true; } /** * Updates a named input in the form with the given name in the current * document to the new value specified. **/ function setFormElement(formName,inputName,value) { var form = document.forms[formName]; if(form == null) return false; var input = form.elements[inputName]; if(input == null) return false; input.value=value; return true; } /** * Changes the page number. **/ function changePage(page) { setFormElement('searchForm', 'pageNum', page); return true; } </script> <c:set var="formHandlerPath" value="/atg/commerce/search/ProductCatalogQueryFormHandler"/> <dspel:getvalueof var="thisPage" bean="/OriginatingRequest.requestURI"/> <dspel:form formid="searchForm" name="searchForm" method="POST" action="${thisPage}"> <!-- The page number --> <dspel:getvalueof var="pageNum" bean="${formHandlerPath}.requestAttributes.pageNum"/> <c:if test="${empty pageNum}"><c:set var="pageNum" value="0" scope="request"/></c:if> <dspel:input type="hidden" name="pageNum" bean="${formHandlerPath}.requestAttributes.pageNum" value="${pageNum}"/> <!-- The text input --> Search Text: <dspel:input type="text" name="question" bean="${formHandlerPath}.question" beanvalue="${formHandlerPath}.question" onchange="changePage(0);"/> <!-- The hidden query refinement control --> <dspel:input type="hidden" bean="${formHandlerPath}.documentSetsBuilder.tags.refineAnd.tagname" value="and" /> <dspel:input type="hidden" bean="${formHandlerPath}.documentSetsBuilder.tags.refineAnd.opts.generate" value="ifchild" /> <dspel:getvalueof var="tags" bean="${formHandlerPath}.documentSetsBuilder.tags.refineAnd"/> <c:set var="refineCount" value="0"/> <c:forEach var="tag" items="${tags}" varStatus="varStatus"> <c:choose> <c:when test="${tag.key == 'tagname' || tag.key == 'opts' || tag.key == 'attr' || tag.key == 'nested'}"> </c:when> <c:otherwise> <c:if test="${!empty tag.value.body}"> <!-- This submits previous refinement selections --> <c:set var="refineCount" value="${refineCount + 1}"/> <c:set var="prop" value="${formHandlerPath}.documentSetsBuilder.tags.\ refineAnd.refineElement${refineCount}"/> <dspel:input type="hidden" bean="${prop}.tagname" value="prop" /> <dspel:input type="hidden" bean="${prop}.opts.generate" value="ifvalue:body" /> <dspel:input type="hidden" bean="${prop}.attr.type" value="${tag.value.attr.type}" priority="10" /> <dspel:input type="hidden" bean="${prop}.attr.name" value="${tag.value.attr.name}" priority="10" /> <dspel:input type="hidden" bean="${prop}.attr.op" value="equal" /> <dspel:input type="hidden" bean="${prop}.attr.case" value="true" /> <dspel:input type="hidden" bean="${prop}.body" value="${tag.value.body}" priority="10" /> </c:if> </c:otherwise> </c:choose> </c:forEach> <!-- This submits new refinement selections if made --> <c:set var="refineCount" value="${refineCount + 1}"/> <c:set var="prop" value="${formHandlerPath}.documentSetsBuilder.tags.refineAnd.\ newRefineElement"/> <dspel:input type="hidden" bean="${prop}.tagname" value="prop" /> <dspel:input type="hidden" bean="${prop}.opts.generate" value="ifvalue:body" /> <dspel:input type="hidden" bean="${prop}.attr.type" value="" name="newRefinementType" priority="10"/> <dspel:input type="hidden" bean="${prop}.attr.name" value="" name="newRefinementName" priority="10"/> <dspel:input type="hidden" bean="${prop}.attr.op" value="equal" /> <dspel:input type="hidden" bean="${prop}.attr.case" value="true" /> <dspel:input type="hidden" bean="${prop}.body" value="" name="newRefinementValue" priority="10"/> <!-- end hidden query refinement controls --> <!-- submit button --> <dspel:input type="submit" bean="${formHandlerPath}.search" name="submit" value="Search" priority="-20"/> </dspel:form> <!-- refinement input controls --> <dspel:getvalueof var="results" bean="${formHandlerPath}.results"/> <c:if test="${results.refinements.size > 0}"> Refine Results By: <c:forEach var="refinement" items="${results.refinements.refinementsList}"> <div> <c:out value="${refinement.name}"> <div> <c:forEach var="refinementValue" items="${refinement.refinementValues}"> <% com.primus.searchstudio.RefinementValue value = (com.primus.searchstudio.RefinementValue)pageContext.\ findAttribute("refinementValue"); pageContext.setAttribute("count", "" + value.count); pageContext.setAttribute("value", value.value); %> <a href="#" onclick="refine('<c:out value="${refinement.type}"/>', '<c:out value="${refinement.name}"/>', '<c:out value="${value}"/>');"><c:out value= "${value}"/></a> (<c:out value="${count}"/>) </c:forEach> </div> </div> </c:forEach> </c:if> </dspel:page>