previous next Title Contents

Appendix A: Categories

The APIs described so far provide recommendations based solely on the (subjective) votes of items recorded by persons. This appendix describes additions to that functionality, extending the recommendation mechanism to use demographic information known about the persons and/or descriptive information known about the items.

The approach we've taken is to define "categories", to allow persons to be associated with categories of demographic information, and to allow items to be associated with categories of descriptive information. Here are examples of possible demographic categories:


    age_0_20
    age_21_35
    age_36_54
    age_55_up
    job_doctor
    job_lawyer
    job_teacher
    zip_9xxxx
And here are examples of item description categories for a travel information application:

    restaurant_French
    restaurant_Chinese
    music_blues
    music_classical
    recreation_bicycling
Note: We do not allow a person to explicitly rate a whole category, e.g., it is not possible to say "I like Chinese restaurants in general." Instead, such information is inferred. We also do not allow the specification of structural relationships between categories, such as "Chinese restaurants are a kind of Asian restaurant".

Here are the API additions to eetypes.h:


    class ee_category {                   // an opaque uid for a category
    public:
        int uid;
        ee_category(int uu = 0): uid(uu) {};
    };
    inline int operator==(const ee_category& x, const ee_category& xx)
    { return x.uid == xx.uid; }
    
    const ee_category ee_category_null(0); // unused "null" value
For each category, there is a model (just as with persons and items). The schema for nonvolatile storage needs to be extended with a Categories table to hold the category models:

    ee_category category;                // unique key
    ee_model model;

There must also be a mechanism (tables or procedures) to map information about persons and items to categories.

Here are the additions to eepredict.h:

(a) Add two member functions:


    void reset_person_category(
        const ee_person x, const ee_category c, const float w);
    /* Assert c as a category for person x with weight w; remove any
       such assertion if w==0. This call should follow any change in
       the nonvolatile database; it resets any cache the predictor may
       have kept. */
    void reset_item_category(
        const ee_item y, const ee_category c, const float w);
    /* Assert c as a category for item y with weight w; remove any such
       assertion if w is 0. This call should follow any change in the
       nonvolatile database; it resets any cache the predictor may have
       kept. */
(b) Add two pure virtual functions (to be implemented by the application programmer):

    virtual void get_person_categories(
        const ee_person x,
        void (*setcategory)(
            const ee_person x, const ee_category c, const float w, void* a),
        void* arg) = 0;
    /* Retrieve all categories (and weights) for person x from nonvolatile
       storage, calling (*setcategory)(x, category, weight, arg) for each. */
    virtual void get_person_category_model(
        const ee_category c,
        ee_model& m) = 0;
    /* Retrieve category c's model from nonvolatile storage, and return
       it in m; if there is no model, return the null model. */

Finally, here are the additions to eesolve.h:

(a) Add four member functions to class ee_solve:


    void set_category_model(const ee_category c, const ee_model& m);
    /* Set the model for category c to be m. Before initialization, a
       model is treated as null. */
        
    void set_person_in_category(
        const ee_person x, const ee_category c, const float w);
    /* Assert that x is a member of c with weight w; a zero weight
       clears an assertion. */
    void set_item_in_category(
        const ee_item y, const ee_category c, const float w);
    /* Assert that y is a member of c with weight w; a zero weight
       clears an assertion. */
    void get_category_model(const ee_category c, ee_model& m);
    /* Set m to category c's model. */
(b) Add a new class:

    class category_iterator {
    public:
        category_iterator(ee_solve& s); // constructor
        ~category_iterator();           // destructor
        ee_category get_next();         // iterate over categories
    private:
        // Disable the copy constructor and assignment operator:
        category_iterator(const category_iterator& rhs);
        category_iterator& operator=(const category_iterator& rhs);
        ee_solve_category_iterator_impl *impl; // instance data
    };
    friend class category_iterator;
    /* A category_iterator is used to discover all the categories known
       to the solver.  A category is known to the solver if one or more
       persons or items have been registered in that category via
       set_person_in_category or set_item_in_category and not deleted
       via restart, or if a model for that category has been registered
       via set_category_model and not deleted via restart.
       Each call to get_next returns another category not previously
       returned since the iterator was constructed, or ee_category_null
       if none remain.  The result of interleaving calls to get_next
       with calls to set_*_in_category or set_category_model is undefined. */


previous next Title Contents