Mahout and DAO connection

classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

Mahout and DAO connection

Johan Fredholm
Hi,
I have been trying to configure Mahout for using hibernate. I haven't
been able to find any examples of such a configuration. Its probably
the wrong way to do it but I cant even get this simple model to work.
It would be great if you could tell me what I'm doing wrong here, and
maybe some pointers on how it should be done.

Items are Arrangements, Users are Accounts and Preferences are Reviews
So I have made this DataModel. Recommendations should only be made
from the arrangements that I supply to the datamodel in the
constructor

-------------------
public class WorkDataModel implements DataModel {

    DataModel delegate;

    public WorkDataModel(AccountDAO accountDAO, ArrangementDAO
arrangementDAO, ReviewDAO reviewDAO, List<Arrangement> arrangements) {
        super();
        this.accountDAO = accountDAO;
        this.arrangementDAO = arrangementDAO;
        this.reviewDAO = reviewDAO;
        this.arrangements = arrangements;
        refresh();

        FastByIDMap<PreferenceArray> users = readUsers();
        delegate = new GenericDataModel(users);
    }

    private FastByIDMap<PreferenceArray> readUsers() {
        FastByIDMap<Collection<Preference>> userIDPrefMap = new
FastByIDMap<Collection<Preference>>();

        for (Review r : reviews) {

            Collection<Preference> userPrefs =
userIDPrefMap.get(r.getReviewer().getId());
            if (userPrefs == null) {
                userPrefs = new ArrayList<Preference>(2);
                userIDPrefMap.put(r.getReviewer().getId(), userPrefs);
            }
            userPrefs.add(new GenericPreference(
                    r.getReviewer().getId(),
                    r.getArrangement().getId(),
                    r.getValue()));
        }

        return GenericDataModel.toDataMap(userIDPrefMap, true);
    }

    @Override
    public LongPrimitiveIterator getUserIDs() throws TasteException {
        LongPrimitiveIterator userIDs = delegate.getUserIDs();
        return userIDs;
    }

    @Override
    public PreferenceArray getPreferencesFromUser(long id)
            throws TasteException {
        PreferenceArray preferencesFromUser =
delegate.getPreferencesFromUser(id);
        return preferencesFromUser;
    }

    @Override
    public FastIDSet getItemIDsFromUser(long userID) throws TasteException {
        FastIDSet itemIDsFromUser = delegate.getItemIDsFromUser(userID);
        return itemIDsFromUser;
    }

    @Override
    public LongPrimitiveIterator getItemIDs() throws TasteException {
        LongPrimitiveIterator itemIDs = delegate.getItemIDs();
        return itemIDs;
    }

    @Override
    public PreferenceArray getPreferencesForItem(long itemID)
            throws TasteException {
        PreferenceArray preferencesForItem =
delegate.getPreferencesForItem(itemID);
        return preferencesForItem;
    }

    @Override
    public Float getPreferenceValue(long userID, long itemID)
            throws TasteException {
        Float preferenceValue = delegate.getPreferenceValue(userID, itemID);
        return preferenceValue;
    }

    @Override
    public int getNumItems() throws TasteException {
        int numItems = delegate.getNumItems();
        return numItems;
    }

    @Override
    public int getNumUsers() throws TasteException {
        int numUsers = delegate.getNumUsers();
        return numUsers;
    }

    @Override
    public int getNumUsersWithPreferenceFor(long... itemIDs)
            throws TasteException {
        int numUsersWithPreferenceFor =
delegate.getNumUsersWithPreferenceFor(itemIDs);
        return numUsersWithPreferenceFor;
    }

    @Override
    public void setPreference(long userID, long itemID, float value) {
        throw new UnsupportedOperationException();
    }

    @Override
    public void removePreference(long userID, long itemID) {
        throw new UnsupportedOperationException();
    }

    @Override
    public void refresh(Collection<Refreshable> alreadyRefreshed) {
        // do nothing
    }

    private AccountDAO accountDAO;

    private ReviewDAO reviewDAO;

    private ArrangementDAO arrangementDAO;

    private List<Arrangement> arrangements;

    private List<Account> accounts;

    private List<Review> reviews;

