import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.util.HashMap; import java.util.List; import org.apache.mahout.cf.taste.common.TasteException; import org.apache.mahout.cf.taste.eval.RecommenderBuilder; import org.apache.mahout.cf.taste.eval.RecommenderEvaluator; import org.apache.mahout.cf.taste.impl.common.FastByIDMap; import org.apache.mahout.cf.taste.impl.eval.AverageAbsoluteDifferenceRecommenderEvaluator; import org.apache.mahout.cf.taste.impl.model.GenericDataModel; import org.apache.mahout.cf.taste.impl.model.GenericUserPreferenceArray; import org.apache.mahout.cf.taste.impl.model.file.FileDataModel; import org.apache.mahout.cf.taste.impl.neighborhood.ThresholdUserNeighborhood; import org.apache.mahout.cf.taste.impl.recommender.GenericItemBasedRecommender; import org.apache.mahout.cf.taste.impl.recommender.GenericUserBasedRecommender; import org.apache.mahout.cf.taste.impl.similarity.PearsonCorrelationSimilarity; import org.apache.mahout.cf.taste.model.DataModel; import org.apache.mahout.cf.taste.model.Preference; import org.apache.mahout.cf.taste.model.PreferenceArray; import org.apache.mahout.cf.taste.neighborhood.UserNeighborhood; import org.apache.mahout.cf.taste.recommender.IDRescorer; import org.apache.mahout.cf.taste.recommender.ItemBasedRecommender; import org.apache.mahout.cf.taste.recommender.RecommendedItem; import org.apache.mahout.cf.taste.recommender.Recommender; import org.apache.mahout.cf.taste.recommender.UserBasedRecommender; import org.apache.mahout.cf.taste.similarity.ItemSimilarity; import org.apache.mahout.cf.taste.similarity.UserSimilarity; import org.apache.mahout.cf.taste.impl.model.jdbc.MySQLJDBCDataModel; import com.mysql.jdbc.jdbc2.optional.MysqlDataSource; /** * Hello world! * */ public class BookRecommender implements RecommenderBuilder { static HashMap<String, String> books; public static void main(String[] args) throws Exception { books = loadBooks("data/BX-Books.csv"); itemBased(); // userBased(); evaluateRecommender(); } public static HashMap<String, String> loadBooks(String filename) throws Exception { HashMap<String, String> map = new HashMap<String, String>(); BufferedReader in = new BufferedReader(new FileReader(filename)); String line = ""; while ((line = in.readLine()) != null) { String parts[] = line.replace("\"", "").split(";"); map.put(parts[0], parts[1]); } in.close(); // System.out.println(map.toString()); System.out.println("Total items: " + map.size()); return map; } public static ItemBasedRecommender itemBased() throws Exception { // Load the data StringItemIdFileDataModel dataModel = loadFromFile("data/BX-Book-Ratings.csv", ";"); // Collection<GenericItemSimilarity.ItemItemSimilarity> correlations = // null; // ItemItemSimilarity iis = new ItemItemSimilarity(0, 0, 0); // ItemSimilarity itemSimilarity = new // GenericItemSimilarity(correlations); ItemSimilarity itemSimilarity = new PearsonCorrelationSimilarity(dataModel); ItemBasedRecommender recommender = new GenericItemBasedRecommender( dataModel, itemSimilarity); IDRescorer rescorer = new MyRescorer(); // List recommendations = recommender.recommend(2, 3, rescorer); String itemISBN = "042513976X"; long itemID = dataModel.readItemIDFromString(itemISBN); int noItems = 10; System.out.println("Recommendations for item: " + books.get(itemISBN)); System.out.println("\nMost similar items:"); List<RecommendedItem> recommendations = recommender.mostSimilarItems( itemID, noItems); for (RecommendedItem item : recommendations) { itemISBN = dataModel.getItemIDAsString(item.getItemID()); System.out.println("Item: " + books.get(itemISBN) + " | Item id: " + itemISBN + " | Value: " + item.getValue()); } return recommender; } public static void userBased() throws Exception { StringItemIdFileDataModel model = loadFromFile("data/BX-Book-Ratings.csv",";"); UserSimilarity similarity = new PearsonCorrelationSimilarity(model); UserNeighborhood neighborhood = new ThresholdUserNeighborhood(0.1, similarity, model); UserBasedRecommender recommender = new GenericUserBasedRecommender(model, neighborhood, similarity); IDRescorer rescorer = new MyRescorer(); // List recommendations = recommender.recommend(2, 3, rescorer); long userID = 276704;// 276704;//212124;//277157; int noItems = 10; System.out.println("Rated items:"); for (Preference preference : model.getPreferencesFromUser(userID)) { String itemISBN = model.getItemIDAsString(preference.getItemID()); System.out.println("Item: " + books.get(itemISBN) + " | Item id: " + itemISBN + " | Value: " + preference.getValue()); } System.out.println("\nRecommended items:"); List<RecommendedItem> recommendations = recommender.recommend(userID, noItems); for (RecommendedItem item : recommendations) { String itemISBN = model.getItemIDAsString(item.getItemID()); System.out.println("Item: " + books.get(itemISBN) + " | Item id: " + itemISBN + " | Value: " + item.getValue()); } } public static StringItemIdFileDataModel loadFromFile(String filePath, String seperator) throws Exception{ StringItemIdFileDataModel dataModel = new StringItemIdFileDataModel( new File(filePath), seperator); return dataModel; } public static DataModel loadFromFile(String filePath) throws IOException{ // File-based DataModel - FileDataModel DataModel dataModel = new FileDataModel(new File("preferences.csv")); return dataModel; } public static DataModel loadFromDB() throws Exception { // Database-based DataModel - MySQLJDBCDataModel /* * A JDBCDataModel backed by a PostgreSQL database and accessed via * JDBC. It may work with other JDBC databases. By default, this class * assumes that there is a DataSource available under the JNDI name * "jdbc/taste", which gives access to a database with a * "taste_preferences" table with the following schema: CREATE TABLE * taste_preferences ( user_id BIGINT NOT NULL, item_id BIGINT NOT NULL, * preference REAL NOT NULL, PRIMARY KEY (user_id, item_id) ) CREATE * INDEX taste_preferences_user_id_index ON taste_preferences (user_id); * CREATE INDEX taste_preferences_item_id_index ON taste_preferences * (item_id); */ MysqlDataSource dbsource = new MysqlDataSource(); dbsource.setUser("user"); dbsource.setPassword("pass"); dbsource.setServerName("localhost"); dbsource.setDatabaseName("my_db"); DataModel dataModelDB = new MySQLJDBCDataModel(dbsource, "taste_preferences", "user_id", "item_id", "preference", "timestamp"); return dataModelDB; } public DataModel loadInMemory() { // In-memory DataModel - GenericDataModels FastByIDMap<PreferenceArray> preferences = new FastByIDMap<PreferenceArray>(); PreferenceArray prefsForUser1 = new GenericUserPreferenceArray(10); prefsForUser1.setUserID(0, 1L); prefsForUser1.setItemID(0, 101L); prefsForUser1.setValue(0, 3.0f); prefsForUser1.setItemID(1, 102L); prefsForUser1.setValue(1, 4.5F); preferences.put(1L, prefsForUser1); // use userID as the key //TODO: add others users // Return preferences as new data model DataModel dataModel = new GenericDataModel(preferences); return dataModel; } public static void evaluateRecommender() throws Exception{ StringItemIdFileDataModel dataModel = loadFromFile("data/BX-Book-Ratings.csv",";"); RecommenderEvaluator evaluator = new AverageAbsoluteDifferenceRecommenderEvaluator(); RecommenderBuilder builder = new BookRecommender(); double result = evaluator.evaluate(builder, null, dataModel, 0.9, 1.0); System.out.println(result); } public Recommender buildRecommender(DataModel arg0) { try { return BookRecommender.itemBased(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } }