001/*-------------------------------------------------------------------------+
002 |                                                                          |
003 | Copyright 2005-2011 the ConQAT Project                                   |
004 |                                                                          |
005 | Licensed under the Apache License, Version 2.0 (the "License");          |
006 | you may not use this file except in compliance with the License.         |
007 | You may obtain a copy of the License at                                  |
008 |                                                                          |
009 |    http://www.apache.org/licenses/LICENSE-2.0                            |
010 |                                                                          |
011 | Unless required by applicable law or agreed to in writing, software      |
012 | distributed under the License is distributed on an "AS IS" BASIS,        |
013 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
014 | See the License for the specific language governing permissions and      |
015 | limitations under the License.                                           |
016 +-------------------------------------------------------------------------*/
017package org.conqat.lib.commons.datamining;
018
019import java.io.Serializable;
020import java.util.HashMap;
021import java.util.HashSet;
022import java.util.Map;
023import java.util.Set;
024
025/**
026 * Based on a set of association rules, this recommender can recommend items for
027 * a given basket.
028 */
029public class AssociationRuleRecommender<T> implements IRecommender<T>, Serializable {
030
031        /** Serial ID */
032        private static final long serialVersionUID = 1L;
033        /** The database containing the ratings. */
034        private final RecommenderRatingDatabase<T> ratingDatabase;
035        /** The mined association rules */
036        private final Set<AssociationRule<T>> associationRules;
037
038        /** Constructor. */
039        public AssociationRuleRecommender(RecommenderRatingDatabase<T> ratingDatabase, float supportThreshold,
040                        float confidenceThreshold) {
041                this.ratingDatabase = ratingDatabase;
042                Set<Set<T>> baskets = new HashSet<Set<T>>();
043                for (IRecommenderUser user : ratingDatabase.getUsers()) {
044                        baskets.add(ratingDatabase.getLikedItems(user));
045                }
046                associationRules = new AssociationRuleMiner<T>(supportThreshold, confidenceThreshold)
047                                .mineAssociationRules(baskets);
048        }
049
050        /**
051         * Recommends items for the given user. The returned set may be empty, if no
052         * recommendations could be made.
053         */
054        @Override
055        public Set<Recommendation<T>> recommend(IRecommenderUser user) {
056
057                Map<T, Recommendation<T>> itemToRecommendationMap = new HashMap<T, Recommendation<T>>();
058                Set<T> items = ratingDatabase.getLikedItems(user);
059
060                for (AssociationRule<T> rule : associationRules) {
061                        if (items.containsAll(rule.getItemSet()) && !items.contains(rule.getAssociatedItem())) {
062                                T item = rule.getAssociatedItem();
063                                double confidence = rule.getConfidence();
064
065                                Recommendation<T> existingRecommendation = itemToRecommendationMap.get(item);
066
067                                if (existingRecommendation == null || confidence > existingRecommendation.getConfidence()) {
068                                        itemToRecommendationMap.put(item, new Recommendation<T>(item, confidence));
069                                }
070                        }
071                }
072                return new HashSet<Recommendation<T>>(itemToRecommendationMap.values());
073        }
074
075}