    public void refresh() {

        if (arrangements == null) {
            arrangements = arrangementDAO.getAll();
        }
        accounts = accountDAO.getAll();
        reviews = reviewDAO.getAll();
    }
}
-------------------



and I use this to get recommendations from user:

-------------------
List<Arrangement> arrangements = arrangementDAO.getArrangements();
DataModel model = new WorkDataModel(accountDAO, arrangementDAO,
reviewDAO, arrangements);

UserSimilarity userSimilarity = new PearsonCorrelationSimilarity(model);
UserNeighborhood neighborhood =  new NearestNUserNeighborhood(3,
userSimilarity, model);

Recommender recommender = new GenericUserBasedRecommender(model,
neighborhood, userSimilarity);
Recommender cachingRecommender = new CachingRecommender(recommender);

List<RecommendedItem> recommendations =
cachingRecommender.recommend(account.getId(), amount);
-------------------

and this to get recommendations from arrangements:

-------------------

DataModel model = new WorkDataModel(accountDAO, arrangementDAO,
reviewDAO, arrangements);
ItemSimilarity correlations = new PearsonCorrelationSimilarity(model);
Recommender cachingRecommender = new CachingRecommender(new
GenericItemBasedRecommender(model, correlations));
List<RecommendedItem> recommendations =
cachingRecommender.recommend(arrangement.getId(), 10);

-------------------


When running recommendations from arrangement I get a
"org.apache.mahout.cf.taste.common.NoSuchUserException"  in
GenericDataModel.getPreferencesFromUser. It seems that it gets a Item
ID instead of a User ID, so probably a stupid mistake, but I cant find
out what.
Running recommendations from Account (User) doesnt return any
recommendations at all.
I think my testdate should be ok, probably something is fishy in my
DataModel implementation.
If you could also give me some pointers on how I could do this faster
I would be thankfull..

Thanks!
Johan
Reply | Threaded
Open this post in threaded view
|

Re: Mahout and DAO connection

Sean Owen
Yes everything looks fine here, but with one key issue.
It seems you are trying to recommender "users" to "items" in the
second case. That is not what an item-based recommender does -- it
still recommenders items to users.

To do what you want, you need to transpose user and item IDs in your
DataModel, then use any algorithm you like. It's a two-line change to
the line where you make a GenericPreference. Maybe create a flag in
the constructor that controls this so you can reuse the model in both
cases.

It does mean you need a separate model, yes.

PS I think your model-building will use a lot of memory at peak --
that map of Collection<Preference> will be a lot bigger than the final
data set. You can instead build PreferenceArray directly, note.

On Thu, Nov 26, 2009 at 9:38 AM, Johan Fredholm
<[hidden email]> wrote:
> Hi,
> I have been trying to configure Mahout for using hibernate. I haven't
> been able to find any examples of such a configuration. Its probably
> the wrong way to do it but I cant even get this simple model to work.
> It would be great if you could tell me what I'm doing wrong here, and
> maybe some pointers on how it should be done.
>
Reply | Threaded
Open this post in threaded view
|

Re: Mahout and DAO connection

Johan Fredholm
Thanks for the help.
I got the recommender based on items to work, but I cant seem to get
the recommender based on users to work.
I don't get any errors, I just don't get any results.

My call>
-----------------
WorkDataModel model = new WorkDataModel(accountDAO, arrangementDAO,
reviewDAO, arrangements);
UserSimilarity userSimilarity = new PearsonCorrelationSimilarity(model);
userSimilarity.setPreferenceInferrer(new AveragingPreferenceInferrer(model));
NearestNUserNeighborhood  neighborhood =  new NearestNUserNeighborhood
(3, userSimilarity, model);
GenericUserBasedRecommender recommender = new
GenericUserBasedRecommender(model, neighborhood, userSimilarity);
List<RecommendedItem> recommendations =
recommender.recommend(account.getId(), amount);
------------------

It looks like WorkDataModel returns everything correctly.
This is my test:

------------------
List<Arrangement> allReady = arrangementDAO.getAllReady();

Account ac1 = accountDAO.get(22L);
Account ac2 = accountDAO.get(21L);
Account ac3 = accountDAO.get(23L);
               
int i = 0;
Arrangement aSearch = null;
               
