Академический Документы
Профессиональный Документы
Культура Документы
Version 2007.1
Commerce Search Guide
ATG
One Main Street
Cambridge, MA 02142
www.atg.com
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
Contents
Getting Started
5
6
6
6
7
7
Repository Indexing
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
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
81
83
Examples
Index
83
89
iv
Contents
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.
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.
5
1 - Getting Started
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
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.
6
1 - Getting Started
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
8
1 - Getting Started
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
9
2 - Repository Indexing
For example, the following definition file enables indexing of site users and their home addresses:
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
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:
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:
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:
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
Note that you can use map-iteration-type=entries to display just the keys or just the values, by
omitting the other tag.
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
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
</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>
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.
14
2 - Repository Indexing
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.
<text-properties>
<property name="fullName"/>
</text-properties>
<monitor>
15
2 - Repository Indexing
<property name="firstName"/>
<property name="lastName"/>
</monitor>
For information about derived properties, see the ATG Repository Guide.
16
2 - Repository Indexing
2.
3.
In the Methods section, click the link for bulkLoad (to run the bulk loader) or
processQueuedUpdates (to run the incremental loader).
4.
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.
17
2 - Repository Indexing
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
For information about the firstWithLocale derivation method, and about derived properties in
general, see the ATG Repository Guide.
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).
19
2 - Repository Indexing
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
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.
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"/>
21
2 - Repository Indexing
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
<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&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
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
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
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.
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
25
2 - Repository Indexing
This is the rule for custom catalogs (which overrides the standard catalog rule if you run the
DCS.Search.CustomCatalogs module):
26
2 - Repository Indexing
27
2 - Repository Indexing
28
2 - Repository Indexing
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
Query Type
QueryFormHandler
<query>
ClientQueryRequest
StructuredQueryFormHandler
<structquery>
ClientStructuredRequest
BrowseFormHandler
<browse>
ClientCategoryRequest
ViewInContextFormHandler
<viewInContext>
ClientVicRequest
SimilarDocsFormHandler
<similardocs>
ClientSimilarDocsRequest
29
3 - Search Form Handlers
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.
30
3 - Search Form Handlers
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
Description
Form Handlers
docContextID
ViewInContextFormHandler
docProps
QueryFormHandler
documentSetsBuilder
BrowseFormHandler
input
BrowseFormHandler
CategorizeFormHandler
SimilarDocsFormHandler
ViewInContextFormHandler
parserOptionsBuilder
BrowseFormHandler
CategorizeFormHandler
QueryFormHandler
SimilarDocsFormHandler
StructuredQueryFormHandler
prefAnswerConstrBuilder
QueryFormHandler
priorInput
QueryFormHandler
property
ViewInContextFormHandler
question
QueryFormHandler
relQuestSettings
QueryFormHandler
requestAttributes
BrowseFormHandler
CategorizeFormHandler
QueryFormHandler
SimilarDocsFormHandler
StructuredQueryFormHandler
CategorizeFormHandler
QueryFormHandler
SimilarDocsFormHandler
StructuredQueryFormHandler
32
3 - Search Form Handlers
responseNumberSettings
QueryFormHandler
return
ViewInContextFormHandler
structuredStatements
StructuredQueryFormHandler
url
ViewInContextFormHandler
value
ViewInContextFormHandler
weightedPropsBuilder
QueryFormHandler
StructuredQueryFormHandler
<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
<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"/>
responseNumberSettings.ans:
<dspel:input type="text" bean="${formHandlerPath}.responseNumberSettings.ans"/>
34
3 - Search Form Handlers
<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
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.
<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
<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>
37
3 - Search Form Handlers
The following JSP example creates a page that includes the form controls shown above.
38
3 - Search Form Handlers
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
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:
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
41
3 - Search Form Handlers
<td>
<c:out value="${document.responseId}"/>
</td>
<td>
<c:out value="${document.normalizedResponse}"/>
</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
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.
43
3 - Search Form Handlers
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
}
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.
45
3 - Search Form Handlers
<!-<!--
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.
uri="http://java.sun.com/jstl/core" %>
46
3 - Search Form Handlers
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
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
49
3 - Search Form Handlers
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
optionSetName
The option set used for the search; empty for the default
option set
resultCount
results
siteName
userProfile
version
BrowseMessage
Property
Description
queryText
CategorizeMessage
Property
Description
queryText
queryMode
QueryMessage
50
3 - Search Form Handlers
Property
Description
queryText
pageNumber
queryMode
SimilarDocsMessage
Property
Description
queryText
queryMode
StructuredQueryMessage
Property
Description
queryText
excludeQueryText
pageNumber
ViewInContextMessage
Property
Description
docContextID
input
property
return
url
value
51
3 - Search Form Handlers
52
3 - Search Form Handlers
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
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.
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.
54
4 - Dynamic Search and Navigation
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.
55
4 - Dynamic Search and Navigation
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.
56
4 - Dynamic Search and Navigation
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.
constraints created based on the facets and categories in the facet trail
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.
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
57
4 - Dynamic Search and Navigation
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>
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.
58
4 - Dynamic Search and Navigation
<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">
. . .
/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.
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
facetTrailSeparator
59
4 - Dynamic Search and Navigation
lastRangeValueIndicator
valueIndicatorSeparator
categoryRefineConfigPropertyName
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
facetSearchService
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
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
defaultSortMode
Specifies the value to use for the sortMode input parameter, if it is not
specified in the page. Default: relevance
defaultSortOrder
61
4 - Dynamic Search and Navigation
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
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.
63
4 - Dynamic Search and Navigation
</dsp:oparam>
64
4 - Dynamic Search and Navigation
<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
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:
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
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
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.
68
4 - Dynamic Search and Navigation
<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
70
4 - Dynamic Search and Navigation
<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
72
4 - Dynamic Search and Navigation
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
73
5 - Search Merchandising
manages the process of generating the search configuration files and submitting them
to ATG Search.
74
5 - Search Merchandising
75
5 - Search Merchandising
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
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.
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.
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
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.
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.
78
5 - Search Merchandising
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
80
5 - Search Merchandising
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.
2.
3.
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.
81
Appendix A: Configuring ATG Search
82
Appendix A: Configuring ATG Search
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:
83
Appendix B: Using the MapXMLBuilder Class
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
identifier.attr.attributeName
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
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
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:
The JSP:
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
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
88
Appendix B: Using the MapXMLBuilder Class
Index
local access, 74
remote access, 74
customizing XHTML output, 17
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
LanguageDimensionService, 76
loading data, 14
LocaleVariantProducer, 19
MapXMLBuilder, 35, 83
examples, 83
modules
Commerce Search, 5
monitored properties, 15
multi-value properties, indexing, 10
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
variant producers, 19
LocaleVariantProducer, 19
91
Index