This section describes extensions made to ATG Consumer Commerce and DPS for the Pioneer Cycling store site. DPS performs the collection, storage, and retrieval of data specific to individual users of the Web application. A profile is the data stored for an individual customer based on forms she fills out or her actions on the site. Once this data is collected, it provides Web site developers the ability to show the customer personalized products and content based on this profile.

In the Pioneer Cycling site, we used personalization in a variety of ways to make a compelling shopping experience. DPS provides basic personalization capability, but you can easily extend this functionality to fit the needs of your Web application. The Pioneer Cycling site demonstrates several ways to extend this functionality. Please refer to the Setting up a Profile Repository chapter in the ATG Personalization Programming Guide and the SQL Content Repositories chapter in the ATG Repository Guide for more detailed information about the SQL Repository definitions in DPS and Consumer Commerce.

DPS stores customer data in a repository, which consists of user item types and several supporting item types. The default DPS repository contains item types defined with the set of properties that are needed by most personalized Web applications. In ATG Consumer Commerce, some additional properties have been added to the user item type to make possible many commerce features. Pioneer Cycling adds yet more item types and properties to provide functionality that is specific to a bike store.

These extensions are defined in the XML file <ATG2007.3dir>/atg/userprofiling/userProfile.xml. This file is combined with the files of the same name from ATG Consumer Commerce, DSS, and DPS. These files are combined per the rules of XML combination to produce one XML file that is then parsed and used by ATG to describe the item types in the repository. (See the Nucleus: Organizing JavaBean Components chapter of the for more information on XML file combination.) The combined file is reparsed each time the repository starts and it is never written out to disk, so we only need to maintain the separate files, not the combined one.

The underlying storage of the user profile repository in Pioneer Cycling is a relational database. The SQL Profile Repository is used to expose that data via the Repository API. In the XML file, we describe the mapping of repository items to the relational database tables and columns.

Here are the properties we added to the user item type:

Property

Description

size

The customer’s clothing size. We use this property for targeting size-appropriate clothing to the user.

weightPreference

This integer value is incremented or decremented according to the weight class of the items purchased by the customer. If the customer purchases many lightweight items, he has a low value for weightPreference and we would use that low value to target additional lightweight items to the customer.

pricePreference

This property works much like weightPreference. Products have, in addition to the actual price, a price class that indicates if the product is cheap, moderate, expensive, or luxury, as compared to similar products. If a customer tends to buy cheap items, we can target our best bargains to that customer. A customer that tends to purchase luxury items can be shown more expensive items.

numOrders

A count of the number of orders that this user has placed with the store. This can be used as a measure of customer loyalty.

cumulativeOrderAmount

A running total of the amount of money spent on the site. This can be used for targeting promotions or identifying trends in the customer base. This number represents the amount spent in the currency indicated by the customer’s selected locale. If the user changes his locale from ja_JP to en_US between purchases, then the total, a sum of yen and dollars, will not be meaningful. We assume that a customer chooses a locale and sticks to it.

bikesOwned

We use a scenario to keep track of the types of bikes a user owns so that we can target compatible products to the user.

userKeywords

A list of keywords the customer picks up based on his activities in the store. This property’s value is populated by DSS. When a user purchases a product, that product’s keywords are appended to the userKeywords. When a user conducts a product search, the search term is added to the userKeywords. In general, when a user expresses interest in an item, we store the keywords for the item of interest so that we might use that information later to personalize the user’s experience.

itemsBought

A list of the IDs of items purchased by the user.

categoriesViewed

This transient property keeps track of a list of the catalog categories recently visited by the user.

productsViewed

This transient property keeps track of a list of the products recently visited by the user.

recentSearches

This transient property keeps track of a list of the strings that the user has searched on recently.

The following example shows the XML file for Pioneer Cycling. Please refer to the SQL Repository Architecture chapter in the ATG Repository Guide for the proper definition file syntax.