for (Arrangement a : allReady) {
                       
        if (i < 8) {
                reviewDAO.save(new Review(a, ac1, 4F, Reviewtype.HUMAN));
        }
        if (i > 3) {
                reviewDAO.save(new Review(a, ac2, 2F, Reviewtype.HUMAN));
        }
        if (i > 6 && i < 16) {
                reviewDAO.save(new Review(a, ac3, 5F, Reviewtype.HUMAN));
        }
                       
        if (i == 5) {
                aSearch = a;
        }
                       
        if (i > 15) {
                break;
        }
                       
        i++;
}

List<Arrangement> recommendations =
arrangementService.getRecommendations(ac1, allReady, 10);
-------------------

I'm not really sure what I am sending in there, I'm just trying to mix
it up a bit :-)
I have tried to get recommendations from for all three of the accounts
(users), but I don't get anything.
Do I need more preferences, or is something else wrong?? The
preferences are not overlapping, so shouldn't I get some kind of
result back?

Thanks!
Johan


On Thu, Nov 26, 2009 at 12:02 PM, Sean Owen <[hidden email]> wrote:

> Yes everything looks fine here, but with one key issue.
> It seems you are trying to recommender "users" to "items" in the
> second case. That is not what an item-based recommender does -- it
> still recommenders items to users.
>
> To do what you want, you need to transpose user and item IDs in your
> DataModel, then use any algorithm you like. It's a two-line change to
> the line where you make a GenericPreference. Maybe create a flag in
> the constructor that controls this so you can reuse the model in both
> cases.
>
> It does mean you need a separate model, yes.
>
> PS I think your model-building will use a lot of memory at peak --
> that map of Collection<Preference> will be a lot bigger than the final
> data set. You can instead build PreferenceArray directly, note.
>
> On Thu, Nov 26, 2009 at 9:38 AM, Johan Fredholm
> <[hidden email]> wrote:
>> Hi,
>> I have been trying to configure Mahout for using hibernate. I haven't
>> been able to find any examples of such a configuration. Its probably
>> the wrong way to do it but I cant even get this simple model to work.
>> It would be great if you could tell me what I'm doing wrong here, and
>> maybe some pointers on how it should be done.
>>
>
Reply | Threaded
Open this post in threaded view
|

Re: Mahout and DAO connection

Sean Owen
I'm not clear what you mean. There are user-based and item-based
recommenders. Both recommend items to users. You had expressed
interest in recommending users to items. That could be done with a
user-based or item-based recommender, by flipping user and item IDs.

Which one(s) are and aren't working exactly? You show a user-based
recommender below, but can't tell whether you mean this works or
doesn't.

Also I am not sure what's going on in WorkDataModel. Have you
'flipped' user and item IDs there or no?

Last you say you are trying to recommend items to users, and that's an
issue, but I thought you had that working.

Back up a bit and clarify what the situation is.

(PS I wouldn't use a preference inferrer unless you know for sure it's
beneficial. It usually isn't.)

On Fri, Nov 27, 2009 at 12:51 AM, Johan Fredholm
<[hidden email]> wrote:

> Thanks for the help.
> I got the recommender based on items to work, but I cant seem to get
> the recommender based on users to work.
> I don't get any errors, I just don't get any results.
>
> My call>
> -----------------
> WorkDataModel model = new WorkDataModel(accountDAO, arrangementDAO,
> reviewDAO, arrangements);
> UserSimilarity userSimilarity = new PearsonCorrelationSimilarity(model);
> userSimilarity.setPreferenceInferrer(new AveragingPreferenceInferrer(model));
> NearestNUserNeighborhood  neighborhood =  new NearestNUserNeighborhood
> (3, userSimilarity, model);
> GenericUserBasedRecommender recommender = new
> GenericUserBasedRecommender(model, neighborhood, userSimilarity);
> List<RecommendedItem> recommendations =
> recommender.recommend(account.getId(), amount);
> ------------------
>
> It looks like WorkDataModel returns everything correctly.
> This is my test:
>
> ------------------
> List<Arrangement> allReady = arrangementDAO.getAllReady();
>
> Account ac1 = accountDAO.get(22L);
> Account ac2 = accountDAO.get(21L);
> Account ac3 = accountDAO.get(23L);
>
> int i = 0;
> Arrangement aSearch = null;
>
> for (Arrangement a : allReady) {
>
>        if (i < 8) {
>                reviewDAO.save(new Review(a, ac1, 4F, Reviewtype.HUMAN));
>        }
>        if (i > 3) {
>                reviewDAO.save(new Review(a, ac2, 2F, Reviewtype.HUMAN));
>        }
>        if (i > 6 && i < 16) {
>                reviewDAO.save(new Review(a, ac3, 5F, Reviewtype.HUMAN));
>        }
>
>        if (i == 5) {
>                aSearch = a;
>        }
>
>        if (i > 15) {
>                break;
>        }
>
>        i++;
> }
>
> List<Arrangement> recommendations =
> arrangementService.getRecommendations(ac1, allReady, 10);
> -------------------
>
> I'm not really sure what I am sending in there, I'm just trying to mix
> it up a bit :-)
> I have tried to get recommendations from for all three of the accounts
> (users), but I don't get anything.
> Do I need more preferences, or is something else wrong?? The
> preferences are not overlapping, so shouldn't I get some kind of
> result back?
>
> Thanks!
> Johan
>
>
> On Thu, Nov 26, 2009 at 12:02 PM, Sean Owen <[hidden email]> wrote:
>> Yes everything looks fine here, but with one key issue.
>> It seems you are trying to recommender "users" to "items" in the
>> second case. That is not what an item-based recommender does -- it
>> still recommenders items to users.
>>
>> To do what you want, you need to transpose user and item IDs in your
>> DataModel, then use any algorithm you like. It's a two-line change to
>> the line where you make a GenericPreference. Maybe create a flag in
>> the constructor that controls this so you can reuse the model in both
>> cases.
>>
>> It does mean you need a separate model, yes.
>>
>> PS I think your model-building will use a lot of memory at peak --
>> that map of Collection<Preference> will be a lot bigger than the final
>> data set. You can instead build PreferenceArray directly, note.
>>
>> On Thu, Nov 26, 2009 at 9:38 AM, Johan Fredholm
>> <[hidden email]> wrote:
>>> Hi,
>>> I have been trying to configure Mahout for using hibernate. I haven't
>>> been able to find any examples of such a configuration. Its probably
>>> the wrong way to do it but I cant even get this simple model to work.
>>> It would be great if you could tell me what I'm doing wrong here, and
>>> maybe some pointers on how it should be done.
>>>
>>
>
Reply | Threaded
Open this post in threaded view
|

Re: Mahout and DAO connection

Johan Fredholm
Ok, sorry for being unclear.
I wrote at the end there in mail 1 "Running recommendations from
Account (User) doesn't return any
recommendations at all.". That's the userbased recommender. It didn't
throw any exceptions like the item-based recommender, but it also
didn't (and doesn't) return anything. I did flip the values in the
DataModel for the item-based recommender like you suggested, and it
now works. The DataModel for the user-based recommender is unchanged.
So in total for the user-based recommender the code now is:

The DataModel.
--------------------

public class WorkDataModel implements DataModel {

        org.apache.mahout.cf.taste.model.DataModel delegate;

        public WorkDataModel(ArrangementDAO arrangementDAO,
                        ReviewDAO reviewDAO, List<Arrangement> arrangements) {
                super();
                this.arrangementDAO = arrangementDAO;
                this.reviewDAO = reviewDAO;
                this.arrangements = arrangements;
                refresh();

                FastByIDMap<PreferenceArray> users = readUsers();
                delegate = new GenericDataModel(users);
        }

        private FastByIDMap<PreferenceArray> readUsers() {
                FastByIDMap<Collection<Preference>> userIDPrefMap = new
FastByIDMap<Collection<Preference>>();

                for (Review r : reviews) {

                        Collection<Preference> userPrefs =
userIDPrefMap.get(r.getReviewer().getId());
                        if (userPrefs == null) {
                                userPrefs = new ArrayList<Preference>(2);
                                userIDPrefMap.put(r.getReviewer().getId(), userPrefs);
                        }
                        userPrefs.add(new GenericPreference(
                                        r.getReviewer().getId(),
                                        r.getArrangement().getId(),
                                        r.getValue()));
                }

                return GenericDataModel.toDataMap(userIDPrefMap, true);
        }


