Sie sind auf Seite 1von 91

atg

Version 2007.1
Commerce Search Guide

ATG
One Main Street
Cambridge, MA 02142
www.atg.com

ATG Commerce Search Guide


Document Version
Doc2007.1 REPOSEARCHv2 8/16/07

Copyright
Copyright 1998-2007 Art Technology Group, Inc. All rights reserved.
This publication may not, in whole or in part, be copied, photocopied, translated, or reduced to any electronic medium or machine-readable
form for commercial use without prior consent, in writing, from Art Technology Group, Inc. (ATG) ATG does authorize you to copy
documents published by ATG on the World Wide Web for non-commercial uses within your organization only. In consideration of this
authorization, you agree that any copy of these documents which you make shall retain all copyright and other proprietary notices
contained herein.

Trademarks
ATG, Art Technology Group, and DYNAMO are registered trademarks of Art Technology Group, Inc.
ATG Wisdom, ATG Dynamo Application Server, ATG Adaptive Scenario Engine, ATG Scenario Personalization, ATG Portal, ATG Commerce,
ATG Content Administration, ATG Data Anywhere Architecture, ATG Search, ATG Response Management, ATG Merchandising, ATG
Knowledge, ATG Self Service, ATG Commerce Assist, ATG Advisor, ATG Forum and ATG Business Control Center are trademarks of Art
Technology Group, Inc.
Microsoft, Windows and Word are the trademarks or registered trademarks of Microsoft Corporation in the United States and other countries.
IBM, AIX, and MQ-Series are the trademarks or registered trademarks of IBM Corporation in the United States and other countries. Oracle is a
registered trademark, and other Oracle product names, service names; slogans or logos referenced in this document are trademarks or
registered trademarks of Oracle Corporation. Adobe Acrobat Reader is a registered trademark of Adobe. CORBA is a trademark of the OMG
(Object Management Group). Java and all Java-based trademarks and logos are trademarks or registered trademarks of Sun Microsystems,
Inc. in the United States and other countries. Primus, and its respective logo, and Primus Knowledge Solutions, are trademarks, registered
trademarks, or service marks of Primus.
This product includes software developed by the Apache Software Foundation (http://www.apache.org/).
EditLive Authoring Software Copyright 2004 Ephox Corporation. All rights reserved. Includes code licensed from RSA Security, Inc.. Some
portions licensed from IBM are available at http://oss.software.ibm.com/icu4j/. Includes software developed by the Apache Software
Foundation (http://www.apache.org/). Contains spell checking software from Wintertree Software Inc.. The Sentry Spell Checker Engine
2000 Wintertree Software Inc..
All other product names, service marks, and trademarks mentioned herein are trademarks of their respective owners. This publication may
not, in whole or in part, be copied, photocopied, translated, or reduced to any electronic medium or machine-readable form for commercial
use without prior consent, in writing, from Art Technology Group (ATG), Inc. ATG does authorize you to copy documents published by ATG
on the World Wide Web for non-commercial uses within your organization only. In consideration of this authorization, you agree that any
copy of these documents which you make shall retain all copyright and other proprietary notices contained herein.

No Warranty
This documentation is provided as is without warranty of any kind, either expressed or implied, including, but not limited to, the implied
warranties of merchantability, fitness for a particular purpose, or non-infringement.
The contents of this publication could include technical inaccuracies or typographical errors. Changes are periodically added to the
information herein; these changes will be incorporated in the new editions of the publication. ATG may make improvements and/or changes
in the publication and/or product(s) described in the publication at any time without notice.

Limitation of Liability
In no event will ATG be liable for direct, indirect, special, incidental, economic, cover, or consequential damages arising out of the use of or
inability to use this documentation even if advised of the possibility of such damages. Some states do not allow the exclusion or limitation of
implied warranties or limitation of liability for incidental or consequential damages, so the above limitation or exclusion may not apply to
you.
ATG One Main Street Cambridge MA 02142
617.386.1000 phone 617.386.1111 fax www.atg.com

ATG Commerce Search Guide

Contents

Getting Started

Running the Commerce Search Modules


Assembling an EAR File
Creating the Database Tables
Configuring the ATG Platform to Issue Queries
SearchServer Component
ESSearchService Component

5
6
6
6
7
7

Repository Indexing

Transforming the Repository Data


Definition File Format
XHTML Output Documents
Loading the Repository Data into ATG Search
Configuring Bulk Loading
Configuring Incremental Loading
Using Incremental Indexing in an ATG Content Administration Environment
Configuring a Document Submitter for Debugging
Customizing the Output
Using Custom Property Accessors
Using Variant Producers
Accessing the Context Object
Using Other Customization Classes
Transforming and Loading Catalog Data
Transforming Catalog Data
Transforming Custom Catalog Data
Excluding Uncategorized Products from Indexing
Using SKU-Based Indexing
Loading Catalog Data

Search Form Handlers


Form Handler Classes and Architecture
Configuring the Form Handlers
Sample Application
Constructing Queries
Setting the Request Attributes
Using the XML Builder
Specifying Structured Statements

9
9
12
14
14
15
16
16
17
18
19
19
20
21
21
24
25
26
27

29
29
30
31
31
33
35
36

iii
Contents

ATG Commerce Search Guide

Creating Parametric Search Queries


Handling Results
Controlling Paging
Handling Repository Items
Using Collection Filters
Refining Search Results
JMS Event Handling
Patch Bay Configuration

Dynamic Search and Navigation


Overview of Facets
Indexing the Catalog Repository
Generating the Refinement Configuration Files
Building Pages that Include Facets
Using the CommerceFacetTrailDroplet
Using the FacetSearchDroplet
Incorporating Search Results
Configuring the Dynamic Navigation Servlet Beans
CommerceFacetTrailDroplet Configuration
CommerceFacetSearchDroplet Configuration
CommerceFacetTrailDroplet
FacetSearchDroplet

Search Merchandising
Configuring the Customization Adapters
Configuring the Adapter Components
Invoking the Adapters
Generating the Search Configuration Files
Determining the Search Configuration to Use
Determining the Language
Configuring the Dimension Services
Handling Redirects
Collecting Updated Inventory Data

37
40
42
43
43
45
49
52

53
53
54
54
55
55
57
57
59
59
60
62
66

73
73
74
75
75
76
77
78
78
78

Appendix A: Configuring ATG Search

81

Appendix B: Using the MapXMLBuilder Class

83

Examples

Index

83

89

iv
Contents

ATG Commerce Search Guide

1 Getting Started

This guide provides information about using ATG Search to index and search content in ATG repositories,
including ATG Commerce catalogs. Implementing Commerce Search on your site involves the following
steps:
1.

You specify repository items and attributes to index through an XML definition file.

2.

Based on the information in the XML definition file, the repository items are
transformed into XHTML documents.

3.

These XHTML documents are indexed by ATG Search.

4.

Using search forms in your site pages (created with form handlers that communicate
with ATG Search), site visitors search these indexed documents.

For example, if you index your ATG Commerce catalog, a site visitor can use ATG Search to search your
Commerce site for specific products.
This chapter describes how to set up Commerce Search in a production environment. It includes the
following sections:
Running the Commerce Search Modules
Creating the Database Tables
Configuring the ATG Platform to Issue Queries
For information about setting up ATG Merchandising to work with Commerce Search in an ATG Content
Administration environment, see the ATG Merchandising User Guide. For information about setting up ATG
Search, see the ATG Search Installation and Configuration Guide.

Running the Commerce Search Modules


The core functionality for Commerce Search is included in the DAF.Search module and its Index and
Query submodules. These modules provide the tools for indexing data in ATG repositories, submitting
the data to ATG Search, issuing queries, and handling the results.
The catalog search modules provide commerce-specific functionality for using ATG Search to index and
return results from standard and custom catalogs. The following modules, each of which contain Index
and Query submodules, are provided:

DCS.Search includes standard catalog indexing and query configuration

5
1 - Getting Started

ATG Commerce Search Guide

DCS.Search.CustomCatalogs adds support for custom catalogs

B2BCommerce.Search adds support for ATG Business Commerce properties

Assembling an EAR File


To run Commerce Search, you need to build an J2EE Enterprise Archive (EAR) file that contains an instance
of your ATG product modules. ATG provides an assembly tool that you can use to create your EAR file. You
can find detailed information about the application assembly tool in the ATG Programming Guide.
To assemble an EAR file that includes the search modules, you execute a command in this format:
<ATG2007.1dir>/home/bin/runAssembler [options] output-file-name
m module-list

For example, to assemble an application in development mode that includes the DCS.Search module,
use this command:
<ATG2007.1dir>/home/bin/runAssembler output-file-name m DCS.Search

Creating the Database Tables


The ATG platform includes scripts for creating the database tables for Commerce Search. This section
contains information about creating these database tables. For information about creating database
tables for the rest of the ATG platform, see the ATG Installation and Configuration Guide. For information
about creating database tables for ATG Search, see ATG Search Installation and Configuration Guide.
To create the tables, run the following scripts:
<ATG2007.1dir>/DAF/Search/Index/sql/db_components/db-vendor/search_ddl.sql
<ATG2007.1dir>/DAF/Search/common/sql/db_components/db-vendor/
refinement_ddl.sql

The search_ddl.sql script creates the tables used by the IncrementalLoader to changes to the
indexed repository. The refinement_ddl.sql script creates the tables used by the
RefinementRepository.

Configuring the ATG Platform to Issue Queries


To enable the ATG platform to communicate with ATG Search, two Nucleus services are preconfigured:

/atg/search/es/ESSearchService This component, which is of class


atg.search.es.ESSearchServiceImpl, submits requests to the ATG Search server

and receives results.

6
1 - Getting Started

ATG Commerce Search Guide

/atg/search/es/SearchServer This component, which is of class


atg.search.es.SearchServer, is configured with the ATG Search host name, port

number, and application server platform.


These services are accessed by the search form handlers and the dynamic navigation servlet beans when
they issue queries to ATG Search and receive results.

SearchServer Component
Configure the SearchServer component by giving it global scope and setting the following properties:
appServerType
If ATG Search Routing is running on the same ATG instance as the application issuing
queries, set this property to local. Otherwise set the value of this property to rmi,
and set the host and port properties.
host
The IP address or symbolic name of the machine that Routing is running on. Set only if
appServerType is set to rmi.
port
The RMI port of the machine that Routing is running on. Set only if appServerType is
set to rmi.

ESSearchService Component
Configure the ESSearchService component by giving it global scope and setting the following
property:
searchServer
The SearchServer component to use.

7
1 - Getting Started

ATG Commerce Search Guide

8
1 - Getting Started

ATG Commerce Search Guide

2 Repository Indexing

To make repository data available for searching, the ATG platform must transform the data into a format
that ATG Search can work with, and then load this data into the ATG Search system for indexing. This
chapter describes the ATG classes and components that perform these functions, and explains how to
configure or override these classes and components to work with the repositories on your site.
This chapter contains the following sections:
Transforming the Repository Data
Loading the Repository Data into ATG Search
Customizing the Output
Transforming and Loading Catalog Data

Transforming the Repository Data


To make repository items searchable, the ATG platform creates textual representations of these items.
These textual representations are XHTML documents whose tags encode the parent and child
relationships of the items, as well as information about their properties.
For example, an XHTML document that represents a Commerce product can include information about its
parent categorys properties, as well as information about the properties of the child SKUs. This means
that property values from this category (such as the name of the category) are included in each XHTML
document representing an individual product, thus making it possible to search category and SKU
properties as well as product properties.
To specify how to transform repository items to their XHTML representations, you create a definition file.
This is an XML file that contains information such as the repositorys Nucleus location, and the repository
item types and properties to include in the resulting XHTML documents.

Definition File Format


The definition file format begins with a top-level item element that specifies the repository and item
descriptor to use, and then lists the properties of that item type to include. The properties appear as
property elements within text-properties (used for full-text indexing) or meta-properties (used
for constraints) elements. The top-level item element can contain child item elements for properties that
refer to other repository items (or arrays, Collections, or Maps of repository items). Those child item
elements in turn can contain property and item elements themselves.

9
2 - Repository Indexing

ATG Commerce Search Guide

For example, the following definition file enables indexing of site users and their home addresses:

<?xml version="1.0" encoding="UTF-8"?>


<!DOCTYPE item PUBLIC "-//Art Technology Group, Inc.//DTD Repository Ouput
Specifier 1.0//EN" "http://www.atg.com/dtds/search/indexing-dependencyschema.dtd">
<item item-descriptor-name="user"
repository-path="/atg/userprofiling/ProfileAdapterRepository"
is-document="true">
<title property-name="lastName"/>
<meta-properties>
<property name="dateOfBirth" type="date"/>
</meta-properties>
<text-properties>
<property name="firstName"/>
<property name="lastName"/>
</text-properties>
<item property-name="homeAddress">
<text-properties>
<property name="address1"/>
<property name="address2"/>
<property name="city"/>
<property name="state"/>
<property name="postalCode"/>
<property name="phoneNumber"/>
</text-properties>
</item>
</item>

Note that in the above example, the top-level item element has the is-document attribute set to true.
This attribute specifies that an XHTML document should be generated for each item of that type (in this
case, each user item). If, instead, you want to generate a separate XHTML document per homeAddress
item, you set is-document to true for the homeAddress item type and not for the user item type. In that
case, the parent properties (firstName and lastName in the above example) are repeated in each
XHTML document.
Property values that come from standard JavaBean properties of the RepositoryItem object (rather
than dynamic bean properties) are specified using a dollar-sign ($) prefix; e.g., $repositoryId or
$repository.repositoryName. These dollar-sign property specifiers are the only constructions in the
definition file that support JavaBean dot notation.

Multi-value Properties
The item element has an is-multi attribute for specifying multi-value properties. If a property is an
array, Collection, or Map, you should set this attribute to true. The output XHTML document will include
all of the values of the property.

10
2 - Repository Indexing

ATG Commerce Search Guide

For example, in a Commerce product catalog, a product item will typically have a multi-valued
childSKUs property whose values are the various SKUs for the product. You might specify the property
like this:

<item property-name="childSKUs" is-multi="true">


<text-properties>
<property name="displayName"/>
<property name="description"/>
</text-properties>
</item>

The output document will include the displayName and description value for each SKU.
For properties that are Maps, the situation is more complex, because each Map entry has a key and a
value. To specify how to output the Map entries, you use the map-iteration-type attribute. The value
of this attribute can either be entries or values.
If map-iteration-type=values, only the values of the Map entries are output. Essentially, the values
are treated as an array or Collection, and the keys are ignored. The values must be repository items, and
the text-properties element is used to specify the properties of those items to output. For example:

<item property-name="someMap" is-multi="true" map-iteration-type="values">


<text-properties>
<property name="name"/>
<property name="age"/>
<property name="height"/>
</text-properties>
</item>

If map-iteration-type=entries, both the keys and the values of the Map are output; each Map entry
is treated as if it were a repository item with two properties, key and value. The values of value can be
either repository items or simple values such as primitives or Strings. For simple values, you can specify
the output like this:

<item property-name="someMap" is-multi="true" map-iteration-type="entries">


<text-properties>
<property name="key"/>
<property name="value"/>
</text-properties>
</item>

If the values of value are repository items, you treat the items as child items of the Map entry. For
example:

11
2 - Repository Indexing

ATG Commerce Search Guide

<item property-name="someMap" is-multi="true" map-iteration-type="entries">


<text-properties>
<property name="key"/>
</text-properties>
<item property-name="value">
<text-properties>
<property name="color"/>
<property name="size"/>
<property name="weight"/>
</text-properties>
</item>
</item>

Note that you can use map-iteration-type=entries to display just the keys or just the values, by
omitting the other tag.

XHTML Output Documents


ATG Search represents each document as a set of properties and their values. Each ATG Search document
is uniquely identified by a URL (typically the path name of the file on the file system). Properties can either
be meta properties, which are used for constraints and are not full-text indexed, or text properties, which
are full-text indexed for searching. When constructing a query, a client can constrain the search by meta
property, and also specify a list of properties to be returned for each search result item.
In the XHTML documents that the ATG platform generates from repository items, meta properties are
represented by meta tags in the head of the document, while text properties are represented by div tags
in the body of the document. The ATG platform generates meta and div tags using values from
repository item properties, and uses a URL of the following form to uniquely identify each document:
atgrep:/repository-name/item-descriptor-name/repository-id
meta and div properties are output with the following formats:
<meta name="atg:type:property-name" content="property-value">
<div class="atg:role:property-name" id="ID">

The XHTML documents name the properties using a simplified bean property notation. For example, a
document generated from a user profile might have firstName and lastName properties corresponding
to the equivalent properties of the user repository item type. The document properties corresponding to
the address1 and address2 properties of the homeAddress child repository item would be
homeAddress.address1 and homeAddress.address2.
Multi-value properties are given names without array subscripts, as are the property names of multi-value
repository item properties. For example, suppose a user repository item can have multiple homeAddress
child items. In the ATG platform, the state properties of these items would be named
homeAddress[0].state and homeAddress[1].state. In the XHTML documents, however, both
properties would be named homeAddress.state.

12
2 - Repository Indexing

ATG Commerce Search Guide

In addition to the properties you specify in the definition file, the output document also includes certain
properties that provide sufficient information to identify the repository items represented in the
document. The output for each item automatically includes the properties $repositoryId,
$repository.repositoryName, and $itemDescriptor.itemDescriptorName. The output for the
document-level item also includes a $url property and a $baseUrl property, which each contain the
URL representing this repository item. (The difference between these properties is that if a
VariantProducer is used to generate multiple documents from the same repository item, the $url
property for each document will include unique query arguments to distinguish the document from the
others. The $baseUrl property, which omits the query arguments, will be the same for each document.
See Using Variant Producers for more information.)
The following XHTML document, which shows sample output from the definition file appearing in the
Definition File Format section, illustrates each of these constructs:

<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/>
<title>Madeira</title>
<meta name="atg:date:dateOfBirth" content="-1583175600000"/>
<meta name="atg:string:$repository.repositoryName"
content="UserProfiles"/>
<meta name="atg:string:$repositoryId" content="743"/>
<meta name="atg:string:$itemDescriptor.itemDescriptorName"
content="user"/>
<meta name="atg:string:$url" content="atgrep:/UserProfiles/user/743"/>
<meta name="atg:string:$baseUrl"
content="atgrep:/UserProfiles/user/743"/>
<meta name="atg:string:homeAddress.$repository.repositoryName"
content="UserProfiles"/>
<meta name="atg:string:homeAddress.$repositoryId" content="743"/>
<meta
name="atg:string:homeAddress.$itemDescriptor.itemDescriptorName"
content="contactInfo"/>
</head>
<body>
<div class="atg:role:firstName" id="0">
Franklin
</div>
<div class="atg:role:lastName" id="1">
Madeira
</div>
<div class="atg:role:homeAddress.address1" id="2">
802 Replicant Blvd.
</div>
<div class="atg:role:homeAddress.city" id="3">
Los Angeles
</div>
<div class="atg:role:homeAddress.state" id="4">
CA

13
2 - Repository Indexing

ATG Commerce Search Guide

</div>
<div class="atg:role:homeAddress.postalCode" id="5">
98506
</div>
<div class="atg:role:homeAddress.phoneNumber" id="6">
(212)555-1234
</div>
</body>
</html>

Loading the Repository Data into ATG Search


Once you have created your XML definition file, the ATG platform can generate the XHTML documents
and load them into ATG Search for indexing. Depending on the needs of your site, this may be an
operation that is performed occasionally (if the content rarely changes) or frequently (if the content
changes often). To be as flexible as possible, the ATG platform provides two approaches to loading the
data:

Bulk loading loads all of the data generated from a repository into ATG Search. Each
time a bulk load is performed, the ATG platform creates and loads the complete set of
XHTML files for the repository, and ATG Search builds a complete index.

Incremental loading loads only the data that has changed since the last load. The
ATG platform determines which repository items have changed since the last
incremental or bulk load, and creates and loads the XHTML files for those items. ATG
Search then incrementally indexes those documents.

Bulk loading and incremental loading are not mutually exclusive. For some sites, only bulk loading will be
necessary, especially if site content is updated only occasionally. For other sites, incremental loading will
be needed to keep the search content up to date, but even for those sites it is important to perform a bulk
load occasionally to ensure the integrity of the indexed data. In particular, if you make any structural
changes to an indexed repository, you should run a bulk load so ATG Search builds a complete index to
replace the existing index.
In addition to configuring the Nucleus components described in this section, you must also create a
project in ATG Search Administration that manages the indexing process. You configure the project by
specifying the content to be indexed and various additional parameters, such as text processing options
or a schedule for performing the indexing. For example, you might schedule incremental indexing to take
place every 4 hours, and schedule bulk indexing to be performed once a week. For more information, see
the ATG Search Administration Guide.

Configuring Bulk Loading


You perform much of the configuration for the document loading operation through the
atg.repository.search.indexing.IndexingOutputConfig class. To set up document loading,
create a Nucleus component of this class, and give it global scope. You should create a separate

14
2 - Repository Indexing

ATG Commerce Search Guide

IndexingOutputConfig component for each type of XHTML document you want to index. At a
minimum, you need to set the following properties on each IndexingOutputConfig component:

bulkLoader
A Nucleus component of a class that implements the BulkLoader interface. You
should set this to /atg/search/repository/BulkLoader. Any number of
IndexingOutputConfig components can use this bulk loader.
definitionFile
The Nucleus address of the XML definition file that specifies how to transform the
repository data.

Configuring Incremental Loading


If you want to use incremental loading, there are two additional properties that need to be set on your
IndexingOutputConfig component:
enableIncrementalLoading
Set to true to enable incremental loading. Default is false.
incrementalLoader
A Nucleus component of a class that implements the
atg.repository.search.indexing.IncrementalLoader interface. You should
set this to /atg/search/repository/IncrementalLoader. Any number of
IndexingOutputConfig components can use this incremental loader.

The IncrementalLoader component uses an implementation of the PropertiesChangedListener


interface to monitor the repository for add, update, and delete events. It then analyzes these events to
determine which ones necessitate updating XHTML documents, and creates a queue of the affected
repository items. When a new incremental update is triggered, the IncrementalLoader processes the
items in the queue, generating and loading a new XHTML document for each changed repository item.

Using Monitored Properties


By default, the IncrementalLoader determines which changes necessitate updates by monitoring the
meta-properties and text-properties specified in the definition file. In some cases, however, the
properties you want to monitor are not necessarily the ones that you want to output. This is especially the
case if you are outputting derived properties, because these properties do not have values of their own.
For example, suppose your user item type has firstName and lastName properties, plus a fullName
derived property whose value is formed by concatenating the values of firstName and lastName. You
might want to output the fullName property, but to detect when the value of this property changes, you
need to monitor (but not necessarily output) firstName and lastName.
You can do this by including a monitor element in your definition file to specify properties that should be
monitored but not output. For example:

<text-properties>
<property name="fullName"/>
</text-properties>
<monitor>

15
2 - Repository Indexing

ATG Commerce Search Guide

<property name="firstName"/>
<property name="lastName"/>
</monitor>

For information about derived properties, see the ATG Repository Guide.

Tuning Incremental Loading


The number of changed items that accumulate in the queue can vary greatly, depending on how
frequently your data changes and how long you specify between incremental updates. Rather than
processing all of the changes at once, the IndexingOutputConfig component groups changes in
batches called generations. Each generation is processed as a separate ATG Search job.
IndexingOutputConfig has a maxIncrementalUpdatesPerGeneration property that specifies the
maximum number of changes that can be assigned to a generation. By default, this value is 1000, but you
can change this value if necessary. Larger generations require more ATG platform resources to process,
but reduce the number of ATG Search jobs required (and hence the overhead associated with starting up
and completing these jobs). Smaller generations require fewer ATG platform resources, but increase the
number of ATG Search jobs.

Using Incremental Indexing in an ATG Content Administration


Environment
A common setup is to use ATG Content Administration to manage a versioned repository (such as a
product catalog), and then to index the corresponding deployment (nonversioned) repository on your
staging or production environment. In this setup, when a repository is modified and deployed, the
incremental indexing system needs to be notified about the changes so they can be reflected in the next
incremental index.
To ensure that this happens, an IndexingOutputConfig component needs to be running in the ATG
Content Administration environment and listening for change events on the deployment repository. To
configure this IndexingOutputConfig component, set the targetName property to the name of the
deployment target.

Configuring a Document Submitter for Debugging


The bulk loader and the incremental loader call ATG system services to generate the XHTML
representations of the data. After each XHTML document is generated, the loaders use a document
submitter (created automatically) to submit the document content to ATG Search.
For debugging purposes, the atg.repository.search.indexing.submitter package includes
ConsoleDocumentSubmitter and FileDocumentSubmitter classes that can direct the XHTML to the
console or to files, rather than to ATG Search. These classes allow you to view the output without actually
initiating an indexing job. To direct the output to the console:
1.

Set the documentSubmitter property of your IndexingOutputConfig to a


component of class ConsoleDocumentSubmitter. (This step is optional. If the
property is not set, the output will be directed to the console by default.)

16
2 - Repository Indexing

ATG Commerce Search Guide

2.

Access the page for the IndexingOutputConfig component in the Component


Browser of the Dynamo Admin UI.

3.

In the Methods section, click the link for bulkLoad (to run the bulk loader) or
processQueuedUpdates (to run the incremental loader).

4.

At the confirmation prompt, click Yes to invoke the method.

To direct the XHTML output to files instead of the console, in Step 1 set the documentSubmitter
property to a component of class FileDocumentSubmitter. This class creates a separate file for each
XHTML document generated. The location and names of the files are automatically determined based on
the following properties:
baseDirectory
The pathname of the directory to write the files to.
filePrefix
The String to prepend to the name of each generated file. Default is the empty String.
fileSuffix
The String to append to the name of each generated file. Default is .xhtml.
nameByRepositoryId
If true, each filename will be based on the repository ID of the item the file represents.
If false (the default), files are named 0.xhtml, 1.xhtml, etc.
overwriteExistingFiles
If true, if the generated filename matches an existing file, the existing file will be
overwritten by the new file. If false (the default), the new file will be given a different
name to avoid overwriting the existing file.

Customizing the Output


The previous sections described the basic configuration of the document loading system. For many sites,
this configuration should be sufficient.
However, some sites have complex repositories that may require custom handling of the XHTML output.
For example, a repository may contain multiple versions of the same data, each in a different language. To
enable the document loading system to handle situations like this, the ATG platform includes interfaces
and classes that you can implement or extend to handle the particular needs of your site. The main
interfaces are PropertyAccessor, which defines how the document loaders obtain property values, and
VariantProducer, which specifies logic for creating multiple XHTML documents from the same
repository item.
Classes that implement these interfaces must be stateless, because they can be accessed by multiple
threads at the same time. Rather than maintaining state themselves, these classes instead use the
Context class to store state information and to pass data to each other.
This section discusses:

Using Custom Property Accessors

17
2 - Repository Indexing

ATG Commerce Search Guide

Using Variant Producers

Accessing the Context Object

Using Other Customization Classes

Using Custom Property Accessors


The document loaders access property values through an implementation of the
atg.repository.search.indexing.PropertyAccessor interface. This interface defines methods for
getting property values from repository items. It defines separate methods for text properties and meta
properties, as well as for properties that return child items. By default, the loaders use the
atg.repository.search.indexing.PropertyAccessorImpl class, which simply invokes
RepositoryItem.getPropertyValue(). You can write your own implementations of
PropertyAccessor that use custom logic for determining the values of specific properties. The simplest
way to do this is to subclass PropertyAccessorImpl.
In the definition file, you can specify a custom property accessor by using the property-accessor
attribute. For example, suppose you have a Nucleus component named
/MyStuff/MyPropertyAccessor, of a custom class that implements the PropertyAccessor interface.
You can specify it in the definition file like this:
<property name="price" property-accessor="/MyStuff/MyPropertyAccessor"/>

The value of the property-accessor attribute is the absolute path of the Nucleus component. To
simplify coding of the definition file, you can map PropertyAccessor Nucleus components to simple
names, and use those names as the values of property-accessor attributes. For example, if you map
the /MyStuff/MyPropertyAccessor component to the name myAccessor, the above tag becomes:
<property name="price" property-accessor="myAccessor"/>

You can perform this mapping by setting the propertyAccessorMap property of the
IndexingOutputConfig component. This property is a Map in which the keys are the names and the
values are PropertyAccessor Nucleus components that the names represent.

FirstWithLocalePropertyAccessor
The atg.repository.search.indexing.accessor package includes a subclass of
PropertyAccessorImpl named FirstWithLocalePropertyAccessor. This property accessor works
only with derived properties that are defined using the firstWithLocale derivation method.
FirstWithLocalePropertyAccessor determines the value of the derived property by looking up the
currentDocumentLocale property of the Context object. Typically, this property is set by the
LocaleVariantProducer, as described in Accessing the Context Object.
You can specify this property accessor in your definition file using the attribute value firstWithLocale.
(Note that you do not need to map this name to the property accessor in the propertyAccessorMap.)
For example:
<property name="displayName" property-accessor="firstWithLocale"/>

18
2 - Repository Indexing

ATG Commerce Search Guide

For information about the firstWithLocale derivation method, and about derived properties in
general, see the ATG Repository Guide.

Using Variant Producers


By default, for the repository item type designated by the is-document attribute, the
IndexingOutputConfig component generates one XHTML document per item. In some cases, though,
you may want to generate more than one document for each repository item. For example, suppose you
have a repository whose text properties are stored in both French and English, and the language
displayed is determined by the users locale setting. In this case you will typically want to create two
documents from each repository item, one with the text content in French, and the other one in English.
To handle situations like this, the ATG platform provides an interface named
atg.repository.search.indexing.VariantProducer. You can write your own implementations of
the VariantProducer interface, or you can use implementations included with the ATG platform. This
interface defines a single method, prepareNextVariant(), for determining the number and type of

variants to produce. Depending on how your repository is organized, implementations of this method
can use a variety of approaches for determining how to generate variant documents. For example, the
atg.repository.search.indexing.producer.LocaleVariantProducer class generates a variant
for each locale specified in its locales array property.
You specify the VariantProducer components to use by setting the variantProducers property of
the IndexingOutputConfig component. Note that this property is an array; you can specify any number
of VariantProducer components, and the IndexingOutputConfig will generate a separate variant for
each possible combination of values of the variant criteria. For example, suppose you use
LocaleVariantProducer and you specify two locales, French and English. If you add a second
VariantProducer that creates three variants (1, 2, and 3), the total number of variants generated for
each repository item would be six (French 1, English 1, French 2, English 2, French 3, and English 3).

Accessing the Context Object


When a document loader is invoked, it creates an object of class
atg.repository.search.indexing.Context. The PropertyAccessor and VariantProducer
classes use this object to store and retrieve state information about the loading process. The Context
object contains the current list of parent repository items that were navigated to reach the current item
(both specifiers and repository items), the current document URL (if any), the current collected output
values (if any), and status information.
One of the main uses of the Context object is to store information used to determine what variant to
generate next. For example, each time a new document is generated, the LocaleVariantProducer uses
the next value in its locale array to set the currentDocumentLocale property of the Context object. A
PropertyAccessor instance might read the currentDocumentLocale property and use its current
value to determine the locale to use for the property.
For more information about the Context object, see the ATG API Reference.

19
2 - Repository Indexing

ATG Commerce Search Guide

Using Other Customization Classes

In addition to the PropertyAccessor and VariantProducer interfaces, the


atg.repository.search.indexing package includes two other interfaces that you can use to
customize your output:

PropertyFormatter

PropertyValuesFilter

Note that classes that implement these interfaces are applied after all of the output properties have been
gathered, so these classes do not have access to the Context object.
The PropertyFormatter and PropertyValuesFilter interfaces and implementation classes are
described below. For additional information, see the ATG API Reference.

PropertyFormatter
If a property takes an object as its value, the document loader must convert that object to a String to
include it in an output document. The PropertyFormatter interface defines two methods for
performing this conversion: formatText() (for text properties) and formatMeta() (for meta properties).
By default, the document loaders use the implementation class
atg.repository.search.indexing.formatter.PropertyFormatterImpl. For text properties, this
class simply invokes the objects toString() method. For meta properties, it invokes getLong() for
numbers, getTime() for dates, and toString() for other objects.

You can write your own implementations of PropertyFormatter that use custom logic for performing
the conversion. The simplest way to do this is to subclass PropertyFormatterImpl.
In the definition file, you can specify a custom property formatter by using the formatter attribute. For
example, suppose you have a Nucleus component named /MyStuff/MyPropertyFormatter, of a
custom class that implements the PropertyFormatter interface. You can specify it in the definition file
like this:
<property name="price" formatter="/MyStuff/MyPropertyFormatter"/>

The value of the formatter attribute is the absolute path of the Nucleus component. To simplify coding
of the definition file, you can map PropertyFormatter Nucleus components to simple names, and use
those names as the values of formatter attributes. For example, if you map the
/MyStuff/MyPropertyFormatter component to the name myFormatter, the above tag becomes:
<property name="price" formatter="myFormatter"/>

You can perform this mapping by setting the formatterMap property of the IndexingOutputConfig
component. This property is a Map in which the keys are the names and the values are
PropertyFormatter Nucleus components that the names represent.

PropertyValuesFilter
In some cases, you may want to filter a set of property values before outputting an XHTML document. For
example, suppose your document-level item has many child items, and each child item has a color

20
2 - Repository Indexing

ATG Commerce Search Guide

property that can have only a few possible values. Rather than outputting the color of every child item,
you may want the document to include each color just once. To do this, you could use a filter that
removes duplicate property values.
The PropertyValuesFilter interface defines a method for filtering property values. The
atg.repository.search.indexing.filter package includes two implementations of this interface:

UniqueFilter removes duplicate property values, returning only the unique values.

ConcatFilter concatenates all of the property values into a single String.

In the definition file, you can specify property filters by using the filter attribute. Note that you can use
multiple property filters on the same property. The value of the filter attribute is a comma-separated
list of Nucleus components. The component names must be absolute pathnames.
To simplify coding of the definition file, you can map PropertyValuesFilter Nucleus components to
simple names, and use those names as the values of filter attributes. You can perform this mapping by
setting the filterMap property of the IndexingOutputConfig component. This property is a Map in
which the keys are the names and the values are PropertyFilter Nucleus components that the names
represent.
For example, suppose you create Nucleus components of the UniqueFilter and ConcatFilter classes,
and you map these components to the names myUnique and myConcat. You could then specify these
filters like this:
<property name="color" filter="myUnique,MyConcat"/>

Transforming and Loading Catalog Data


This section discusses specific aspects of indexing repository items in an ATG Commerce catalog. It
includes the following topics:

Transforming Catalog Data

Transforming Custom Catalog Data

Excluding Uncategorized Products from Indexing

Loading Catalog Data

Transforming Catalog Data


For indexing, commerce catalogs are typically broken down by product. Each product item is transformed
into an XHTML document based on a definition file. The definition file specifies that each output
document should include information about the products parent category and child SKUs (as well as the
product itself), so that site visitors can search category or SKU properties in addition to product
properties.
The DCS.Search module includes an IndexingOutputConfig component and definition file that are
preconfigured to work with a typical catalog repository. You can use this component and definition file as

21
2 - Repository Indexing

ATG Commerce Search Guide

is, or modify them or create your own component based on them. The component,
/atg/commerce/search/ProductCatalogOutputConfig, is configured like this:

definitionFile=/atg/commerce/search/product-catalog-output-config.xml
bulkLoader=/atg/search/repository/BulkLoader
incrementalLoader=/atg/search/repository/IncrementalLoader
enableIncrementalLoading=false
variantProducers=LocaleVariantProducer
indexingSynchronizations+=\
/atg/commerce/search/refinement/RefinementConfigurationSubmitter

The XML definition file, product-catalog-output-config.xml, is designed to output the catalog


properties that users are most likely to search for, and exclude the least likely ones. For example, it
includes the products display name and description properties and the list price and sale price of the
child SKUs, but omits all image properties.
The following is a sample XHTML file generated for a product, based on the product-catalog-outputconfig.xml definition file:

<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/>
<title>strawberries (organic)</title>
<meta name="atg:string,index:$repositoryId" content="prod10015"/>
<meta name="atg:date:creationDate" content="1149279750"/>
<meta name="atg:string:displayName" content="strawberries (organic)"/>
<meta name="atg:string:description" content="organic strawberries"/>
<meta name="atg:string:longDescription" content="Organic strawberries for your
eating pleasure. Pesticide free and great tasting too."/>
<meta name="atg:string:$repository.repositoryName"
content="CustomProductCatalog"/>
<meta name="atg:string:$itemDescriptor.itemDescriptorName" content="product"/>
<meta name="atg:string:$url"
content="atgrep:/CustomProductCatalog/product/prod10015?
catalog=catalog10003&amp;locale=en_US"/>
<meta name="atg:string:$baseUrl"
content="atgrep:/CustomProductCatalog/product/prod10015"/>
<meta name="atg:string:childSKUs.$repositoryId" content="sku10018"/>
<meta name="atg:date:childSKUs.creationDate" content="1149279810"/>
<meta name="atg:string:childSKUs.type" content="sku"/>
<meta name="atg:float:childSKUs.wholesalePrice" content="2.0"/>
<meta name="atg:float:childSKUs.listPrice" content="3.99"/>
<meta name="atg:float:childSKUs.salePrice" content="2.49"/>
<meta name="atg:boolean:childSKUs.onSale" content="false"/>
<meta name="atg:string:childSKUs.displayName" content="strawberries pint
(organic)"/>
<meta name="atg:string:childSKUs.$repository.repositoryName"

22
2 - Repository Indexing

ATG Commerce Search Guide

content="CustomProductCatalog"/>
<meta name="atg:string:childSKUs.$itemDescriptor.itemDescriptorName"
content="sku"/>
<meta name="atg:string:childSKUs.$repositoryId" content="sku10020"/>
<meta name="atg:date:childSKUs.creationDate" content="1149279836"/>
<meta name="atg:string:childSKUs.type" content="sku"/>
<meta name="atg:float:childSKUs.wholesalePrice" content="3.99"/>
<meta name="atg:float:childSKUs.listPrice" content="6.99"/>
<meta name="atg:float:childSKUs.salePrice" content="4.99"/>
<meta name="atg:boolean:childSKUs.onSale" content="false"/>
<meta name="atg:string:childSKUs.displayName" content="strawberries quart
(organic)"/>
<meta name="atg:string:childSKUs.description" content="quart of organic
strawberries"/>
<meta name="atg:string:childSKUs.$repository.repositoryName"
content="CustomProductCatalog"/>
<meta name="atg:string:childSKUs.$itemDescriptor.itemDescriptorName"
content="sku"/>
<meta name="atg:string:parentCategory.$repositoryId" content="cat10009"/>
<meta name="atg:date:parentCategory.creationDate" content="1149279681"/>
<meta name="atg:string:parentCategory.displayName" content="organic berries"/>
<meta name="atg:string:parentCategory.$repository.repositoryName"
content="CustomProductCatalog"/>
<meta name="atg:string:parentCategory.$itemDescriptor.itemDescriptorName"
content="category"/>
<meta name="atg:string:ancestorCategories.$repositoryId" content="cat10005"/>
<meta name="atg:date:ancestorCategories.creationDate" content="1149258114"/>
<meta name="atg:string:ancestorCategories.displayName" content="berries"/>
<meta name="atg:string:ancestorCategories.$repository.repositoryName"
content="CustomProductCatalog"/>
<meta name="atg:string:ancestorCategories.$itemDescriptor.itemDescriptorName"
content="category"/>
<meta name="atg:string:ancestorCategories.$repositoryId" content="cat10009"/>
<meta name="atg:date:ancestorCategories.creationDate" content="1149279681"/>
<meta name="atg:string:ancestorCategories.displayName" content="organic
berries"/>
<meta name="atg:string:ancestorCategories.$repository.repositoryName"
content="CustomProductCatalog"/>
<meta name="atg:string:ancestorCategories.$itemDescriptor.itemDescriptorName"
content="category"/>
<meta name="atg:string:catalogs.$repositoryId" content="catalog10003"/>
<meta name="atg:string:catalogs.$repository.repositoryName"
content="CustomProductCatalog"/>
<meta name="atg:string:catalogs.$itemDescriptor.itemDescriptorName"
content="catalog"/>
</head>
<body>
<div class="atg:role:displayName" id="0">strawberries (organic)</div>
<div class="atg:role:description" id="1">organic strawberries</div>
<div class="atg:role:longDescription" id="2">Organic strawberries for your

23
2 - Repository Indexing

ATG Commerce Search Guide

eating pleasure. Pesticide free and great tasting too.</div>


<div class="atg:role:childSKUs.displayName" id="3">strawberries pint
(organic)</div>
<div class="atg:role:childSKUs.displayName" id="4">strawberries quart
(organic)</div>
<div class="atg:role:childSKUs.description" id="5">quart of organic
strawberries</div>
<div class="atg:role:parentCategory.displayName" id="6">organic berries</div>
<div class="atg:role:ancestorCategories.displayName" id="7">berries</div>
<div class="atg:role:ancestorCategories.displayName" id="8">organic
berries</div>
</body>
</html>

Transforming Custom Catalog Data


Custom catalogs include catalog items in addition to the category, product, and SKU items that make
up the standard catalog. Each user is assigned a catalog, and sees the navigational structure, product and
SKU items, and property values associated with that catalog. A given product may appear in multiple
catalogs. The product repository item type for custom catalogs includes an additional property,
catalogs, which is an array of the catalogs the product is included in.
In addition to introducing a new organizational structure, custom catalogs also offer the ability to
customize the view of a catalog entity such as a category, product, or SKU, so that its property values can
vary depending on the catalog that is associated with the user. For example, if you assign catalogs to
users based on the region they live in, you might want the product descriptions to be tailored to the
region. This means that when you index the catalog, you will need to generate multiple XHTML files for
each product (one for each catalog a product is included in).
If your site uses custom catalogs, you should be sure to include the DCS.Search.CustomCatalogs
module when you assemble your application. This module creates several Nucleus components that are
used when indexing catalog data on a site that uses custom catalogs, including these key components:

/atg/commerce/search/CustomCatalogPropertyAccessor This component is


of class atg.commerce.search.producer.CustomCatalogPropertyAccessor,
which implements the atg.repository.search.indexing.PropertyAccessor

interface. (See Using Custom Property Accessors.)

/atg/commerce/search/CustomCatalogVariantProducer This component is of


class atg.commerce.search.producer.CustomCatalogVariantProducer, which
implements the atg.repository.search.indexing.VariantProducer interface.
(See Using Variant Producers.)

The DCS.Search.CustomCatalogs module makes the following modifications to the configuration of


the ProductCatalogOutputConfig component to support custom catalogs:

Adds the catalogs property to the product item type in the product-catalogoutput-config.xml definition file, and specifies that the
CustomCatalogPropertyAccessor component should be used to determine the
value of this property.

24
2 - Repository Indexing

ATG Commerce Search Guide

Adds the /atg/commerce/search/CustomCatalogVariantProducer component


to the components variantProducers property.

Generating Multiple XHTML Files for Each Product


The CustomCatalogPropertyAccessor and the CustomCatalogVariantProducer work together to
generate a separate XHTML document for each catalog a product is in.
ProductCatalogOutputConfig uses the CustomCatalogVariantProducer to generate, for an
individual product, a separate XHTML document for each catalog listed in the catalogs property of the

product. The value of this property in the catalog repository is an array of all the catalogs the product is
included in. The variant producer iterates through these catalogs individually, so that each XHTML
document will contain, for other properties of the product, only the values associated with a single
catalog.
The values of the products properties are obtained by the CustomCatalogPropertyAccessor, based
on the catalog associated with the current variant. Note that these properties must be derived properties
that use the CatalogDerivationMap class to derive their catalog-specific values.
If your custom catalog does not use catalog-specific values, you should disable the
CustomCatalogVariantProducer by removing it from the variantProducers property of
ProductCatalogOutputConfig. This will reduce the number of XHTML documents generated,
decreasing the time it takes to index the data.

Excluding Uncategorized Products from Indexing


The top-level node in the XML definition file defines the starting point for retrieving items to index. You
can limit the set of items to index by adding an optional repository-item-group attribute to specify
the Nucleus location of a component whose class implements the
atg.repository.RepositoryItemGroup interface. A class that implements this interface defines a
logical grouping of repository items.
For example:
<item item-descriptor-name="product"
repository-path="/atg/commerce/catalog/ProductCatalog"
repository-item-group="/atg/commerce/search/IndexedItemsGroup"
is-document="true">

Some commerce sites display search results only for items that can also be viewed by browsing the
catalog hierarchy. In order to be displayed in the catalog tree, a product must have an associated
category.
If you want to exclude uncategorized products from indexing, you can specify a repository item group,
such as /atg/commerce/search/IndexedItemsGroup, that represents the location of items that are
properly categorized within your site. If a repository-item-group attribute is not specified,
uncategorized products will be indexed.
IndexedItemsGroup specifies rules for both standard and custom catalogs, depending on which

modules are started. This is the rule for standard catalogs:

25
2 - Repository Indexing

ATG Commerce Search Guide

<!-- products whose "ancestorCategories" property includes an item whose "root"


property is true. -->
<ruleset>
<accepts>
<rule op="includesItem">
<valueof target="ancestorCategories">
<rule op=eq>
<valueof target="root">
<valueof constant="true">
</rule>
</rule>
</accepts>
</ruleset>

This is the rule for custom catalogs (which overrides the standard catalog rule if you run the
DCS.Search.CustomCatalogs module):

<!-- products whose "catalogs" property is not null. -->


<ruleset>
<accepts>
<rule op=isNotNull>
<valueof target="catalogs">
</rule>
</accepts>
</ruleset>

Using SKU-Based Indexing


By default, the ProductCatalogOutputConfig component is configured to create an XHTML document
for each product in the product catalog. This means that each document indexed by ATG Search
corresponds to a product, so that when a site visitor searches the catalog, each individual result returned
represents a product.
Some sites may prefer to create a separate XHTML document for each SKU, so that each search result
represents a SKU rather than a product. To enable SKU-based indexing, ATG Commerce includes the
DCS.Search.Index.SKUIndexing module. This module makes various configuration changes to
Commerce components to enable SKU-based indexing rather than product-based indexing. For example,
it modifies the ProductCatalogOutputConfig components definition file (product-catalogoutput-config.xml), setting the is-document attribute to false for the product item type, and to
true for the childSKUs item type.
To enable SKU-based indexing, include the DCS.Search.Index.SKUIndexing module when you
assemble your application. See Running the Commerce Search Modules for more information.

26
2 - Repository Indexing

ATG Commerce Search Guide

Loading Catalog Data


Catalog data does not require any special commerce extensions for loading. By default,
ProductCatalogOutputConfig uses the standard bulk loader and incremental loader.
Note that modifying a catalog often results in structural changes to the catalog repository. To ensure the
integrity of the indexed data, it is a good idea to run a bulk load (rather than an incremental load) after
you modify a catalog.

27
2 - Repository Indexing

ATG Commerce Search Guide

28
2 - Repository Indexing

ATG Commerce Search Guide

3 Search Form Handlers

The ATG platform includes several form handlers that you can use to build forms for issuing queries to
ATG Search. These forms are useful for searching ATG repository data that has been indexed by ATG
Search, but they are not restricted to this type of data. In fact, they can be used for searching any data
indexed by ATG Search. It is therefore possible to use these form handlers to build a wide variety of user
interfaces to ATG Search, and to make the full power of the ATG platform available for working with ATG
Search data. For example, you could create a form that uses the data returned from a search query to
construct a JMS message that triggers a scenario.
Note that this chapter discusses a large number of ATG platform and ATG Search classes and components.
In some cases you may want more detail than is provided here. For more information about the classes
described here, see the ATG API Reference.
This chapter includes the following sections:
Form Handler Classes and Architecture
Constructing Queries
Handling Results
Refining Search Results
JMS Event Handling

Form Handler Classes and Architecture


The atg.search.query.formhandlers package provides a set of six form handlers for submitting
queries to ATG Search. Each form handler can construct one of the six ATG Search query types.

Form Handler Class

Query Type

Client API Request Type

QueryFormHandler

<query>

ClientQueryRequest

StructuredQueryFormHandler

<structquery>

ClientStructuredRequest

BrowseFormHandler

<browse>

ClientCategoryRequest

ViewInContextFormHandler

<viewInContext>

ClientVicRequest

SimilarDocsFormHandler

<similardocs>

ClientSimilarDocsRequest

29
3 - Search Form Handlers

ATG Commerce Search Guide

CategorizeFormHandler

<categorize>

ClientCategorizeRequest

These form handler classes are all subclasses of an abstract class, BaseSearchFormHandler, that
implements much of the generic functionality of the form handlers: error handling, URL redirection,
maintaining state information, query submission, event firing, etc. Each subclass then implements the
logic necessary for constructing queries of one specific type.
From an architectural point of view, the search form handler classes are designed to be as simple as
possible. Rather than including related functionality in the form handlers themselves, the ATG platform
provides a number of additional classes with discrete functional roles. This approach allows each piece of
functionality to be replaced more easily, and helps minimize the duplication of code.
A key element of this design is the SearchContext class, which is used as a session-scoped component
for maintaining state information between requests. The form handlers themselves are designed to be
request scoped.

Configuring the Form Handlers


ATG Commerce includes a preconfigured instance of the QueryFormHandler,
/atg/commerce/search/ProductCatalogQueryFormHandler. You can use this form handler to create
search forms for Commerce sites.
To create a new form handler component, determine which form handler class you need, and configure a
request-scoped Nucleus component of that class. Set the following properties:
siteName
The name of the site, as shown under the Admin tab of the ATG Search Management
Console.
searchService
The ESSearchServiceImpl component to use. Any number of form handler
components can use the same ESSearchServiceImpl component.
searchContext
The SearchContext component to use to store state information between requests.
(You must create this component and give it session scope, but there are no
properties that you need to set.)
If the form handler class is QueryFormHandler, and you are searching ATG repository items, you also
need to set the activeSolutionZones key of the form handlers relQuestSettings property. The
value of this key should be a String that encodes the names of all the indexed properties as a commaseparated list.
The relQuestSettings property is of type atg.nucleus.ResolvingMap, a Map type that supports the
Nucleus ^= syntax for linking to property values of other components. This syntax makes it possible to set
the activeSolutionZones key by linking it to the textActiveZones property of the
IndexingOutputConfig component, which contains the appropriate String. For example:

30
3 - Search Form Handlers

ATG Commerce Search Guide

relQuestSettings=\
activeSolutionZones^=/MyStuff/MyIndexingOutputConfig.textActiveZones

Sample Application
The ATG platform includes a sample Web application that uses the search form handler classes. This
application has six search form pages, one for each ATG Search query type (and thus each one using a
different form handler). You can use the application for submitting test queries, or use the JSPs as starting
points for building your own search pages. The application also includes sample Nucleus components of
all of the form handlers and related classes described above.
Before you can use this sample application, you need to modify its SearchServer component to point to
your ATG Search Routing instance. To do this, create an
<ATG2007.1dir>/home/localconfig/atg/search/query/formhandlers directory, and in this
directory create a file named SampleSearchServer.properties to set the properties of the
component. See Configuring the ATG Platform to Issue Queries for information about the settings to use.
To run the sample application, you need to assemble an EAR file that includes the
DAF.Search.Query.SearchTest module, and deploy this application on your application server. You
can then access the application at:
http://hostname:port/search/search/index.jsp

See the ATG Installation and Configuration Guide for more information about the port number to use. For
information about assembling applications, see the ATG Programming Guide.
Once the application is open in your browser, click the link for one of the query types. This opens a page
that contains a form for constructing a query of that type. Fill in the form, and then click the Search
button. The results of the search are displayed at the bottom of the page.
Note that neither the search forms nor the results output are intended to be realistic examples of how you
would use these form handlers on an actual site. The forms enable you set search attributes that are rarely
set by individual queries. In addition, the forms allow you to specify the attributes directly. In an actual
search page, the form handler might set certain attributes, but the values used would typically be
determined by logic implemented in the page or in methods of the form handler itself. For the results
output, the pages simply display a table of the fields of the ATG Search Results object and their values.
Obviously, on an actual site, the results would be displayed in a more usable (and selective) format.

Constructing Queries
Each search form handler has properties that store the values that are sent to ATG Search when a query is
submitted. Each form handler uses a different set of these properties, depending on the tags the
individual query type supports.
The following table describes all of the form handler properties that can be set in JSPs. Some of the more
complex properties are described in more detail below the table.

31
3 - Search Form Handlers

ATG Commerce Search Guide

Form Handler Property

Description

Form Handlers

docContextID

A String used to set the contents of the


<docContextID> tag of the query.

ViewInContextFormHandler

docProps

An array of Strings used to set the docProps


request attribute, which controls the meta
properties returned with each result.

QueryFormHandler

documentSetsBuilder

Sets the contents of the <documentSets> tag


of the query, using the XML Builder feature
described in Using the XML Builder.

BrowseFormHandler

input

A String used to set the contents of the


<input> tag of the query.

BrowseFormHandler
CategorizeFormHandler
SimilarDocsFormHandler
ViewInContextFormHandler

parserOptionsBuilder

Sets the contents of the <parserOptions> tag


of the query, using the XML Builder feature
described in Using the XML Builder.

BrowseFormHandler
CategorizeFormHandler
QueryFormHandler
SimilarDocsFormHandler
StructuredQueryFormHandler

prefAnswerConstrBuilder

Sets the contents of the <prefAnswerConstr>


tag of the query, using the XML Builder feature
described in Using the XML Builder.

QueryFormHandler

priorInput

An array of Strings used to set the contents of


<priorInput> tags of the query. Each String in
the array is used as the body of a separate
<priorInput> tag.

QueryFormHandler

property

A String used to set the contents of the


<property> tag of the query.

ViewInContextFormHandler

question

The search String entered by the user.

QueryFormHandler

relQuestSettings

A Map used to set the value of the


relQuestSettings request attribute of the
<query> query type. See Setting the
relQuestSettings and responseNumberSettings
Attributes.

QueryFormHandler

requestAttributes

The request attributes for the query. This


property is a Map of key/value pairs, where the
keys are attribute names and the values are
used to set the corresponding attribute in the
query.

BrowseFormHandler

CategorizeFormHandler
QueryFormHandler
SimilarDocsFormHandler
StructuredQueryFormHandler

CategorizeFormHandler
QueryFormHandler
SimilarDocsFormHandler
StructuredQueryFormHandler

32
3 - Search Form Handlers

ATG Commerce Search Guide

responseNumberSettings

A Map used to set the value of the


responseNumberSettings request attribute
of the <query> query type. See Setting the
relQuestSettings and responseNumberSettings
Attributes.

QueryFormHandler

return

A String used to set the value of the


returnType request attribute.

ViewInContextFormHandler

structuredStatements

An array of StructuredStatement objects used


to set the <statement> tags of the query. See
Specifying Structured Statements.

StructuredQueryFormHandler

url

A String used to set the contents of the <url>


tag of the query.

ViewInContextFormHandler

value

A String used to set the contents of the


<value> tag of the query.

ViewInContextFormHandler

weightedPropsBuilder

Sets the contents of the <weightedProps> tag


of the query, using the XML Builder feature
described in Using the XML Builder.

QueryFormHandler
StructuredQueryFormHandler

Setting the Request Attributes


Most of the search form handlers have a requestAttributes property that is used to set the request
attributes of the query. This property is a Map that stores each attribute name and its value as a key/value
pair. When a JSP that includes a search form handler is loaded, the value of requestAttributes is set by
reading in the site defaults from ATG Search. In the page, you can use DSP tags to modify the values of the
Map entries for certain attributes, based on user input. When the query is submitted, the entire
requestAttributes Map is included. Note, however, that you will typically want to modify the values of
only a small subset of the possible attributes; for most attributes, the value submitted will be the same as
the site default.
This JSP fragment from the sample application uses a variety of controls (text field, drop-down, checkbox)
to set the values of a few of the request attributes:

<c:set var="formHandlerPath"
value="/atg/search/query/formhandlers/SampleQueryFormHandler"/>
debug [0=8]:
<dspel:input type="text" id="debug"
name="debug" bean="${formHandlerPath}.requestAttributes.debug" />
RQText:
<dspel:select bean="${formHandlerPath}.requestAttributes.RQText">

33
3 - Search Form Handlers

ATG Commerce Search Guide

<dspel:option value="question">question</dspel:option>
<dspel:option value="sparsetree">answer</dspel:option>
</dspel:select>
sorting:
<dspel:select bean="${formHandlerPath}.requestAttributes.sorting">
<dspel:option value="score">score</dspel:option>
<dspel:option value="document">document</dspel:option>
</dspel:select>
docSetSort:
<dspel:select bean="${formHandlerPath}.requestAttributes.docSetSort">
<dspel:option value="none">
none
</dspel:option>
<dspel:option value="fulltree">
fulltree
</dspel:option>
<dspel:option value="sparsetree">
sparsetree
</dspel:option>
</dspel:select>
autospell:
<dspel:input type="checkbox"
bean="${formHandlerPath}.requestAttributes.autospell"/>

Setting the relQuestSettings and responseNumberSettings Attributes


The request attributes for the <query> query type include two important attributes, relQuestSettings
and responseNumberSettings, that each comprise many subattributes. In the requestAttributes
Map, each of these attributes is stored as a single long String that encodes the values of all of the
subattributes.
To simplify the setting of the subattributes, the QueryFormHandler has relQuestSettings and
responseNumberSettings properties that correspond to these request attributes. Each of these
properties is a Map that stores the subattributes as key/value pairs. When a JSP that includes a
QueryFormHandler is loaded, the values in each Map are set by parsing the corresponding String. In the
page, you can use DSP tags to modify the values of the Map entries for certain subattributes, based on
user input. When the query is submitted, the Map is then used to recreate the entire String and the
corresponding request attribute is set to the new String.
The following is an example of setting a responseNumberSettings attribute in a JSP:

responseNumberSettings.ans:
<dspel:input type="text" bean="${formHandlerPath}.responseNumberSettings.ans"/>

34
3 - Search Form Handlers

ATG Commerce Search Guide

Using the XML Builder


Certain form handler properties (documentSets, parserOptions, prefAnswerConstr, and
weightedProps) set query tags that can contain child tags. To set these query tags, the form handler
must gather user input and use it to assemble the XML. This can be an involved process, especially if the
XML is complex, with many levels of nested tags.
For example, the contents of the <documentSets> tag might look something like this:

<and>
<strprop op="equal" case="false" name="childSKU.color">
rose
</strprop>
<numprop op="lesseq" name="childSKU.price">
30.00
</numprop>
</and>

Within the <documentSets> tag, these tags would limit search results to items with a property key called
childSKU.color with an associated value of "rose" and a property key called childSKU.price with
an associated value that is less than or equal to 30.00. This is only a simple constraints example. Actual
<documentSets> tags can be arbitrarily complex, and can include nested Boolean (<or>,<and>, and
<not>) tags.
Query tags that can contain nested tags are represented in the form handlers by properties of type
atg.search.query.formhandlers.XMLBuilder. XMLBuilder is a simple interface with one method,
buildXML(), which the form handlers invoke when they assemble the query. You can create your own
implementation of this interface, and point the corresponding form handler property at a Nucleus
component of this custom class.
For example, to specify a custom XML builder to use for the <documentSets> tag:
documentSetsBuilder=/app/customXMLBuilder

MapXMLBuilder
If no custom builder is specified for a given XMLBuilder type form handler property, the form handler
will default to using the atg.search.query.formhandlers.MapXMLBuilder class. This class is
designed to allow creation of arbitrarily complex XML in JSPs.
For more information, see Appendix B: Using the MapXMLBuilder Class.

CustomCatalogXMLBuilder
Queries for ATG Commerce custom catalogs can use the
atg.commerce.search.CustomCatalogXMLBuilder class, an extension of the MapXMLBuilder class,
as the documentSetsBuilder. This adds an extra dynamic constraint to the query that checks to see if all
the product document results are part of the users catalog.

35
3 - Search Form Handlers

ATG Commerce Search Guide

CustomCatalogXmlBuilder constructs an AND query that contains the existing query and a query
constraint for the catalog, which checks to see if the product.ancestorCatalogs property contains the
catalog currently set as the users.

Specifying Structured Statements


The structuredStatements property of the StructuredQueryFormHandler is an array of
StructuredStatement objects. When the form handler submits a query, it uses each object in the array
to create a separate <statement> tag for the query. The attributes of the tag are set from the properties
of the StructuredStatement object.
In the JSP, you create the individual StructuredStatement objects by setting the properties of each
object through form fields. For example, the following page fragment creates a four-row table where each
row represents an individual <statement> tag:

<c:set var="formHandlerPath"
value="/atg/search/query/formhandlers/SampleStructQueryFormHandler"/>
<c:set var="tagname" value="structquery"/>
<dspel:importbean var="formHandler"
bean="${formHandlerPath}"/>
<!-- StructuredStatement -->
<table border="1" width="100%">
<tr bgcolor="LIGHTBLUE">
<td>name</td>
<td>query text (body)</td>
<td>op</td>
<td>mode</td>
<td>strategy</td>
<td>weight (0-100)</td>
<td>threshold (0-100)</td>
<td>mutex</td>
</tr>
<c:forEach begin="0" end="3" var="index">
<tr>
<td>
<dspel:input type="text"
bean="${formHandlerPath}.statement[${index}].name"/>
</td>
<td>
<dspel:input type="text"
bean="${formHandlerPath}.statement[${index}].queryText"/>
</td>
<td>
<dspel:select bean="${formHandlerPath}.statement[${index}].op">
<dspel:option value="">default</dspel:option>
<dspel:option value="required">required</dspel:option>
<dspel:option value="negative">negative</dspel:option>

36
3 - Search Form Handlers

ATG Commerce Search Guide

<dspel:option value="optional">optional</dspel:option>
</dspel:select>
</td>
<td>
<dspel:select bean="${formHandlerPath}.statement[${index}].mode">
<dspel:option value="">default</dspel:option>
<dspel:option value="required">nlp</dspel:option>
<dspel:option value="negative">boolean</dspel:option>
</dspel:select>
</td>
<td>
<dspel:select bean="${formHandlerPath}.statement[${index}].strategy">
<dspel:option value="">default</dspel:option>
<dspel:option value="normal">normal</dspel:option>
<dspel:option value="everything">everything</dspel:option>
<dspel:option value="expand">expand</dspel:option>
<dspel:option value="restrict">restrict</dspel:option>
<dspel:option value="exact">exact</dspel:option>
</dspel:select>
</td>
<td>
<dspel:input type="text"
bean="${formHandlerPath}.statement[${index}].weight"/>
</td>
<td>
<dspel:input type="text"
bean="${formHandlerPath}.statement[${index}].threshold"/>
</td>
<td>
<dspel:input type="checkbox"
bean="${formHandlerPath}.statement[${index}].mutex"/>
</td>
</tr>
</c:forEach>
</table>

Creating Parametric Search Queries


Parametric search is the ability to restrict the search based on properties of the item type being searched
for. For example, you could enable users to search for products made by a certain manufacturer. The
search results would return only those product repository items whose manufacturer property is set to
the specified value.
The following figure illustrates a search form that allows the user to restrict the search to products from a
single manufacturer:

37
3 - Search Form Handlers

ATG Commerce Search Guide

The following JSP example creates a page that includes the form controls shown above.

<%@ 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">
/**
* Changes the page number.
**/
function changePage(page) {
var form = document.forms['searchForm'];
if(form == null)
return false;
var input = form.elements['pageNum'];
if(input == null)
return false;
input.value=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"

38
3 - Search Form Handlers

ATG Commerce Search Guide

onchange="changePage(0);"/>
<!-- The parametric search control -->
<!-- This generates the following XML query constraint -->
<!-- <prop type="string" name="manufacturer.$repositoryId"
op="equals" case="false">Kawaf</prop> -->
<dspel:input type="hidden"
bean="${formHandlerPath}.documentSetsBuilder.tags.str1.tagname"
value="prop" />
<dspel:input type="hidden"
bean="${formHandlerPath}.documentSetsBuilder.tags.str1.opts.generate"
value="ifvalue:body" />
<dspel:input type="hidden"
bean="${formHandlerPath}.documentSetsBuilder.tags.str1.attr.type"
value="string"/>
<dspel:input type="hidden"
bean="${formHandlerPath}.documentSetsBuilder.tags.str1.attr.name"
value="manufacturer.$repositoryId"/>
<dspel:input type="hidden"
bean="${formHandlerPath}.documentSetsBuilder.tags.str1.attr.op"
value="equal"/>
<dspel:input type="hidden"
bean="${formHandlerPath}.documentSetsBuilder.tags.str1.attr.case"
value="false"/>
Manufacturer:
<dspel:select multiple="false"
bean="${formHandlerPath}.documentSetsBuilder.tags.str1.body"
onclick='changePage(0);'>
<dspel:importbean var="CatalogTools" bean="/atg/commerce/catalog/CatalogTools"/>
<dspel:droplet var="possibleValues" name=
"/atg/dynamo/droplet/PossibleValues">
<dspel:param name="itemDescriptorName" value="manufacturer"/>
<dspel:param name="repository" value="${CatalogTools.catalog}"/>
<dspel:param name="sortProperties" value="+displayName"/>
<dspel:oparam name="output">
<dspel:option value="">-- Select --</dspel:option>
<c:forEach var="manufacturer" items="${possibleValues.values}">
<dspel:oparam name="output">
<dspel:tomap var="manufacturerMap" value="${manufacturer}"/>
<dspel:option value="${manufacturer.repositoryId}">
<c:out value="${manufacturerMap.displayName}"/>
</dspel:option>
</dspel:oparam>
</c:forEach>
</dspel:oparam>
</dspel:droplet>
</dspel:select> (optional)
<!-- submit button -->
<dspel:input type="submit" bean="${formHandlerPath}.search"

39
3 - Search Form Handlers

ATG Commerce Search Guide

name="submit" value="Search" priority="-20"/>


</dspel:form>
</dspel:page>

Handling Results
For most query types, ATG Search returns the query results as an object of class
com.primus.searchstudio.Results. Each form handler has a results property for storing a Results
object, so you can display the query results in a JSP. For example, the following JSP fragment creates a
three-column table that displays the label, path, and score properties of each category in the
Results.suggestedCategories List property:

<dspel:getvalueof bean="${formHandlerPath}.results" var="results"/>


<c:set value="${results}" var="results" scope="request"/>
<table border="1" width="100%">
<tr bgcolor="LIGHTBLUE">
<td>label</td>
<td>path</td>
<td>score</td>
</tr>
<c:if test="${ ! empty results.suggestedCategories }">
<c:forEach items="${results.suggestedCategories}" var="category">
<tr>
<td>
<c:out value="${category.label}"/>&nbsp;
</td>
<td>
<c:out value="${category.path}"/>&nbsp;
</td>
<td>
<c:out value="${category.score}"/>&nbsp;
</td>
</tr>
</c:forEach>
</c:if>
</table>

Notice that most of the JSP tags in this example are standard JSTL tags, rather than DSP tags, because the
Results object is not a Nucleus component.
For the <browse> query type, ATG Search returns the query results as an array of objects of class
com.primus.searchstudio.CategoryDocument. These objects are stored in the

40
3 - Search Form Handlers

ATG Commerce Search Guide

results.categories.combinedResults.categoryDocuments array of the BrowseFormHandler. To


display results from a <browse> query, you retrieve them from this array. For example, the following JSP
fragment creates a table in which each row displays the properties of a different CategoryDocument
object:

<table border="1" width="100%">


<tr bgcolor="LIGHTBLUE">
<td>timestamp</td>
<td>paTimestamp</td>
<td>popularity</td>
<td>vicDocTypeAsString</td>
<td>title</td>
<td>fullTitle</td>
<td>isTruncated</td>
<td>FAQ</td>
<td>responseId</td>
<td>normalizedResponse</td>
<td>properties</td>
</tr>
<c:if test="${ ! empty results.categories }">
<c:forEach items="${results.categories.combinedResults.categoryDocuments}"
var="document">
<tr>
<td>
<c:out value="${document.timestamp}"/> &nbsp;
</td>
<td>
<c:out value="${document.paTimestampString}"/> &nbsp;
</td>
<td>
<c:out value="${document.popularity}"/> &nbsp;
</td>
<td>
<c:out value="${document.vicDocTypeAsString}"/> &nbsp;
</td>
<td>
<c:out value="${document.title}"/> &nbsp;
</td>
<td>
<c:out value="${document.fullTitle}"/> &nbsp;
</td>
<td>
<c:out value="${document.isTruncated}"/> &nbsp;
</td>
<td>
<c:out value="${document.faq}"/> &nbsp;
</td>

41
3 - Search Form Handlers

ATG Commerce Search Guide

<td>
<c:out value="${document.responseId}"/> &nbsp;
</td>
<td>
<c:out value="${document.normalizedResponse}"/> &nbsp;
</td>
<td>
<table border="1">
<tr bgcolor="LIGHTBLUE">
<td>key</td>
<td>value</td>
</tr>
<c:forEach items="${document.properties}" var="property">
<tr>
<td>
<c:out value="${property.key}"/>
</td>
<td>
<c:out value="${property.value}"/>
</td>
</tr>
</c:forEach>
</table>
</td>
</tr>
</c:forEach>
</c:if>
</table>

Controlling Paging
For an individual query, ATG Search typically returns results as an array of objects. Each object represents
one item returned by the search.
The number of items returned may be large, so queries can include pageSize and pageNum request
attributes that restrict the size of the returned array. For example, if pageSize=10 and pageNum=1, the
array will contain ten objects, representing the eleventh through twentieth items in the search results.
(Note that pageNum is zero-based, so page 1 is the second page.)
The following JSP fragment creates a text field for entering the value of the pageNum attribute, and a
drop-down for selecting a value for the pageSize attribute:

Page:
<dspel:input type="text" id="pageNum" value="0"
name="pageNum" bean="${formHandlerPath}.requestAttributes.pageNum"/>
Page Size
<dspel:select bean="${formHandlerPath}.requestAttributes.pageSize">

42
3 - Search Form Handlers

ATG Commerce Search Guide

<dspel:option value="1000000">one million</dspel:option>


<c:forEach begin="5" end="35" step="5" var="pageSize">
<dspel:option value="${pageSize}">
<c:out value="${pageSize}"/>
</dspel:option>
</c:forEach>
</dspel:select>

Handling Repository Items


The form handlers described in this chapter can be used for searching any content indexed by ATG
Search. They are not restricted to searching documents created from ATG repository items.
If the documents being searched do represent repository items, each Result object will contain the URL
for the corresponding item. You can use the URL to display the repository item. For example:

URL: <c:out value="${result.url}"/>


<dspel:droplet name="/atg/targeting/RepositoryLookup">
<dsp:param name="url" param="${result.url}"/>
<dsp:oparam name="output">
<dsp:valueof param="element.displayName"/>
</dsp:oparam>
</dspel:droplet>

Note, however, these URLs will not be recognized unless the repository is registered. To register a
repository, add it to the list of repositories in the initialRepositories property of the
/atg/registry/ContentRepositories component.

Using Collection Filters


For most query types, the results property of the form handler is set to the Results object returned by
ATG Search. Typically, you do not need to modify the Results object in the ATG platform, because ATG
Search includes many configuration options for customizing the search results on the server side.
In some cases, however, you may want to manipulate or filter the data in some way on the client (ATG
platform) side. To enable you to do this, each form handler has a resultsFetcher property that can
point to a component that implements the
atg.search.query.formhandlers.ResultsFetchingProxy interface. If the form handler is
configured this way, the fetch() method of this component is used to get the Results object. Your
implementation of this method can include logic that modifies the Results object before using it to set
the results property of the form handler.
The ATG platform includes a class,
atg.search.query.formhandlers.CollectionFilterFetchingProxy, that implements the
ResultFetchingProxy interface. This class has a filter property that you can set to a collection filter

component that performs the actual filtering of the results.

43
3 - Search Form Handlers

ATG Commerce Search Guide

In addition, the ATG platform includes an abstract class for filtering results returned by ATG Search. This
class, atg.search.query.filters.RepositoryItemResultCollectionFilter, serves as a base
class that you can subclass to create your own collection filters.
The following example shows the source code of a sample subclass,
atg.search.query.filters.SampleRepositoryItemCollectionFilter, which evaluates all of the
Result objects stored in the results property of the Results object, and rejects any Result object
that does not refer to a valid repository item. The SampleRepositoryItemCollectionFilter class is

intended mainly as a simple example of how to write a collection filter that operates on an ATG Search
Results object, and is not necessarily functionality that you will find useful in itself.

package atg.search.query.filters;
import
import
import
import
import
import

atg.repository.Repository;
atg.repository.RepositoryException;
atg.repository.RepositoryItem;
atg.service.collections.filter.FilterException;
com.primus.searchstudio.Result;
javax.naming.NamingException;

/**
* A sample RepositoryItemResultCollectionFilter which rejects any
* search Result object which does not refer to a valid repository
* item.
*/
public class SampleRepositoryItemCollectionFilter extends
RepositoryItemResultCollectionFilter
{
public SampleRepositoryItemCollectionFilter() {}
/**
* Filter that rejects any search result that does not refer to a
* repository item
*
* @param pResult a search result object
* @param pRepositoryItem the associated repository item or null if
* the search result object does not refer to a repository item
*/
protected boolean accept( Result pResult, RepositoryItem pUserProfile)
throws FilterException
{
RepositoryItem repositoryItem = null;
try {
// Use the url property of the Result object to retrieve the
// repository item
repositoryItem = getRepositoryItem( pResult );

44
3 - Search Form Handlers

ATG Commerce Search Guide

}
catch ( NamingException ne ) {
// Don't care
}
if ( isLoggingDebug() )
logDebug( "repositoryItem = " + repositoryItem );
return repositoryItem != null;
}
}

For more information about collection filters, see the ATG Personalization Programming Guide.

Refining Search Results


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"

45
3 - Search Form Handlers

ATG Commerce Search Guide

<!-<!--

to return
min:
to return
inc:

-->
for ranges, minimum size of a property value "bucket"
-->
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.

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');

46
3 - Search Form Handlers

ATG Commerce Search Guide

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"

47
3 - Search Form Handlers

ATG Commerce Search Guide

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"

48
3 - Search Form Handlers

ATG Commerce Search Guide

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>&nbsp;
(<c:out value="${count}"/>)
</c:forEach>
</div>
</div>
</c:forEach>
</c:if>
</dspel:page>

JMS Event Handling


Note: The message classes described in this section have largely been superseded by the messages fired
by ATG Search Routing. The Routing messages include information used in ATG Search reports, whereas
these messages do not. For information about the Routing messages, see the ATG Search Installation and
Configuration Guide.
Each of the search form handlers has a searchMessageSource property that specifies a component of
class atg.search.query.messages.SearchMessageSource. This component is a Patch Bay message
source that fires JMS messages when query results are received from ATG Search. The form handler uses
the data in the Results object to construct a message object, which is sent off by the
SearchMessageSource.

49
3 - Search Form Handlers

ATG Commerce Search Guide

Each form handler uses a different search message class. The message classes are all subclasses of
atg.search.query.messages.SearchMessage, which has several properties that are common to all
query types. Each subclass has additional properties that are specific to the corresponding query type.
The following tables summarize the properties of the SearchMessage class, plus the properties added by
the subclasses.

SearchMessage

Property

Description

JMSType

The JMS type (supplied by the message subclasses)

optionSetName

The option set used for the search; empty for the default
option set

resultCount

The number of results returned from the search

results

The results object returned from the search

siteName

The search site name

userProfile

The profile of the user executing the query

version

The request version

BrowseMessage

Property

Description

queryText

Text submitted in the body of the <input>

CategorizeMessage

Property

Description

queryText

Text submitted in the body of the <input>

queryMode

One of the following: text | question | document | xhtml

QueryMessage

50
3 - Search Form Handlers

ATG Commerce Search Guide

Property

Description

queryText

The requests queryText and concatenated prior input

pageNumber

The page number requested

queryMode

One of the following: nlp | boolean | and | keyword | matchall

SimilarDocsMessage

Property

Description

queryText

The requests queryText and concatenated prior input

queryMode

One of the following: text | question | document | xhtml

StructuredQueryMessage

Property

Description

queryText

A concatenation of all <statement> bodies that have an op


attribute that is not negative

excludeQueryText

A concatenation of all <statement> bodies that have an op


attribute that is negative

pageNumber

The page number requested

ViewInContextMessage

Property

Description

docContextID

Text submitted in the body of the <docContextID>

input

Text submitted in the body of the <input>

property

Text submitted in the body of the <property>

return

Text submitted as the value of the returnType request


attribute

url

Text submitted in the body of the <url>

value

Text submitted in the body of the <value>

51
3 - Search Form Handlers

ATG Commerce Search Guide

Patch Bay Configuration

The DAF.Search.Query module includes a dynamoMessagingSystem.xml (Patch Bay configuration) file


that declares the /atg/search/query/formhandlers/SearchMessageSource component as a
message source. The configuration file also creates a destination for these messages,
localdms:/local/SearchTopic/SearchEvents, and configures the ScenarioManager to listen for
search events at this destination. This means you do not need to perform any additional Patch Bay
configuration if you want to use search events to trigger scenario actions.
If you want other message sinks to subscribe to the SearchEvents topic, you can add your own
dynamoMessagingSystem.xml file to your CONFIGPATH. For more information about configuring Patch
Bay, see the ATG Programming Guide.

52
3 - Search Form Handlers

ATG Commerce Search Guide

4 Dynamic Search and Navigation

The Dynamic Search and Navigation feature enables ATG Commerce sites to provide a navigational
structure that is not strictly based on the catalog hierarchy. Dynamic navigation is based on facets, which
are like virtual categories that are populated by the results of search queries.
This chapter describes how to implement Dynamic Search and Navigation on an ATG Commerce site. It
includes the following sections:
Overview of Facets
Indexing the Catalog Repository
Generating the Refinement Configuration Files
Building Pages that Include Facets
Configuring the Dynamic Navigation Servlet Beans
CommerceFacetTrailDroplet
FacetSearchDroplet

Overview of Facets
A facet is a search refinement element that corresponds to a property of a commerce item type. The
property is referred to as a faceting property. The values of this property are broken down into selections
that can be either ranges or specific values. For example, you might define a price facet whose faceting
property is the salePrice property of a products SKUs. (Facets are always used to group products, but
the faceting property can be a property of a related commerce item type, such as the products parent
categories or child SKUs.) The selection ranges, which can either be determined dynamically or specified
explicitly when you create the facet in ATG Merchandising, might be $100 to $200, $200 to $500, $500 to
$1000, etc. Or you might define a manufacturer facet with selection values of Acme, Cogswell, and
Spacely.
The selection values are displayed on site pages as hyperlinks. When a user clicks one of these links, a
query is issued to ATG Search, using the selection range or value as a refinement criterion. For example, if
the customer clicks the $100 to $200 link, the query issued would be something like return all products
whose sale price is between $100 and $200. The results of this query are then displayed on the page.
There are three main aspects of ATGs dynamic navigation functionality:

53
4 - Dynamic Search and Navigation

ATG Commerce Search Guide

1.

Defining the facets. You specify facets and the logic for determining the selections in
ATG Merchandising as part of creating your product catalog. Each facet corresponds to
a property of a commerce item, and can be associated with one or more categories or
custom catalogs. Each facet is stored in the RefinementRepository as a separate
refineElement repository item. When you deploy your catalog to your production
site, the RefinementRepository is deployed as well.

2.

Generating the refinement configuration (refineConfig.xml) files. These are the


files used in ATG Search to specify the refinement criteria that the facets represent. The
ATG platform generates the refinement configuration files when the XHTML
documents representing catalog repository items are submitted to ATG Search. Before
the documents are submitted, a process is initiated that steps through the catalog
hierarchy and, based on the associated refinement elements, generates the complete
set of refineConfig.xml files required, and submits these files to ATG Search.

3.

Displaying the selections in pages. This is enabled by creating pages containing servlet
beans that display the facet selections as hyperlinks. Based on the selections the
customer chooses, queries are issued to ATG Search and the results are displayed on
the page. The results include only those items whose faceting property value is the
selected value or falls within the selected range.

The first aspect, creating the facets, is discussed in the ATG Merchandising User Guide. The other two
aspects are described in this chapter.

Indexing the Catalog Repository


Once you have performed all of the configuration necessary to index your product catalog (as described
in the Repository Indexing chapter), created your facets in ATG Merchandising, and deployed your catalog
and refinement data to your target site, you should initiate a bulk loading operation. When you do this,
the ATG platform transforms the catalog data into XHTML files and submits these files to ATG Search,
which builds a complete index. As part of this process, the ATG platform also uses the refineElement
items (which define the facets created in ATG Merchandising) in the refinement repository to generate
the refinement configuration files used for dynamic navigation.
If you make any changes to your catalog, including any changes to your facets, you need to redeploy your
catalog repository. When you do this, the refinement repository is redeployed as well. To make sure the
catalog is reindexed completely and the refinement configuration files are regenerated, you should run a
bulk load after each deployment. You can do this manually, or you could configure a message sink in
Patch Bay to listen for deployment events and trigger bulk loading in response.
For more information about indexing and loading catalog data, see the Repository Indexing chapter.

Generating the Refinement Configuration Files


A key aspect of the dynamic navigation feature is the use of refinement configuration files. These are the
XML files that specify to ATG Search how to divide search results into subsets based on the values of a

54
4 - Dynamic Search and Navigation

ATG Commerce Search Guide

faceting property. These files are automatically generated and submitted to ATG Search whenever bulk
loading or incremental loading is initiated. When the dynamic navigation components issue queries to
ATG Search, they automatically determine which refinement configuration file should be used and specify
it in the query.
Depending on the structure of your product catalog and the number of facets youve specified in ATG
Merchandising, the number of refinement configuration files generated can vary greatly. If you are using a
standard catalog and have created a small number of facets, only a few refinement configuration files
may be necessary. If you are using custom catalogs and have created many facets, hundreds or even
thousands of refinement configuration files may be required. Therefore, the generation of these files is
handled through an automated process that inspects the product catalog and the refineElement
repository items, determines the set of refinement configuration files needed, generates those files, and
submits them to ATG Search.
In addition to the properties described in Configuring Bulk Loading, the IndexingOutputConfig class
has a property called indexingSynchronizations, which takes as its value an array of Nucleus
components that implement the atg.repository.search.indexing.IndexingSynchronization
interface. This interface includes afterSessionStart and beforeSessionEnd methods for invoking
additional processes immediately after a DocumentSubmitter session begins or immediately before a
session ends.
The indexingSynchronizations property of the ProductIndexingOutputConfig component is set
by default to /atg/commerce/search/refinement/RefinementConfigurationSubmitter. This is a
component of class
atg.commerce.search.refinement.admin.RefinementConfigurationSubmitter, which
implements the IndexingSynchronization interface. When bulk or incremental loading is initiated, the
RefineConfigurationSubmitter.afterSessionStart() method invokes the service that generates
the refinement configuration files, and then submits these files to ATG Search.

Building Pages that Include Facets


To create pages that enable dynamic navigation, you use two servlet beans,
atg.commerce.search.refinement.CommerceFacetTrailDroplet and
atg.repository.search.refinement.FacetSearchDroplet. You use these servlet beans together
to render facets and facet trails on pages, and, based on the selection ranges or values chosen by
customers, to issue queries to ATG Search. You can then use other servlet beans to render the results
returned by the queries.

Using the CommerceFacetTrailDroplet


A facet trail is similar to a navigational breadcrumb trail, where each entry consists of a facet and a
selection value or range for that facet. For example, a facet trail might appear on the page like this:
Manufacturer:Cogswell > Price:$300-$500 > Voltage:12-24
The CommerceFacetTrailDroplet takes as input a String representation of the current facet trail plus
instructions for modifying the facet trail based on selections chosen by the customer. (Typically these
inputs are taken from the HTTP request query parameters.) From these inputs, it constructs and outputs a

55
4 - Dynamic Search and Navigation

ATG Commerce Search Guide

new FacetTrail object. You can use standard servlet beans such as ForEach and Switch to read the
data from the FacetTrail object and render the facet trail elements on the page.
For example, suppose a site visitor navigates by first selecting the Televisions category, and then selecting
the LCD Televisions subcategory. (This assumes that Category is defined as a facet; see the ATG
Merchandising User Guide.) Next, she chooses the $1000 to $2000 selection range for the price facet, and
Acme as the selection value for the manufacturer facet. The facet trail String might now look something
like this:
1:cat444323:1:cat333222:2:1000-2000:32:Acme

In this example, cat444323 is the repository ID of the Televisions category, and cat333222 is the
repository ID of the LCD Televisions category. The example also assumes the following facets have been
defined in ATG Merchandising:
1 = category
2 = price
32 = manufacturer

The number identifying the facet is the repository ID of the corresponding refinementElement in the
refinement repository, which is also used as the ID of the refinementElement XML attribute in the
refinement configuration.
Now suppose the site visitor clicks a link to remove the Televisions facet. This sets the removeFacet
parameter value to 1:cat444323. When a category selection value is removed from the facet trail, all of
that categorys subcategories are also removed, so in this case the LCD Televisions category is removed as
well. (In addition, any category-specific facets and selection values that no longer apply are also removed.
For example, if the Televisions category has a Screen Size facet associated with it, removing the
Televisions facet from the trail also removes the Screen Size facet and selections.)
The new facet trail String is therefore:
2:1000-2000:32:Acme

The displayed results now consist of all products priced between $1000 and $2000 whose manufacturer is
Acme. So if Acme also manufactures stereo systems, the ones in this price range will now be displayed.

Last Range Indicator


If a site visitor chooses the last selection range for a facet, the facet trail must indicate this in some way.
When a subsequent query is issued to ATG Search, this information is used in constructing the
corresponding constraint.
Suppose in the example above the price facet has three selection ranges: $500 to $1000, $2000 to $3000,
and $3000 to $4000. If the site visitor selects the $3000 to $4000 range, the facet trail String would look
like this:
2:3000-4000|LAST:32:Acme

56
4 - Dynamic Search and Navigation

ATG Commerce Search Guide

Note that although |LAST is included in the facet trail String (and therefore may appear in URLs), it is not
part of the label for the selection range, and therefore does not appear on the page itself. Also, you do not
need to code your JSPs in any special way to deal with this selection range. For example, to remove the
$3000 to $4000 selection range, the removeFacet parameter should be set to 2:3000-4000, not
2:3000-4000|LAST.

Using the FacetSearchDroplet


The CommerceFacetSearchDroplet component is an instance of the FacetSearchDroplet class. It
takes the FacetTrail object and various ATG Search query attributes as inputs, and passes these to the
CommerceFacetSearchService. The CommerceFacetSearchService constructs a search query that
specifies:

constraints created based on the facets and categories in the facet trail

a refinement configuration file, which the CommerceFacetSearchService


determines based on the entries in the facet trail

the search refinement query attributes from the CommerceFacetSearchDroplet

the pagination query attributes from the CommerceFacetSearchDroplet

The CommerceFacetSearchService passes the query to the ESSearchService, which sends the query
to ATG Search and receives back a Search Results object. The CommerceFacetSearchService converts
this object to a FacetSearchResponse object, which the CommerceFacetSearchDroplet outputs.
The page developer can then use servlet beans such as ForEach to iterate through this object and display
the resulting facets and selections and products returned. The selection ranges or values can be displayed
as hyperlinks which, when clicked, pass the new facet trail String and modification instructions as query
parameters to the linked page.

Incorporating Search Results


If your site includes a search form created with the
atg.search.query.formhandlers.QueryFormHandler class, you can constrain the set of items
accessed through facet selections to ones that also satisfy the search query. For example, suppose a site
visitor at a clothing store begins by searching for belt, and then chooses the brown selection value for
the color facet. The site would now display only brown belts, not all brown items in the store.

To enable this behavior in your pages, dynamic navigation allows you to use a special SRCH facet whose
selection value is the search term entered by the site visitor. In this example, the facet trail String would
look something like this:
SRCH:belt:12:cat356782

Constructing the Facet Trail String


When a site visitor submits a query through the QueryFormHandler, the search text is stored in the
question property of the form handler. Typically you will want to clear any existing facet trail (so the
search is not constrained by current facet selections), and then create a new facet trail that starts with the
SRCH facet (so that subsequent facet selections are constrained by the search results).

57
4 - Dynamic Search and Navigation

ATG Commerce Search Guide

The following example illustrates this approach. When the visitor submits a query, the removeAllFacets
query parameter is set to true, and the addFacet query parameter is set to SRCH: plus the search text
(e.g., SRCH:belt). These query parameters can then be used as inputs to the
CommerceFacetTrailDroplet servlet bean, to clear the facet trail and create a new facet trail that starts
with the SRCH facet. For example:
<dsp:getvalueof var="searchTerm"
bean="/atg/commerce/search/ProductCatalogQueryFormHandler.question"/>
<dsp:droplet name="/atg/dynamo/droplet/Redirect">
<dsp:param name="url" value=
"../facetPage.jsp?removeAllFacets=true&addFacet=SRCH:${searchTerm}"/>
</dsp:droplet>

Specifying the Refinement Configuration


When a search query is issued through the CommerceFacetSearchDroplet servlet bean, it invokes the
CommerceFacetSearchService, which determines the refinement configuration to use and specifies it
in the query. The QueryFormHandler, however, does not invoke the CommerceFacetSearchService,
so another mechanism for determining the search configuration is needed for queries issued through the
form handler.
One approach involves having ATG Search determine the refinement configuration to use based on the
items that are returned. You can do this by adding the following settings to the requestAttributes
Map:
requestAttributes+=\
refineConfig=$map,\
refineConfigMapProp=ancestorCategories.$repositoryId

Setting the refineConfig attribute to $map instructs ATG Search to determine the refinement
configuration to use by finding a metadata property value common to all of results; the
refineConfigMapProp attribute specifies which metadata property to use. So these settings specify that
ATG Search should use the refinement configuration for the lowest-level ancestor category that is
common to all of the returned items.
The main drawback to this approach is that if there is no ancestor category common to all of the results,
the refinement configuration cannot be determined. In this case, ATG Search does not return any facets.

Rendering the Facets


When a search query is issued through the CommerceFacetSearchDroplet servlet bean, the
CommerceFacetSearchService receives back a Search Results object. It converts this Results object
to a FacetSearchResponse object, which the CommerceFacetSearchDroplet outputs.
When the QueryFormHandler issues a query, however, it does not invoke the
CommerceFacetSearchService, so the form handler handles this conversion itself, and stores the
FacetSearchResponse object in its facetSearchResponse property. The page developer can use
servlet beans such as ForEach to iterate through this object and display the resulting facets and
selections, just as when the object is returned by CommerceFacetSearchDroplet. For example:

58
4 - Dynamic Search and Navigation

ATG Commerce Search Guide

<c:set var="formHandlerPath"
value="/atg/commerce/search/ProductCatalogQueryFormHandler"/>
<dsp:droplet name="ForEach">
<dsp:param name="array"
param="${formHandlerPath}.facetSearchResponse.availableFacets"/>
<dsp:oparam name="output">
. . .

For a more complete example of rendering facets, see FacetSearchDroplet.

Configuring the Dynamic Navigation Servlet Beans


The dynamic navigation application modules include component instances of the dynamic navigation
servlet beans:

/atg/commerce/search/refinement/CommerceFacetTrailDroplet, which is of
class atg.commerce.search.refinement.CommerceFacetTrailDroplet.

/atg/commerce/search/refinement/CommerceFacetSearchDroplet, which is of
class atg.commerce.search.refinement.FacetSearchDroplet.

The CommerceFacetTrailDroplet and CommerceFacetSearchDroplet components are


preconfigured with default settings. In some cases, you may want to change these settings or configure
additional instances of these servlet beans.

CommerceFacetTrailDroplet Configuration
The following table describes the properties of the CommerceFacetTrailDroplet component and their
default settings. Note that each property whose name ends with ParameterName specifies the name of
the query parameter that supplies the value to use for the corresponding input parameter if the input
parameter is not supplied. For more information about these input parameters, see
CommerceFacetTrailDroplet.

Property

Description

facetManager

Specifies the component used to retrieve items from the


refinement repository. Default:
/atg/commerce/search/refinement/CommerceFacetManager

facetTrailSeparator

The character used as a separator between the facets and the


faceting property values in the facet trail. Default: the colon
character (:)

59
4 - Dynamic Search and Navigation

ATG Commerce Search Guide

lastRangeValueIndicator

A String appended to a selection range in the facet trail if the


range is the last one for a particular facet. Default: LAST

valueIndicatorSeparator

Separator placed between a selection range and the


lastRangeValueIndicator String if the range is the last one for
a particular facet. Default: the vertical bar character (|)

categoryRefineConfigPropertyName

The name of the property of the category repository item that


contains a reference to the refinement configuration for the
category. Default: refineConfig

trailParameterName

The name of the query parameter that specifies the value to use
for the trail input parameter, if the input parameter is not
supplied. Default: trail

addFacetParameterName

The name of the query parameter that specifies the value to use
for the addFacet input parameter, if the input parameter is not
supplied. Default: addFacet

removeFacetParameterName

The name of the query parameter that specifies the value to use
for the removeFacet input parameter, if the input parameter is
not supplied. Default: removeFacet

removeAllFacetsParameterName

The name of the query parameter that specifies the value to use
for the removeAllFacets input parameter, if the input parameter
is not supplied. Default: removeAllFacets

removeFacetTypeParameterName

The name of the query parameter that specifies the value to use
for the removeFacetType input parameter, if the input parameter
is not supplied. Default: removeFacetType

CommerceFacetSearchDroplet Configuration
The following table describes the properties of the CommerceFacetSearchDroplet component and
their defaults. Note that each property whose name begins with default specifies the value to use for
the corresponding input parameter if the input parameter is not supplied. For more information about
these input parameters, see FacetSearchDroplet.

Property

Description

facetManager

Specifies the component used to retrieve items from the refinement


repository. Default:
/atg/commerce/search/refinement/CommerceFacetManager

facetSearchService

Specifies the component used to issue queries to ATG Search and


receive results. Default: See Note below.

defaultPageNum

Specifies the value to use for the pageNum input parameter, if the
input parameter is not supplied. Default: 0

60
4 - Dynamic Search and Navigation

ATG Commerce Search Guide

defaultPageMode

Specifies the value to use for the pageMode input parameter, if the
input parameter is not supplied. Default: group

defaultPageSize

Specifies the value to use for the pageSize input parameter, if the
input parameter is not supplied. Default: 30

defaultRefineMin

Specifies the value to use for the refineMin input parameter, if the
input parameter is not supplied. Default: 1

defaultRefineMax

Specifies the value to use for the refineMax input parameter, if the
input parameter is not supplied. Default: 5

defaultRefineTop

Specifies the value to use for the refineTop input parameter, if it is


not specified in the page. Default: 10

defaultSortMode

Specifies the value to use for the sortMode input parameter, if it is not
specified in the page. Default: relevance

defaultSortOrder

Specifies the value to use for the refineTop input parameter, if it is


not specified in the page. Default: descending

Note: The default value for the facetSearchService property is


/atg/commerce/search/refinement/CommerceFacetSearchService, unless your site is running the
DCS.Search.CustomCatalogs module, in which case the default is
/atg/commerce/search/refinement/custom/CustomCatalogFacetSearchService.

61
4 - Dynamic Search and Navigation

ATG Commerce Search Guide

CommerceFacetTrailDroplet
Class Name

atg.commerce.search.refinement.CommerceFacetTrailDroplet

Component

/atg/commerce/search/refinement/CommerceFacetTrailDroplet

This servlet bean takes as input a String representing a facet trail, plus additional input parameters
specifying modifications to the facet trail. It outputs the modified facet trail as a FacetTrail object,
which can then be rendered on the page or passed to the FacetSearchDroplet.
The input parameters can be set explicitly or they can be set by the pages URL query parameters. For
example, when a customer clicks a link for a selection value, the query parameter corresponding to the
servlet beans addFacet parameter can be set to this selection value. When the new page is displayed,
the chosen value will appear at the end of the facet trail. Similarly, another link could be used to remove a
selection value or range from the facet trail.

Input Parameters
trail
String that represents the current facet trail. This parameters value is typically specified through a query
parameter in the URL for the page. The name of the query parameter that sets the value of this input
parameter is configured through the trailParameterName property.
refineConfig
The refineConfig repository item to use for querying ATG Search. If this value is not specified, the
refinement configuration will be chosen automatically.
addFacet
String that represents an entry (consisting of a facet and an associated selection value or range) to add to
the facet trail. This parameters value is typically specified through a query parameter in the URL for the
page. The name of the query parameter that sets the value of this input parameter is configured through
the addFacetParameterName property.
removeFacet
String that represents an entry to remove from the trail. This parameters value is typically specified
through a query parameter in the URL for the page. The name of the query parameter that sets the value
of this input parameter is configured through the removeFacetParameterName property.
removeAllFacets
If this parameter is set to true, the facet trail is cleared. This parameters value is typically specified
through a query parameter in the URL for the page. The name of the query parameter that sets the value
of this input parameter is configured through the removeAllFacetsParameterName property.
removeFacetType
The item ID of a refinement element repository item (i.e., a facet); specifies that all facet values or ranges

62
4 - Dynamic Search and Navigation

ATG Commerce Search Guide

for this facet should be removed from the facet trail. This parameters value is typically specified through a
query parameter in the URL for the page. The name of the query parameter that sets the value of this
input parameter is configured through the removeFacetTypeParameterName property.

Output Parameters
facetTrail
The FacetTrail object generated from the input or query parameters.
errorMessage
The message generated if an error occurs when creating the FacetTrail object.

Open Parameters
output
This open parameter is rendered if no errors occur when creating the FacetTrail object.
error
This open parameter is rendered if any errors occur when creating the FacetTrail object.

Example
This example shows a page that renders the current facet trail, and provides links for removing each
individual entry in the trail.
Note: This is a simplified example for illustrative purposes only. For a more realistic example, there are
several sample JSPs in <ATG2007.1>/DAF/Search/Query/SearchTest/web-apps/search.war that
use the faceted navigation servlet beans. You may find these pages helpful as starting points for writing
your own JSPs.

<%@ taglib uri="dsp" prefix="dsp" %>


<dsp:page>
<%-- Import components used in this page --%>
<dsp:importbean
bean="/atg/commerce/search/refinement/CommerceFacetTrailDroplet"/>
<dsp:importbean bean="/atg/dynamo/droplet/ForEach"/>
<dsp:importbean bean="/atg/dynamo/droplet/Switch"/>
<dsp:importbean bean="/atg/dynamo/droplet/IsNull"/>
<dsp:importbean bean="/atg/dynamo/droplet/IsEmpty"/>
<%-- Convert the trail parameter to a bean --%>
<dsp:droplet name="CommerceFacetTrailDroplet">
<dsp:setvalue param="facetValues" paramvalue="facetTrail.facetValues"/>
<dsp:oparam name="error">
Error reported by Facet Trail droplet:</b>
<dsp:valueof param="errorMessage"/>

63
4 - Dynamic Search and Navigation

ATG Commerce Search Guide

</dsp:oparam>

<%-- Render the facet trail on the page --%>


<dsp:oparam name="output">
<dsp:droplet name="ForEach">
<dsp:param name="array" param="facetValues"/>
<dsp:setvalue param="currentFacetValue" paramvalue="element"/>
<dsp:oparam name="empty">
No facet values selected<br/>
</dsp:oparam>
<dsp:oparam name="outputStart">
Current trail:<br/>
</dsp:oparam>
<dsp:oparam name="output">
<%-- Put a separator between each selection value --%>
<dsp:droplet name="Switch">
<dsp:param name="value" param="count"/>
<dsp:oparam name="1"/>
<dsp:oparam name="default">
&gt;
</dsp:oparam>
</dsp:droplet>
<%-- Output the facet name and selection value separated by a colon --%>
<dsp:droplet name="IsNull">
<dspel:param name="value" param="currentFacetValue.facet.label"/>
<dsp:oparam name="true">
<dsp:valueof param="currentFacetValue.facet.id"/>:
</dsp:oparam>
<dsp:oparam name="false">
<dsp:valueof param="currentFacetValue.facet.label"/>:
</dsp:oparam>
</dsp:droplet>
<dsp:valueof param="currentFacetValue.value"/>
<%-Add a remove option. Clicking this will take user to a page
whose URL is specified in a variable named 'removeFacetUrl'.
--%>
<dsp:getvalueof id="removeFacetUrl" idtype="String"
bean="/OriginatingRequest.requestURI">
<dsp:a href="<%=removeFacetUrl%>">
<dsp:param name="trail" param="facetTrail"/>
<dsp:param name="rem" param="currentFacetValue"/>

64
4 - Dynamic Search and Navigation

ATG Commerce Search Guide

<img src="../images/removeFacet.gif"/>
</dsp:a>
</dsp:getvalueof>
</dsp:oparam> <%-- output oparam --%>
</dsp:droplet> <%-- ForEach --%>
</dsp:oparam> <%-- output oparam --%>
</dsp:droplet> <%-- CommerceFacetTrailDroplet --%>
</dsp:page>

65
4 - Dynamic Search and Navigation

ATG Commerce Search Guide

FacetSearchDroplet
Class Name

atg.repository.search.refinement.FacetSearchDroplet

Component

/atg/commerce/search/refinement/CommerceFacetSearchDroplet

This servlet bean takes as input a FacetTrail object (typically as the output from the
CommerceFacetTrailDroplet) and several search query attributes, constructs a search query based on
these inputs, and submits the query to ATG Search. FacetSearchDroplet outputs the results returned
by ATG Search as a FacetSearchResponse object, which can then be rendered on the page.
For more information about the search query attributes set by this servlet beans input parameters, see
the ATG Search Query Reference Guide.

Input Parameters
facetTrail
The FacetTrail object returned by the CommerceFacetTrailDroplet servlet bean. Facet information
in this object is used to specify constraints in the query issued to ATG Search.
pageNum
Sets the value of the pageNum attribute in the search query. This attribute specifies the page of results to
retrieve from ATG Search. (0 is the first page, 1 is the second page, and so on.) If the pageNum parameter is
not specified in the page, its value is taken from the components defaultPageNum property. The default
value is 0, which means the first page is returned.
pageMode
Sets the value of the pageMode attribute in the search query. This attribute specifies what constitutes an
element on the page. This has two possible values:

response each individual item counts towards page size

group each unique result group counts towards page size

If the pageMode parameter is not specified in the page, its value is taken from the components
defaultPageMode property. The default value is group, so that an individual group is not split across
pages. For example, if pageSize is 10 and pageMode is group, and the result groups have a maximum
size of 3, then each page will include up to 30 responses.
pageSize
Sets the value of the pageSize attribute in the search query. This attribute specifies the number of results
to return per page (either individual items or groups, depending on the value of the pageMode
parameter). If the pageSize parameter is not specified in the page, its value is taken from the
components defaultPageSize property. The default value is 30.

66
4 - Dynamic Search and Navigation

ATG Commerce Search Guide

refineMin
Sets the value of the refineMin attribute in the search query. This attribute specifies the minimum
number of items that a selection value or range must have in order to be returned by ATG Search. If the
refineMin parameter is not specified in the page, its value is taken from the components
defaultRefineMin property. The default value is 1, which means that a selection range or value is
returned only if it includes at least one item.
refineMax
Sets the value of the refineMax attribute in the search query. This attribute specifies the maximum
number of facets (refinement elements) to be returned by ATG Search. If the refineMax parameter is not
specified in the page, its value is taken from the components defaultRefineMax property. The default
value is 5, which means that at most five facets will be returned, even if more are available.
refineTop
Sets the value of the refineTop attribute in the search query. This attribute specifies the maximum
number of selection values or ranges to be returned for each facet. If the refineTop parameter is not
specified in the page, its value is taken from the components defaultRefineTop property. The default
value is 10, which means that at most ten selection values will be returned for each facet, even if more are
available.
sortMode
Sets the value of the docSort attribute in the search query. This attribute specifies the criterion for
sorting the result groups returned by ATG Search. If the sortMode parameter is not specified in the page,
its value is taken from the components defaultSortMode property. The default value is relevance,
which means the result groups are sorted by their relevance scores.
sortOrder
Sets the value of the docSortOrder attribute in the search query. This attribute specifies the direction of
the sort. If the sortOrder parameter is not specified in the page, its value is taken from the components
defaultSortOrder property. The default value is descending.
sortProperty
Sets the value of the docSortProp attribute in the search query. This attribute specifies the property to
sort on if the value of the docSort attribute is numprop or strprop.
sortPropertyDefault
Sets the value of the docSortPropDefault attribute in the search query. This attribute provides a default
value for the property specified by the docSortProp attribute.

Output Parameters
facetSearchResponse
The FacetSearchResponse object generated from the results returned by ATG Search.
errorMessage
The error message generated if an error occurs when creating the FacetSearchResponse object.

Open Parameters
output
This open parameter is rendered if no errors occur when creating the FacetSearchResponse object.

67
4 - Dynamic Search and Navigation

ATG Commerce Search Guide

error
This open parameter is rendered if any errors occur when creating the FacetSearchResponse object.

Example
This example shows a page that uses the CommerceFacetSearchDroplet to display selection values and
ranges as hyperlinks, issue search queries when these links are clicked, and display the results returned by
these queries.
Note: This is a simplified example for illustrative purposes only. For a more realistic example, there are
several sample JSPs in <ATG2007.1>/DAF/Search/Query/SearchTest/web-apps/search.war that
use the faceted navigation servlet beans. You may find these pages helpful as starting points for writing
your own JSPs.

<%@ taglib uri="dsp" prefix="dsp" %>


<dsp:page>
<%-- Import components used in this page --%>
<dsp:importbean
bean="/atg/commerce/search/refinement/CommerceFacetTrailDroplet"/>
<dsp:importbean
bean="/atg/commerce/search/refinement/CommerceFacetSearchDroplet"/>
<dsp:importbean bean="/atg/dynamo/droplet/ForEach"/>
<dsp:importbean bean="/atg/dynamo/droplet/Switch"/>
<dsp:importbean bean="/atg/dynamo/droplet/IsNull"/>
<dsp:importbean bean="/atg/dynamo/droplet/IsEmpty"/>
<dsp:importbean bean="/atg/userprofiling/Profile"/>
<%-- Output the current catalog --%>
<dsp:valueof bean="Profile.catalog"/>
<%-- First use the CommerceFacetTrailDroplet to get the facet trail bean.
This servlet bean is invoked here without any input parameters, so it
will construct the facet trail from the request's query parameters. --%>
<dsp:droplet name="CommerceFacetTrailDroplet">
<dsp:oparam name="output">
<%-- Use CommerceFacetSearchDroplet to construct the query and
display the search results. --%>
<dsp:droplet name="CommerceFacetSearchDroplet">
<%-- Pass in the facet trail bean. --%>
<dsp:param name="facetTrail" param="facetTrail"/>
<%-- Set search query attributes. --%>
<dsp:param name="pageNum" value="1"/>
<dsp:param name="pageMode" value="group"/>
<dsp:param name="pageSize" value="10"/>

68
4 - Dynamic Search and Navigation

ATG Commerce Search Guide

<dsp:param
<dsp:param
<dsp:param
<dsp:param
<dsp:param

name="refineMin"
name="refineMax"
name="refineTop"
name="sortMode"
name="sortOrder"

value="0"/>
value="5"/>
value="5"/>
value="date"/>
value="descending"/>

<dsp:oparam name="error">
Error reported by search droplet: <dsp:valueof
param="errorMessage"/><br/>
</dsp:oparam>
<dsp:oparam name="empty">
No results for this search<br/>
</dsp:oparam>
<dsp:oparam name="output">
Page <dsp:valueof param="facetSearchResponse.pageNum"/> out
of <dsp:valueof param="facetSearchResponse.totalPages"/> pages.<br/>
<%-- Output the available facets --%>
<h4>Available Refinements</h4>
<dsp:droplet name="ForEach">
<dsp:param name="array" param="facetSearchResponse.availableFacets"/>
<dsp:setvalue param="currentFacetHolder" paramvalue="element"/>
<dsp:oparam name="empty">
No refinements available.<br/>
</dsp:oparam>
<dsp:oparam name="outputStart">
Refine your search:<br/>
</dsp:oparam>
<dsp:oparam name="output">
<%-- Put a blank line between facets --%>
<dsp:droplet name="Switch">
<dsp:param name="value" param="count"/>
<dsp:oparam name="1"/>
<dsp:oparam name="default">
<br/><br/>
</dsp:oparam>
</dsp:droplet>
<%-- Output the facet name in bold --%>
<b><dsp:valueof param="currentFacetHolder.facet.label"/></b><br/>
<%-- Output the selection values or ranges below the facet name --%>
<dsp:droplet name="ForEach">

69
4 - Dynamic Search and Navigation

ATG Commerce Search Guide

<dsp:param name="array" param="currentFacetHolder.facetValueNodes"/>


<%-- Get the current selection value --%>
<dsp:setvalue param="currentFacetValueNode" paramvalue="element"/>
<dsp:oparam name="empty">
No values for this refinement.
</dsp:oparam>
<%-- Indent the child values --%>
<dsp:oparam name="outputStart">
<blockquote>
</dsp:oparam>
<dsp:oparam name="outputEnd">
</blockquote>
</dsp:oparam>
<dsp:oparam name="output">
<%-- Display selection value as a hyperlink --%>
<dsp:getvalueof id="facetValueUrl" idtype="String"
bean="/OriginatingRequest.requestURI">
<dsp:a href="<%=facetValueUrl%>">
<dsp:param name="trail" param="facetTrail"/>
<dsp:param name="addFacet"
param="currentFacetValueNode.facetValue"/>
<dsp:valueof param="currentFacetValueNode.facetValue.value"/>
</dsp:a>
</dsp:getvalueof>
<%-- Show number of matching items --%>
(<dsp:valueof
param="currentFacetValueNode.facetValue.matchingDocsCount"/>)
<%-- Insert line break --%>
<br/>
</dsp:oparam> <%-- output oparam --%>
</dsp:droplet> <%-- ForEach currentFacetHolder.facetNodeValues --%>
</dsp:oparam> <%-- output oparam --%>
</dsp:droplet> <%-- ForEach facetSearchResponse.availableFacets --%>
<%-- Output details of matching products --%>
<h4>Matching items</h4>
<dsp:droplet name="ForEach">
<dsp:param name="array" param="facetSearchResponse.matchingItems"/>
<dsp:setvalue param="currentResponse" paramvalue="element"/>

70
4 - Dynamic Search and Navigation

ATG Commerce Search Guide

<dsp:oparam name="empty">
No matching items
</dsp:oparam>
<dsp:oparam name="output">
Response[<dsp:valueof param="index"/>] is <dsp:valueof
param="currentResponse"/><br/>
</dsp:oparam>
</dsp:droplet>
</dsp:oparam> <%-- output oparam --%>
</dsp:droplet> <%-- CommerceFacetSearchDroplet --%>
</dsp:oparam> <%-- output oparam --%>
</dsp:droplet> <%-- CommerceFacetTrailDroplet --%>
</dsp:page>

71
4 - Dynamic Search and Navigation

ATG Commerce Search Guide

72
4 - Dynamic Search and Navigation

ATG Commerce Search Guide

5 Search Merchandising

The Search Merchandising feature enables Commerce sites to customize search results based on site
initiatives and customer purchasing patterns. In ATG Merchandising, a merchandiser creates search
configurations, which are sets of rules that determine the order of search results and which items are
excluded from the results. These search configurations are stored in the RefinementRepository (along
with the refinement configurations used for Dynamic Navigation), and are submitted to ATG Search when
the product catalog is indexed. When a site visitor issues a search query, ATG platform components
determine which search configuration to use, and include this information with the query. When ATG
Search returns the results from the query, it applies the rules in the search configuration to those results.
This chapter describes the client-side services involved in Search Merchandising. It includes the following
sections:
Configuring the Customization Adapters
Generating the Search Configuration Files
Determining the Search Configuration to Use
Handling Redirects
Collecting Updated Inventory Data

Configuring the Customization Adapters


Search Merchandising uses customization adapters to submit search configuration files and inventory
data to ATG Search. Each customization adapter is a Nucleus component that is invoked by ATG Search
Administration when it runs an indexing job. When you set up a project in ATG Search Administration for
indexing your Commerce catalog, these customization adapters are automatically associated with the
project.
To make the Search Merchandising customization adapters available to ATG Search Administration, you
must run a script that registers them with the ATG Search SearchAdminRepository. On Windows, the
script is:
<ATG2007.1dir>\DCS\Search\Index\install\importDCSCustomizationAdapters.bat

On UNIX, the script is:


<ATG2007.1dir>/DCS/Search/Index/install/importDCSCustomizationAdapters.sh

73
5 - Search Merchandising

ATG Commerce Search Guide

The script registers two customization adapters with ATG Search:

/atg/commerce/search/config/CatalogRankConfigAdapter This component

manages the process of generating the search configuration files and submitting them
to ATG Search.

/atg/commerce/search/config/SearchUpdateAdapter This component

manages the process of collecting updated inventory information and submitting it to


ATG Search.
For more information about ATG Search Administration and customization data, see the ATG Search
Administration Guide.

Configuring the Adapter Components


The customization adapters need to be configured differently on the ATG Search Administration
environment, depending on whether the Commerce site application is running as part of the same
environment or in a separate environment. Typically, on a production site, the Commerce site application
runs in a separate environment from ATG Search Administration, and Commerce and Search
Administration communicate remotely over RMI. However, for development and evaluation purposes,
you may find it convenient to run everything in the same environment (in which case Search
Administration will access the adapters locally).
The CatalogRankConfigAdapter and SearchUpdateAdapter components are actually generic
services that can be configured to point to local customization adapters or to proxies that communicate
remotely with customization adapters on another system.

Configuring the Adapters for Local Access


To configure a customization adapter for local access, set its customizationDataAdapter property to
the Nucleus pathname of the corresponding local adapter. For the CatalogRankConfigAdapter, set this
property to /atg/commerce/search/config/LocalCatalogRankConfigAdapter. For the
SearchUpdateAdapter, set the property to
/atg/commerce/search/config/LocalSearchUpdateAdapter.

Configuring the Adapters for Remote Access


Setting up the adapters for remote access requires configuring separate instances on the Search
Administration environment and the Commerce environment.
On the Commerce environment, configure the CatalogRankConfigAdapter and
SearchUpdateAdapter components to point to their corresponding local adapters, just as you would for
accessing the adapters locally.
On the Search Administration environment, you set up the proxies that communicate with the
customization adapters on the Commerce environment:

Configure the CatalogRankConfigAdapter and SearchUpdateAdapter


components to point to their corresponding remote proxies. For the
CatalogRankConfigAdapter, set the customizationDataAdapter property to
/atg/commerce/search/config/RemoteCatalogRankConfigAdapter. For the

74
5 - Search Merchandising

ATG Commerce Search Guide

SearchUpdateAdapter, set the customizationDataAdapter property to


/atg/commerce/search/config/RemoteSearchUpdateAdapter.

Configure the RemoteCatalogRankConfigAdapter and


RemoteSearchUpdateAdapter components to communicate with the adapters
running in the Commerce environment. Set the enabled property of these
components to true, and set the remoteHost and remotePort properties to the
machine name and RMI port number of the ATG instance that the Commerce site
application is running on. For example:
enabled=true
remoteHost=mymachine.mycompany.com
remotePort=8860

Invoking the Adapters


Each time a catalog indexing job runs, ATG Search Administration invokes the
CatalogRankConfigAdapter and the SearchUpdateAdapter after the indexing itself is complete. This
ensures that ATG Search has up-to-date search configurations and inventory information.
Depending on the needs of your site, you may want to run the customization adapters more frequently
than you re-index the product catalog. This is particularly true if your inventory information changes
rapidly, and your search configurations include rules based on inventory status. For example, for rules that
exclude out-of-stock items, you want to make sure the data that triggers these rules is up to date.
When you set up scheduled indexing jobs for your project in the ATG Search Administration UI, you can
also set up a post-indexing customizations job and schedule it to run more frequently than the indexing
jobs. For more information about creating and scheduling a post-indexing customizations job, see the
ATG Search Administration Guide.

Generating the Search Configuration Files


A key aspect of the Search Merchandising feature is the use of search configuration files. These are the
XML files that represent sets of ATG Search query rules that specify how to sort the search results and to
exclude certain results entirely, based on terms in the search query and values of the properties of the
returned items. For example, a search configuration might specify that less expensive items should be
displayed first, and that if the query contains the word bargain, all items whose price is above $100.00
should be excluded from the results.
The rules that make up the search configurations are created in ATG Merchandising, and stored as
repository items in the RefinementRepository. When the product catalog is deployed from the ATG
Merchandising environment to the target site, the RefinementRepository is deployed as well.
When Search Administration initiates indexing of the product catalog, it also invokes the
/atg/commerce/search/config/CatalogRankConfigAdapter component. This component is a
customization adapter that manages the process of generating the search configuration files and
submitting them to ATG Search.

75
5 - Search Merchandising

ATG Commerce Search Guide

To generate the search configuration files, CatalogRankConfigAdapter invokes the


/atg/search/repository/SearchConfigurationXMLGenerator component (of class
atg.repository.search.indexing.config.SearchConfigurationXMLGenerator). This
component is responsible for transforming the repository items into the XML files that represent rule sets
in ATG Search. SearchConfigurationXMLGenerator calls various other components that parse the
rules in the RefinementRepository and generate XML representations of those rules.

Determining the Search Configuration to Use


When a visitor enters a search term on a site that uses Search Merchandising, the software determines
which search configuration to apply, and includes this information in the query it sends to ATG Search.
The logic used to select the search configuration is based on the tree structure created in ATG
Merchandising. This structure can take into account two dimensions, user segment and locale (referred to
in ATG Merchandising as language).
The dimension tree structure is stored as repository items in the RefinementRepository. When the
product catalog is deployed from the ATG Merchandising environment to the target site, this repository is
deployed as well.
The dimension services that create the tree structure in ATG Merchandising,
/atg/search/config/LanguageDimensionService and
/atg/commerce/search/config/SegmentDimensionService, are also present on the target (search
client) site. When a site visitor submits a query entered in a search form, the form handler invokes the
/atg/commerce/search/config/SearchConfigNameService component, which uses these services
to traverse the decision tree based on the visitors language (locale) and the user segments he or she is a
member of. It proceeds through the tree until it finds the first search configuration that matches these
values. It then add a reference to this search configuration to the query, which is submitted to ATG Search.
ATG Search executes the query, applies the search configuration rules to the results, and returns the
results to the client site. If there is no matching search configuration, then no search configuration rules
are applied to the query.
For example, suppose the dimension tree created in ATG Merchandising looks like this:

In this example, English is the only language defined, and there are only two segments available, Big
Spenders and Californians.
To determine the search configuration to use, the software would proceed like this:

76
5 - Search Merchandising

ATG Commerce Search Guide

Determine the visitors language, as described in Determining the Language.

If the language is English:

 Determine if the visitor is a member of the Big Spenders segment. If so, use the
Segment: Big Spenders search configuration.
 If the visitor is not a member of the Big Spenders segment, determine if the
visitor is a member of the Californians segment. If so, use the Segment:
Californians search configuration.
 If the visitor is not a member of the Californians segment, use the Segment: All
Others search configuration.

If the language is not English:


 Determine if the visitor is a member of the Big Spenders segment. If so, use the
Segment: Big Spenders 2 search configuration.
 If the visitor is not a member of the Big Spenders segment, do not use any
search configuration.

A couple of things to note in this example:

The ordering of the items in the tree is important. If the visitors language is English,
and he or she is a member of both the Big Spenders and the Californians segments,
the Segment: Big Spenders search configuration is selected, because its position in the
tree is above the Segment: Californians search configuration.

In a group of dimension folders or search configurations at the same position in the


hierarchy, the folder or search configuration whose dimension value is All Others is
always the last item in that group of folders or search configurations. In the example
above, the Language: All Others folder comes after Language: English, and the
Segment: All Others search configuration comes after Segment: Big Spenders and
Segment: Californians. ATG Merchandising enforces this ordering to ensure that a
folder or search configuration whose dimension value is All Others is used only if the
visitors value for that dimension doesnt match any other folder or configuration.

Determining the Language


When a merchandiser defines a search configuration in the ATG Merchandising UI, he or she selects a
language from a preconfigured list. Though the term language is used throughout the Merchandising
UI, the values selected actually represent Java locales. So, for example, the list of available languages
might include both British English (representing the locale en_GB) and US English (representing the locale
en_US).
Different sites may use different logic for determining a users locale. The following steps describe one
possible approach:
1.

If the URL in the request includes a query parameter that specifies a locale, use that
locale.

2.

If the locale is not specified in the URL, examine the current profiles locale property.
If this property is set (typically the case only if the user is logged in), use the value of
that property.

77
5 - Search Merchandising

ATG Commerce Search Guide

3.

If the locale property of the profile is not set, examine the HTTP headers of the
request for a locale setting. This is set by the browser based either on a preference
setting in the browser itself, or on a value derived from an operating-system setting.

Configuring the Dimension Services


To set up the ATG Merchandising UI for Search Merchandising, you must configure the
LanguageDimensionService and SegmentDimensionService. For example, you set properties of the
LanguageDimensionService that map locales to the language names used in the ATG Merchandising
UI. Configuring the dimension services is described in the ATG Merchandising User Guide.
When you set up your Commerce site, make sure its instances of these dimension services have the same
configuration as the instances of these services in the ATG Merchandising environment. If you assemble
both applications from the same ATG installation, this happens automatically.

Handling Redirects
A merchandiser can create a rule in ATG Merchandising that specifies a URL to redirect to if the search
query contains certain terms. For example, if a certain product is highly anticipated but has not yet been
released, the merchandiser may want to create a redirection rule specifying that if a site visitor searches
for this product, the site should display a page where the visitor can sign up to be notified when the
product is available. If this redirection rule is executed, the results returned by ATG Search are not
displayed.
The search form handlers have an autoRedirect property that specifies whether the form handler
should check the search results for a redirect URL. If this property is set to true (the default), the form
handler examines the search results for a redirect URL, and if it finds one, displays the page specified by
that URL. If this property is set to false, the form handler ignores any redirect URL and displays the
results returned by ATG Search.

Collecting Updated Inventory Data


Some search configuration rules can take into account inventory information about the products or SKUs
returned by ATG Search. For example, a merchandiser can create rules that exclude items that are out of
stock or discontinued.
In order for ATG Search to apply these rules appropriately, it needs to have up-to-date inventory
information. To supply this information, services on the client side gather the availability status of the
SKUs and products in the catalog, generate XML files with this data, and submit the files to ATG Search.
When Search Administration initiates indexing of the product catalog, it also invokes the
/atg/commerce/search/SearchUpdateAdapter component. This component is a customization
adapter that manages the process of generating the inventory data files and submitting them to ATG
Search.

78
5 - Search Merchandising

ATG Commerce Search Guide

The SearchUpdateAdapter invokes the


/atg/commerce/search/config/CatalogInventoryCollector component. If the assembled

application uses product-based indexing, the class of this component is


atg.commerce.search.config.ProductInventoryCollector. For each product in the catalog, this

class calls the inventory manager to get the availability status for all of the products child SKUs. It then
summarizes those statuses into a single overall status for the product.
It does this by choosing the best status among the products child SKUs. The goodness of the different
status values is configured by the summaryLogicStatuses property of the
ProductInventoryCollector class. This property is a list of the availability statuses in descending order
of goodness. By default, this property is configured like this:
summaryLogicStatuses=\
IN_STOCK,\
BACKORDERABLE,\
PREORDERABLE,\
OUT_OF_STOCK,\
DISCONTINUED

So, for example, if a product has two child SKUs, and one has a status of BACKORDERABLE and the other is
DISCONTINUED, the status of the product would be BACKORDERABLE. Note that if any child SKUs status is
IN_STOCK, the product status is IN_STOCK. If you want to change this logic, you can reorder the list. For
example, if you put OUT_OF_STOCK first, then a product will be considered out of stock if any child SKUs
status is OUT_OF_STOCK.
If the assembled application uses SKU-based indexing (enabled by including the
DCS.Search.Index.SKUIndexing module), the CollectorPropertyService components class is
atg.commerce.search.config.SKUInventoryCollector. This class also calls the inventory manager
to get the availability of each SKU, but doesnt summarize the statuses of a products SKUs into an overall
product status.
For more information about the inventory manager and availability statuses, see the ATG Commerce
Programming Guide.

79
5 - Search Merchandising

ATG Commerce Search Guide

80
5 - Search Merchandising

ATG Commerce Search Guide

Appendix A: Configuring ATG Search

In addition to configuring the Nucleus components described in this manual, Commerce Search requires
you to perform the following configuration in ATG Search Administration:
1.

Create a project and specify the content you want to index.

2.

Set the Document Set Name for the content to Solutions.

3.

Specify the Nucleus pathname for your IndexingOutputConfig component.

4.

For bulk loading, create an automatic indexing rule for this project. The rule should
use the Complete option.

5.

If you are using incremental indexing, create another automatic indexing rule for this
project. This rule should use the Incremental option.

If you are indexing documents in multiple languages, you need to create additional projects for them. To
create a locale-specific project:
1.

Create a text processing option set. On the Basic tab, set the Input Language to the
language of the content.

2.

Create a project, and select this text processing option set for the project.

For more information, see the ATG Search Administration Guide.

81
Appendix A: Configuring ATG Search

ATG Commerce Search Guide

82
Appendix A: Configuring ATG Search

ATG Commerce Search Guide

Appendix B: Using the MapXMLBuilder


Class

If no custom builder is specified for a given XMLBuilder type form handler property, the form handler
will default to using the atg.search.query.formhandlers.MapXMLBuilder class. This class is
designed to allow creation of arbitrarily complex XML.
Note that you can explicitly set an XMLBuilder property to use the MapXMLBuilder class by creating a
Nucleus component of this class and pointing the property to this component. The advantage of doing
this is that it enables you to configure the builder by setting the following properties:
defaultValue
Default XML to output if builder would otherwise generate no tags.
wrappingXML
XML to wrap any generated output. For example, to wrap either the default XML or the
generated XML in an <and> tag, use:
<and>{0}</and>

Examples
The remainder of this appendix describes how to use the MapXMLBuilder class through several
illustrative examples. Note that in the JSP fragments ${FH} is a variable created elsewhere on the page; its
value is the full Nucleus pathname of the form handler.

Simple Tags
The first example generates this relatively simple strprop tag:

<strprop op="equal" name="childSKU.color">


rose
</strprop>

The JSP looks like this:

83
Appendix B: Using the MapXMLBuilder Class

ATG Commerce Search Guide

<-- Create the <strprop> tag -->

<dspel:input type="hidden" bean="${FH}.documentSetsBuilder.tags.myTag.tagname"


value="strprop">
<-- Add the <strprop op="equal"> attribute -->
<dspel:input type="hidden" bean="${FH}.documentSetsBuilder.tags.myTag.attr.op"
value="equal">
<-- Add the <strprop name="childSKU.color"> attribute -->
<dspel:input type="hidden" bean="${FH}.documentSetsBuilder.tags.myTag.attr.name"
value="childSKU.color">
<-- Finally, the <strprop> tag's body -->
<dspel:input type="hidden" bean="${FH}.documentSetsBuilder.tags.myTag.body"
value="rose">

Note that myTag is an arbitrary string identifier for a given tag on the page. This value is not rendered in
the XML output; it merely serves as a way to distinguish between multiple tags at the same level.
The JSP fragment above illustrates how the basic components of any tag are specified on the page:

identifier.tagname

The input tags value attribute specifies the name of the


generated XML tag. There must be exactly one tagname entry.

identifier.attr.attributeName

The input tags value attribute specifies the value of an XML


tag attribute using the format attributeName="value".
There can be at most one attr entry, and zero or more
attr.attributeName entries.

identifier.body

The input tags value attribute specifies the value for the body
of the generated XML tag.

Nested Tags
This example illustrates the generation of two property constraints tags nested within a Boolean <and>
tag:

<and>
<strprop op="equal" name="childSKU.color">
rose
</strprop>
<numprop op="lesseq" name="childSKU.price">
30.00
</numprop>
</and>

84
Appendix B: Using the MapXMLBuilder Class

ATG Commerce Search Guide

The JSP looks like this:

<-- Create the outer <and> tag -->


<dspel:input type="hidden" bean="${FH}.documentSetsBuilder.tags.andTag.tagname"
value="and">
<-- Create the nested <strprop> tag -->
<dspel:input type="hidden"
bean="${FH}.documentSetsBuilder.tags.andTag.strp.tagname" value="strprop">
<-- Add the <strprop op="equal"> attribute -->
<dspel:input type="hidden"
bean="${FH}.documentSetsBuilder.tags.andTag.strp.attr.op" value="equal">
<-- Add the <strprop name="childSKU.color"> attribute -->
<dspel:input type="hidden"
bean="${FH}.documentSetsBuilder.tags.andTag.strp.attr.name"
value="childSKU.color">
<-- Add the <strprop> tag's body -->
<dspel:input type="hidden"
bean="${FH}.documentSetsBuilder.tags.andTag.strp.body" value="rose">
<-- Create the nested <numprop> tag -->
<dspel:input type="hidden"
bean="${FH}.documentSetsBuilder.tags.andTag.nump.tagname" value="numprop">
<-- Add the <strprop op="lesseq"> attribute -->
<dspel:input type="hidden"
bean="${FH}.documentSetsBuilder.tags.andTag.nump.attr.op" value="equal">
<-- Add the <strprop name="childSKU.price"> attribute -->
<dspel:input type="hidden"
bean="${FH}.documentSetsBuilder.tags.andTag.nump.attr.name"
value="childSKU.price">
<-- Finally, the <strprop> tag's body -->
<dspel:input type="hidden"
bean="${FH}.documentSetsBuilder.tags.andTag.nump.body" value="30.00" >

Things to note from this example

You dont need to explicitly close XML tags, because tag hierarchy is defined in the
bean attribute values of the input tags.

The value of the type attribute need not be "hidden". For example, the body input
tags for each of the two nested tags could be normal input fields, to allow the user to
input the color and maximum price.

85
Appendix B: Using the MapXMLBuilder Class

ATG Commerce Search Guide

Conditionally Rendered Tags

There may be times when the decision to generate one or more tags cannot be made when the page is
rendered. Specifically, it may be undesirable to generate tags meant to capture user input when no input
is provided. In the example below, if the user does not enter a value for the product color,
childSKU.color, then the constraint tag should not be generated.
The conditionally generated strprop tag:

<strprop op="equal" name="childSKU.color">


value from user input, if provided
</strprop>

The JSP:

<-- Create the <strprop> tag -->


<dspel:input type="hidden" bean="${FH}.documentSetsBuilder.tags.myTag.tagname"
value="strprop">
<-- Add the <strprop op="equal"> attribute -->
<dspel:input type="hidden" bean="${FH}.documentSetsBuilder.tags.myTag.attr.op"
value="equal">
<-- Add the <strprop name="childSKU.color"> attribute -->
<dspel:input type="hidden" bean="${FH}.documentSetsBuilder.tags.myTag.attr.name"
value="childSKU.color">
<-- The user input field, in this case the <strprop> tag's body -->
<dspel:input type="text" bean="${FH}.documentSetsBuilder.tags.myTag.body">
<-- The conditional generation option: generate only if user enters a value for
the tag body -->
<dspel:input type="hidden"
bean="${FH}.documentSetsBuilder.tags.myTag.opts.generate" value="ifvalue:body">

Things to note from this example:

The tagname.opts values are used to specify tag generation options to


MapXMLBuilder. These values do not appear in the generated XML.

Currently, the only valid option directive is generate. The valid options for the
generate directive are:
true -- Generate the tag (the default).
false -- Do not generate the tag.
ifchild -- Generate the tag only if it will contain any child tags. Use this option to

prevent the generation of an empty outer tag when none of its child tags are
generated.

86
Appendix B: Using the MapXMLBuilder Class

ATG Commerce Search Guide

ifvalue:tagElement -- Generate the tag if tagIdentifier.tagElement is not


empty. The tagElement value can use dot notation to specify subproperties; for
example, ifvalue:body, or ifvalue:attr.op.
ifbody -- Generate if tagIdentifier.body is not empty. Shorthand for
ifvalue:body.

If a parent tag is not generated, none of its child tags are generated, regardless of the
values of the child tags generate directives.

87
Appendix B: Using the MapXMLBuilder Class

ATG Commerce Search Guide

88
Appendix B: Using the MapXMLBuilder Class

ATG Commerce Search Guide

Index

local access, 74
remote access, 74
customizing XHTML output, 17

assembling an EAR file, 6

D
B
bulk loading, 14
configuring, 14

C
CatalogRankConfigAdapter, 74
catalogs
transforming data, 21
collecting inventory data, 78
collection filters, 43
Commerce Search
configuration, 6
configuring ATG Search, 81
introduction, 5
modules, 5
repository indexing, 9
CommerceFacetSearchDroplet, 57, 66
configuring, 60
CommerceFacetTrailDroplet, 55, 62
configuring, 59
configuring
ATG Search, 81
bulk loading, 14
CommerceFacetSearchDroplet, 60
CommerceFacetTrailDroplet, 59
customization adapters, 74
ESSearchService component, 7
incremental loading, 15
Patch Bay, 52
search form handlers, 30
SearchServer component, 7
constructing queries, 31
Context object, 19
creating database tables, 6
custom catalogs
CustomCatalogPropertyAccessor, 24
CustomCatalogVariantProducer, 24
transforming data, 24
CustomCatalogPropertyAccessor, 24
CustomCatalogVariantProducer, 24
customization adapters, 73
configuring, 74

data, loading, 14
database tables
creating, 6
definition file format, 9
multi-value properties, 10
dimension services, 76
configuring, 78
document submitter
configuring, 16
dynamic navigation
catalog indexing, 54
facets, 53
refinement configuration files, 54
Dynamic Search and Navigation. See dynamic navigation

E
EAR files
assembling, 6
ESSearchServer component, 7

F
facets, 53
CommerceFacetSearchDroplet, 57
CommerceFacetTrailDroplet, 55
facet trails, 55
in JSPs, 55
incorporating search results, 57
FacetSearchDroplet, 57, 66
filtering search results, 43
FirstWithLocalePropertyAccessor, 18
form handlers. See search form handlers

I
incremental loading, 14
configuring, 15
monitored properties, 15
tuning, 16

89
Index

ATG Commerce Search Guide

LanguageDimensionService, 76
loading data, 14
LocaleVariantProducer, 19

refining search results, 45


relQuestSettings attributes, 34
repository indexing, 9
Context object, 19
customizing output, 17
definition file format, 9
loading data, 14
property accessors, 18
PropertyFormatter, 20
PropertyValuesFilter, 20
transforming catalog data, 21
transforming data, 9
variant producers, 19
repository items in search results, 43
request attributes, 33
responseNumberSettings attributes, 34

MapXMLBuilder, 35, 83
examples, 83
modules
Commerce Search, 5
monitored properties, 15
multi-value properties, indexing, 10

sample search application, 31


search configurations
determining which to use, 76
dimension tree, 76
generating, 75
search form handlers, 29
classes, 29
configuring, 30
JMS events, 49
properties, 31
relQuestSettings attributes, 34
request attributes, 33
responseNumberSettings attributes, 34
sample application, 31
using with facets, 57
Search Merchandising
customization adapters, 73
search configuration files, 75
search results
filtering, 43
handling, 40
incorporating in facets, 57
paging, 42
refining, 45
repository items, 43
SearchServer component, 7
SearchUpdateAdapter, 74
ServiceDimensionService, 76
SKUs
indexing, 26
structured statements, 36

IndexingOutputConfig, 14, 15
installing database tables, 6
inventory data
collecting, 78

J
JMS events, 49
Patch Bay configuration, 52

O
output documents, XHTML, 12

P
paging of search results, 42
parametric search queries, 37
Patch Bay configuration, 52
ProductCatalogOutputConfig, 21
properties
monitored, 15
property accessors, 18
FirstWithLocalePropertyAccessor, 18
PropertyFormatter, 20
PropertyValuesFilter, 20

Q
queries
constructing, 31
parametric search, 37
relQuestSettings attributes, 34
request attributes, 33
responseNumberSettings attributes, 34

R
redirection rules, 78
refinement configuration files
generating, 54

T
transforming catalog data, 21
custom catalogs, 24
ProductCatalogOutputConfig, 21

90
Appendix B: Using the MapXMLBuilder Class

ATG Commerce Search Guide

transforming repository data, 9

XHTML output documents, 12


customizing, 17
XMLBuilder, 35, 83

variant producers, 19
LocaleVariantProducer, 19

91
Index