<gsa-template xml-combine="append">

  <header>
    <name>Bikestore Related Profile Changes</name>
    <author>DCS Team</author>
    <version>$Change: 224215 $$DateTime: 2001/12/27 14:00:56 $$Author:
             bbarber $</version>
  </header>

  <item-descriptor name="user">

    <table name="b2c_user" type="auxiliary" id-column-name="id">
      <attribute name="resourceBundle"
           value="atg.projects.b2cstore.UserProfileTemplateResources"/>

      <property category-resource="categoryPioneerCycling" name="size"
                data-type="enumerated"
                default="clothingSizeUnknown" column-name="clothing_size"
                display-name-resource="clothingSize">
        <attribute name="resourceBundle"
             value="atg.projects.b2cstore.UserProfileTemplateResources"/>
        <attribute name="useCodeForValue" value="false"/>
        <option resource="clothingSizeUnknown" code="0"/>
        <option resource="clothingSizeExtraSmall" code="1"/>
        <option resource="clothingSizeSmall" code="2"/>
        <option resource="clothingSizeMedium" code="3"/>
        <option resource="clothingSizeLarge" code="4"/>
        <option resource="clothingSizeExtraLarge" code="5"/>
      </property>
      <property category-resource="categoryPioneerCycling"
                name="weightPreference"
                data-type="int"
                column-name="weight_preference"
                display-name-resource="weightPreference">
        <attribute name="resourceBundle"
             value="atg.projects.b2cstore.UserProfileTemplateResources"/>
      </property>
       <property category-resource="categoryPioneerCycling"
            name="pricePreference"
            data-type="int" column-name="price_preference"
            display-name-resource="pricePreference">
        <attribute name="resourceBundle"
            value="atg.projects.b2cstore.UserProfileTemplateResources"/>
      </property>
       <property category-resource="categoryPioneerCycling"
                 name="numOrders" display-name-resource="numOrders"
                 data-type="int" column-name="num_orders" default="0">
        <attribute name="resourceBundle"
              value="atg.projects.b2cstore.UserProfileTemplateResources"/>
      </property>
       <property category-resource="categoryPioneerCycling"
                 name="cumulativeOrderAmount"
                 display-name-resource="cumulativeOrderAmount"
                 data-type="double"
                 column-name="cum_order_amt"
                 default="0">
        <attribute name="resourceBundle"
             value="atg.projects.b2cstore.UserProfileTemplateResources"/>
      </property>
     </table>

    <table name="b2c_bike_owned" type="multi" id-column-name="id"
           multi-column-name="sequence_num">
      <property category-resource="categoryPioneerCycling"
                name="bikesYouOwn" data-type="list"
                component-data-type="String" column-name="bike"
                display-name-resource="bikesYouOwn">
        <attribute name="resourceBundle"
              value="atg.projects.b2cstore.UserProfileTemplateResources"/>
      </property>
    </table>
    <table name="b2c_user_keyword" type="multi" id-column-name="id"
           multi-column-name="sequence_num">
      <property category-resource="categoryPioneerCycling"
                name="userKeywords" data-type="list"
               component-data-type="String" column-name="keyword"
               display-name-resource="userKeywords">
        <attribute name="resourceBundle"
             value="atg.projects.b2cstore.UserProfileTemplateResources"/>
      </property>
    </table>
    <table name="b2c_item_bought" type="multi" id-column-name="id"
           multi-column-name="sequence_num">
      <attribute name="resourceBundle"
             value="atg.projects.b2cstore.UserProfileTemplateResources"/>
      <property category-resource="categoryPioneerCycling"
                name="itemsBought"
                data-type="list"
                component-item-type="sku"
                repository="/atg/commerce/catalog/ProductCatalog"
                column-name="item"
                display-name-resource="itemsBought">
        <attribute name="resourceBundle"
              value="atg.projects.b2cstore.UserProfileTemplateResources"/>
      </property>
    </table>

    <!-- The following transient properties used to record categories &
         pages viewed, and recent searches -->
    <property category-resource="categoryPioneerCycling"
              name="categoriesViewed"
              display-name-resource="categoriesViewed"
        data-type="set" component-data-type="String">
      <attribute name="resourceBundle"
            value="atg.projects.b2cstore.UserProfileTemplateResources"/>
    </property>

    <property category-resource="categoryPioneerCycling"
              name="productsViewed" display-name-resource="productsViewed"
        data-type="set" component-data-type="String">
      <attribute name="resourceBundle"
           value="atg.projects.b2cstore.UserProfileTemplateResources"/>
    </property>

    <property category-resource="categoryPioneerCycling"
              name="recentSearches" display-name-resource="recentSearches"
         data-type="set" component-data-type="String">
      <attribute name="resourceBundle"
             value="atg.projects.b2cstore.UserProfileTemplateResources"/>
    </property>

  </item-descriptor>

</gsa-template>

We used the following SQL script to create the database schema to store the user profile data. Note that the tables declared in the XML as type="auxiliary" have one row per user. The tables declared as type="multi" have one row per user per value, so if there are1000 users and each customer purchases 5 items, there will be 5000 rows in the b2c_item_bought table.

CREATE TABLE b2c_user (
     id                   VARCHAR(40)       NOT NULL,
     clothing_size        INT               NULL,
     wants_prod_reviews   TINYINT           NULL,
     weight_preference    INTEGER           NULL,
     price_preference     INTEGER           NULL,
     num_orders           INTEGER           NULL,
     cum_order_amt        DOUBLE PRECISION  NULL,
             PRIMARY KEY(id)
);

CREATE TABLE b2c_user_keyword (
        id                VARCHAR(40)      NOT NULL,
        sequence_num      INTEGER          NOT NULL,
        keyword           VARCHAR(50)      NOT NULL,
        PRIMARY KEY(id, sequence_num)
);

CREATE TABLE b2c_item_bought (
        id                VARCHAR(40)      NOT NULL,
        sequence_num      INTEGER          NOT NULL,
        item              VARCHAR(40)      NOT NULL,
        PRIMARY KEY(id, sequence_num)
);

CREATE TABLE b2c_bike_owned (
        id                VARCHAR(40)      NOT NULL,
        sequence_num      INTEGER          NOT NULL,
        bike              VARCHAR(40)      NOT NULL,
        PRIMARY KEY(id, sequence_num)
);
 
loading table of contents...