        @Override
        public LongPrimitiveIterator getUserIDs() throws TasteException {
                LongPrimitiveIterator userIDs = delegate.getUserIDs();
                return userIDs;
        }

        @Override
        public PreferenceArray getPreferencesFromUser(long id) throws TasteException {
                PreferenceArray preferencesFromUser = delegate.getPreferencesFromUser(id);
                return preferencesFromUser;
        }

        @Override
        public FastIDSet getItemIDsFromUser(long userID) throws TasteException {
                FastIDSet itemIDsFromUser = delegate.getItemIDsFromUser(userID);
                return itemIDsFromUser;
        }

        @Override
        public LongPrimitiveIterator getItemIDs() throws TasteException {
                LongPrimitiveIterator itemIDs = delegate.getItemIDs();
                return itemIDs;
        }

        @Override
        public PreferenceArray getPreferencesForItem(long itemID)
                        throws TasteException {
                PreferenceArray preferencesForItem = delegate.getPreferencesForItem(itemID);
                return preferencesForItem;
        }

        @Override
        public Float getPreferenceValue(long userID, long itemID)
                        throws TasteException {
                Float preferenceValue = delegate.getPreferenceValue(userID, itemID);
                return preferenceValue;
        }

        @Override
        public int getNumItems() throws TasteException {
                int numItems = delegate.getNumItems();
                return numItems;
        }

        @Override
        public int getNumUsers() throws TasteException {
                int numUsers = delegate.getNumUsers();
                return numUsers;
        }

        @Override
        public int getNumUsersWithPreferenceFor(long... itemIDs)
                        throws TasteException {
                int numUsersWithPreferenceFor =
delegate.getNumUsersWithPreferenceFor(itemIDs);
                return numUsersWithPreferenceFor;
        }

        @Override
        public void setPreference(long userID, long itemID, float value) {
                throw new UnsupportedOperationException();
        }

        @Override
        public void removePreference(long userID, long itemID) {
                throw new UnsupportedOperationException();
        }

        @Override
        public void refresh(Collection<Refreshable> alreadyRefreshed) {
                // do nothing
        }

        private ReviewDAO reviewDAO;

        private ArrangementDAO arrangementDAO;

        private List<Arrangement> arrangements;

        private List<Review> reviews;

        public void refresh() {

                if (arrangements == null) {
                        arrangements = arrangementDAO.getAll();
                }
                reviews = reviewDAO.getAll();
        }

}
--------------
I have debugged it and the WorkDataModel seems to return valid data.
The call and the test code is in my last mail. I removed the
AveragingPreferenceInferrer, but it didnt change that I get no results
back.
I hope that's clearer.

Thank you!
Johan




On Fri, Nov 27, 2009 at 1:57 AM, Sean Owen <[hidden email]> wrote:

