Search code examples
mahoutrecommendation-enginemahout-recommender

Mahout Recomendaton engine recommending products and with its Quantity to customer


i am working on mahout recommendation engine use case.I precomputed recommendations and stored in database. now i am planning to expose with taste rest services to .net.i had limited customers and products.it is distributor level recommendation use case.my question is if new distributor comes in ,how would i suggests recommendations to him.and also how would i suggest the Quantity of Recommended product to each distributor.could you people give me some guidance.am i going to face performance issues..?


Solution

  • One way is, when new user comes, to precompute the recommendations from scratch for all the users or only for this user. You should know that this user might change the recommendations for the others too. Its up to your needs frequently do you want to do the pre-computations.

    However, if you have limited number of users and items, another way is to have online recommender that computes the recommendations in real time. If you use the FileDataModel, there is a way to get the data from the new user periodically (See the book Mahout in Action). If you use in memory data model, which is faster, you can override the methods: setPreference(long userID, long itemID, float value) and removePreference(long userID, long itemID), and whenever new user comes and likes or removes some items you should call these methods on your data model.

    EDIT: Basically you can get the GenericDataModel, and add this to the methods setPreference and removePreference. This will be your lower level data model. You can wrap it afterwards with ReloadFromJDBCDataModel by setting your data model in the reload() method like this:

    DataModel newDelegateInMemory = delegate.hasPreferenceValues() ? new MutableDataModel(delegate.exportWithPrefs()) : new MutableBooleanPrefDataModel(delegate.exportWithIDsOnly());

    The overridden methods:

    @Override
    public void setPreference(long userID, long itemID, float value) {
    
        userIDs.add(userID);
        itemIDs.add(itemID);
    
        setMinPreference(Math.min(getMinPreference(), value));
        setMaxPreference(Math.max(getMaxPreference(), value));
    
        Preference p = new GenericPreference(userID, itemID, value);
    
        // User preferences
        GenericUserPreferenceArray newUPref;
        int existingPosition = -1;
        if (preferenceFromUsers.containsKey(userID)) {
            PreferenceArray oldPref = preferenceFromUsers.get(userID);
            newUPref = new GenericUserPreferenceArray(oldPref.length() + 1);
            for (int i = 0; i < oldPref.length(); i++) {
                //If the item does not exist in the liked user items, add it!
                if(oldPref.get(i).getItemID()!=itemID){
                    newUPref.set(i, oldPref.get(i));
                }else{
                    //Otherwise remember the position
                    existingPosition = i;
                }
            }
            if(existingPosition>-1){
                //And change the preference value
                oldPref.set(existingPosition, p);
            }else{
                newUPref.set(oldPref.length(), p);
            }
        } else {
            newUPref = new GenericUserPreferenceArray(1);
            newUPref.set(0, p);
        }
        if(existingPosition == -1){
            preferenceFromUsers.put(userID, newUPref);
        }
    
        // Item preferences
        GenericItemPreferenceArray newIPref;
        existingPosition = -1;
        if (preferenceForItems.containsKey(itemID)) {
            PreferenceArray oldPref = preferenceForItems.get(itemID);
            newIPref = new GenericItemPreferenceArray(oldPref.length() + 1);
            for (int i = 0; i < oldPref.length(); i++) {
                if(oldPref.get(i).getUserID()!=userID){
                    newIPref.set(i, oldPref.get(i));
                }else{
                    existingPosition = i;
                }
            }
            if(existingPosition>-1){
                oldPref.set(existingPosition, p);
            }else{
                newIPref.set(oldPref.length(), p);
            }
        } else {
            newIPref = new GenericItemPreferenceArray(1);
            newIPref.set(0, p);
        }
        if(existingPosition == -1){
            preferenceForItems.put(itemID, newIPref);
        }   
    }
    
    @Override
    public void removePreference(long userID, long itemID) {
        // User preferences
        if (preferenceFromUsers.containsKey(userID)) {
            List<Preference> newPu = new ArrayList<Preference>();
            for (Preference p : preferenceFromUsers.get(userID)) {
                if(p.getItemID()!=itemID){
                    newPu.add(p);
                }       
            }
            preferenceFromUsers.remove(userID);
            preferenceFromUsers.put(userID, new GenericUserPreferenceArray(newPu)); 
        }
        if(preferenceFromUsers.get(userID).length()==0){
            preferenceFromUsers.remove(userID);
            userIDs.remove(userID); 
        }
        if (preferenceForItems.containsKey(itemID)) {
            List<Preference> newPi = new ArrayList<Preference>();
            for (Preference p : preferenceForItems.get(itemID)) {
                if(p.getUserID() != userID){
                    newPi.add(p);
                }   
            }
            preferenceForItems.remove(itemID);
            preferenceForItems.put(itemID, new GenericItemPreferenceArray(newPi));
        }   
        if(preferenceForItems.get(itemID).length()==0){
            //Not sure if this is needed, but it works without removing the item
            //preferenceForItems.remove(itemID);
            //itemIDs.remove(itemID);
        }
    }