> I'm not clear what you mean. There are user-based and item-based
> recommenders. Both recommend items to users. You had expressed
> interest in recommending users to items. That could be done with a
> user-based or item-based recommender, by flipping user and item IDs.
>
> Which one(s) are and aren't working exactly? You show a user-based
> recommender below, but can't tell whether you mean this works or
> doesn't.
>
> Also I am not sure what's going on in WorkDataModel. Have you
> 'flipped' user and item IDs there or no?
>
> Last you say you are trying to recommend items to users, and that's an
> issue, but I thought you had that working.
>
> Back up a bit and clarify what the situation is.
>
> (PS I wouldn't use a preference inferrer unless you know for sure it's
> beneficial. It usually isn't.)
>
> On Fri, Nov 27, 2009 at 12:51 AM, Johan Fredholm
> <[hidden email]> wrote:
>> Thanks for the help.
>> I got the recommender based on items to work, but I cant seem to get
>> the recommender based on users to work.
>> I don't get any errors, I just don't get any results.
>>
>> My call>
>> -----------------
>> WorkDataModel model = new WorkDataModel(accountDAO, arrangementDAO,
>> reviewDAO, arrangements);
>> UserSimilarity userSimilarity = new PearsonCorrelationSimilarity(model);
>> userSimilarity.setPreferenceInferrer(new AveragingPreferenceInferrer(model));
>> NearestNUserNeighborhood  neighborhood =  new NearestNUserNeighborhood
>> (3, userSimilarity, model);
>> GenericUserBasedRecommender recommender = new
>> GenericUserBasedRecommender(model, neighborhood, userSimilarity);
>> List<RecommendedItem> recommendations =
>> recommender.recommend(account.getId(), amount);
>> ------------------
>>
>> It looks like WorkDataModel returns everything correctly.
>> This is my test:
>>
>> ------------------
>> List<Arrangement> allReady = arrangementDAO.getAllReady();
>>
>> Account ac1 = accountDAO.get(22L);
>> Account ac2 = accountDAO.get(21L);
>> Account ac3 = accountDAO.get(23L);
>>
>> int i = 0;
>> Arrangement aSearch = null;
>>
>> for (Arrangement a : allReady) {
>>
>>        if (i < 8) {
>>                reviewDAO.save(new Review(a, ac1, 4F, Reviewtype.HUMAN));
>>        }
>>        if (i > 3) {
>>                reviewDAO.save(new Review(a, ac2, 2F, Reviewtype.HUMAN));
>>        }
>>        if (i > 6 && i < 16) {
>>                reviewDAO.save(new Review(a, ac3, 5F, Reviewtype.HUMAN));
>>        }
>>
>>        if (i == 5) {
>>                aSearch = a;
>>        }
>>
>>        if (i > 15) {
>>                break;
>>        }
>>
>>        i++;
>> }
>>
>> List<Arrangement> recommendations =
>> arrangementService.getRecommendations(ac1, allReady, 10);
>> -------------------
>>
>> I'm not really sure what I am sending in there, I'm just trying to mix
>> it up a bit :-)
>> I have tried to get recommendations from for all three of the accounts
>> (users), but I don't get anything.
>> Do I need more preferences, or is something else wrong?? The
>> preferences are not overlapping, so shouldn't I get some kind of
>> result back?
>>
>> Thanks!
>> Johan
>>
>>
>> On Thu, Nov 26, 2009 at 12:02 PM, Sean Owen <[hidden email]> wrote:
>>> Yes everything looks fine here, but with one key issue.
>>> It seems you are trying to recommender "users" to "items" in the
>>> second case. That is not what an item-based recommender does -- it
>>> still recommenders items to users.
>>>
>>> To do what you want, you need to transpose user and item IDs in your
>>> DataModel, then use any algorithm you like. It's a two-line change to
>>> the line where you make a GenericPreference. Maybe create a flag in
>>> the constructor that controls this so you can reuse the model in both
>>> cases.
>>>
>>> It does mean you need a separate model, yes.
>>>
>>> PS I think your model-building will use a lot of memory at peak --
>>> that map of Collection<Preference> will be a lot bigger than the final
>>> data set. You can instead build PreferenceArray directly, note.
>>>
>>> On Thu, Nov 26, 2009 at 9:38 AM, Johan Fredholm
>>> <[hidden email]> wrote:
>>>> Hi,
>>>> I have been trying to configure Mahout for using hibernate. I haven't
>>>> been able to find any examples of such a configuration. Its probably
>>>> the wrong way to do it but I cant even get this simple model to work.
>>>> It would be great if you could tell me what I'm doing wrong here, and
>>>> maybe some pointers on how it should be done.
>>>>
>>>
>>
>
Reply | Threaded
Open this post in threaded view
|

Re: Mahout and DAO connection

Sean Owen
Yes, in order to recommend users to items, you just have to flip user
IDs and item IDs. Then use whatever algorithm you want. Then you pass
in item IDs, not user IDs, to recommend(). If you were passing item
IDs, without flipping the two, that would be why things don't work.

You are saying you flipped the values, and it works now. What is not
working then -- are you just wondering why you saw no results in that
one case?

On Fri, Nov 27, 2009 at 1:19 AM, Johan Fredholm
<[hidden email]> wrote:

> Ok, sorry for being unclear.
> I wrote at the end there in mail 1 "Running recommendations from
> Account (User) doesn't return any
> recommendations at all.". That's the userbased recommender. It didn't
> throw any exceptions like the item-based recommender, but it also
> didn't (and doesn't) return anything. I did flip the values in the
> DataModel for the item-based recommender like you suggested, and it
> now works. The DataModel for the user-based recommender is unchanged.
> So in total for the user-based recommender the code now is:
>
Reply | Threaded
Open this post in threaded view
|

Re: Mahout and DAO connection

Johan Fredholm
No I want both, (both user and item based recommendation) and the
item-based recommender now works, but the user-based recommender
returns nothing.
I remade the DataModel for the _user-based_ recommender. Here it is>

----------------------

public class WorkDataModel implements DataModel {

        FastByIDMap<PreferenceArray> usersArray;
        FastByIDMap<PreferenceArray> itemsArray;

        public WorkDataModel(ArrangementDAO arrangementDAO, ReviewDAO
reviewDAO, List<Arrangement> arrangements) {
                super();
                this.arrangementDAO = arrangementDAO;
                this.reviewDAO = reviewDAO;
                this.arrangements = arrangements;
                refresh();

                usersArray = readUsers();
                itemsArray = readItems();
        }

        private FastByIDMap<PreferenceArray> readItems() {

                FastByIDMap<Collection<Preference>> userIDPrefMap = new
FastByIDMap<Collection<Preference>>();

                for (Review r : reviews) {

                        Collection<Preference> userPrefs =
userIDPrefMap.get(r.getArrangement().getId());
                        if (userPrefs == null) {
                                userPrefs = new ArrayList<Preference>(2);
                                userIDPrefMap.put(r.getArrangement().getId(), userPrefs);
                        }
                        userPrefs.add(new GenericPreference(
                                        r.getReviewer().getId(),
                                        r.getArrangement().getId(),
                                        r.getValue()));
                }

                return GenericDataModel.toDataMap(userIDPrefMap, true);
        }

        private FastByIDMap<PreferenceArray> readUsers() {

                FastByIDMap<Collection<Preference>> userIDPrefMap = new
FastByIDMap<Collection<Preference>>();

                for (Review r : reviews) {

                        Collection<Preference> userPrefs =
userIDPrefMap.get(r.getReviewer().getId());
                        if (userPrefs == null) {
                                userPrefs = new ArrayList<Preference>(2);
                                userIDPrefMap.put(r.getReviewer().getId(), userPrefs);
                        }
                        userPrefs.add(new GenericPreference(
                                        r.getReviewer().getId(),
                                        r.getArrangement().getId(),
                                        r.getValue()));
                }

                return GenericDataModel.toDataMap(userIDPrefMap, true);
        }

        @Override
        public LongPrimitiveIterator getUserIDs() throws TasteException {
                LongPrimitiveIterator keySetIterator = usersArray.keySetIterator();
                return keySetIterator;
        }

        @Override
        public PreferenceArray getPreferencesFromUser(long id) throws TasteException {
                return usersArray.get(id);
        }

        @Override
        public FastIDSet getItemIDsFromUser(long userID) throws TasteException {

                FastIDSet itemIDsFromUser = new FastIDSet();
               
                for (Preference pref : usersArray.get(userID)) {
                        itemIDsFromUser.add(pref.getItemID());
                }
               
                return itemIDsFromUser;
        }

        @Override
        public LongPrimitiveIterator getItemIDs() throws TasteException {
                throw new UnsupportedOperationException();
        }

        @Override
        public PreferenceArray getPreferencesForItem(long id)
                        throws TasteException {
                return itemsArray.get(id);
        }

        @Override
        public Float getPreferenceValue(long userID, long itemID)
                        throws TasteException {
                throw new UnsupportedOperationException();
        }

        @Override
        public int getNumItems() throws TasteException {
                return itemsArray.size();
        }

        @Override
        public int getNumUsers() throws TasteException {
                return usersArray.size();
        }

        @Override
        public int getNumUsersWithPreferenceFor(long... itemIDs) throws
TasteException {
                throw new UnsupportedOperationException();
        }

        @Override
        public void setPreference(long userID, long itemID, float value) {
                throw new UnsupportedOperationException();
        }

        @Override
        public void removePreference(long userID, long itemID) {
                throw new UnsupportedOperationException();
        }

        @Override
        public void refresh(Collection<Refreshable> alreadyRefreshed) {
                // do nothing
        }

        private ReviewDAO reviewDAO;

        private ArrangementDAO arrangementDAO;

        private List<Arrangement> arrangements;

        private List<Review> reviews;

        public void refresh() {

                if (arrangements == null) {
                        arrangements = arrangementDAO.getAll();
                }
                reviews = reviewDAO.getAll();
        }
}
-------------------

here is the call

------------------

                        WorkDataModel model = new WorkDataModel(arrangementDAO, reviewDAO,
arrangements);
                        UserSimilarity userSimilarity = new PearsonCorrelationSimilarity(model);
                        NearestNUserNeighborhood  neighborhood =  new
NearestNUserNeighborhood (3, userSimilarity, model);
                        GenericUserBasedRecommender recommender = new
GenericUserBasedRecommender(model, neighborhood, userSimilarity);
                        List<RecommendedItem> recommendations =
recommender.recommend(account.getId(), amount);
-----------------
and the unittest
-----------------

                List<Arrangement> allReady = arrangementDAO.getAllReady();
               
                reviewDAO.emptyTable();
                Account ac1 = accountDAO.get(22L);
                Account ac2 = accountDAO.get(21L);
                Account ac3 = accountDAO.get(23L);
               
                int i = 0;
                Arrangement aSearch = null;
               
                for (Arrangement a : allReady) {
                       
                        if (i < 8) {
                                reviewDAO.save(new Review(a, ac1, 4F, Reviewtype.HUMAN));
                        }
                        if (i > 3) {
                                reviewDAO.save(new Review(a, ac2, 2F, Reviewtype.HUMAN));
                        }
                        if (i > 6 && i < 15) {
                                reviewDAO.save(new Review(a, ac3, 5F, Reviewtype.HUMAN));
                        }
                       
                        if (i == 5) {
                                aSearch = a;
                        }
                       
                        if (i > 15) {
                                break;
                        }
                       
                        i++;
                }
               
                List<Arrangement> recommendations =
arrangementService.getRecommendations(ac1, allReady, 10);

----------------------------
This gives me nothing.

Thanks!
/Johan



On Fri, Nov 27, 2009 at 2:24 AM, Sean Owen <[hidden email]> wrote:

> Yes, in order to recommend users to items, you just have to flip user
> IDs and item IDs. Then use whatever algorithm you want. Then you pass
> in item IDs, not user IDs, to recommend(). If you were passing item
> IDs, without flipping the two, that would be why things don't work.
>
> You are saying you flipped the values, and it works now. What is not
> working then -- are you just wondering why you saw no results in that
> one case?
>
> On Fri, Nov 27, 2009 at 1:19 AM, Johan Fredholm
> <[hidden email]> wrote:
>> Ok, sorry for being unclear.
>> I wrote at the end there in mail 1 "Running recommendations from
>> Account (User) doesn't return any
>> recommendations at all.". That's the userbased recommender. It didn't
>> throw any exceptions like the item-based recommender, but it also
>> didn't (and doesn't) return anything. I did flip the values in the
>> DataModel for the item-based recommender like you suggested, and it
>> now works. The DataModel for the user-based recommender is unchanged.
>> So in total for the user-based recommender the code now is:
>>
>
Reply | Threaded
Open this post in threaded view
|

Re: Mahout and DAO connection

Sean Owen
Just to be clear -- item-based recommenders have nothing to do with
switching around and recommending users to items. You talk about
remaking the DataModel for user-based recommendation, but, there's no
need to change the DataModel to switch between a user-based and
item-based algorithm. You switch up the users and item IDs to switch
*between recommending items to users and users to items*.

One key question is: are you passing account IDs to this recommender?
should be, since your user IDs are account IDs in this setup.

No recommendations may be 'correct'. I don't know, depends on the
data. Someone who doesn't have much data or isn't well connected might
get zero recommendations. And they might with a different algorithm.
So far, that sounds possibly correct.

On Fri, Nov 27, 2009 at 1:54 AM, Johan Fredholm
<[hidden email]> wrote:
> No I want both, (both user and item based recommendation) and the
> item-based recommender now works, but the user-based recommender
> returns nothing.
> I remade the DataModel for the _user-based_ recommender. Here it is>
>