/*
* This file is part of anycook. The new internet cookbook
* Copyright (C) 2014 Jan Graßegger
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see [http://www.gnu.org/licenses/].
*/
package de.anycook.recommendation;
import com.google.common.collect.SortedSetMultimap;
import com.google.common.collect.TreeMultimap;
import de.anycook.db.mysql.DBRecipe;
import de.anycook.db.mysql.DBRecommend;
import de.anycook.recipe.Recipe;
import de.anycook.utils.comparators.InvertedComparator;
import de.anycook.utils.comparators.StandardComparator;
import java.sql.SQLException;
import java.util.*;
public class Recommendation {
public static List<Recipe> recommend(int userId) throws SQLException {
try(DBRecommend dbrecommend = new DBRecommend()){
Map<String, Integer> tasteTags = dbrecommend.getTastyTags(userId);
Map<String, Collection<String>> recipes = dbrecommend.getRecipesByTags(userId);
//logger.debug("tagRecipes: "+tagRecipes);
// cos(a,b) = a*b/|a|*|b|
SortedSetMultimap<Double, String> recommendMap =
TreeMultimap.create(new InvertedComparator<Double>(), new StandardComparator<String>());
double schmecktAmount = 0;
for (String tag : tasteTags.keySet())
schmecktAmount += Math.pow(tasteTags.get(tag), 2);
schmecktAmount = Math.sqrt(schmecktAmount);
for (String tagRecipe : recipes.keySet()) {
double enumerator = 0;
Collection<String> tags = recipes.get(tagRecipe);
for (String tag : tags) {
if (!tasteTags.containsKey(tag)) continue;
enumerator += tasteTags.get(tag);
}
double denominator = schmecktAmount * Math.sqrt(tags.size());
double result = enumerator / denominator;
recommendMap.put(result, tagRecipe);
}
List<Recipe> finalRecipes = new ArrayList<>();
for(String name : recommendMap.values()){
try {
finalRecipes.add(Recipe.init(name));
} catch (DBRecipe.RecipeNotFoundException e) {
//will never happen
}
}
return finalRecipes;
}
}
public static List<Recipe> recommend(int userId, int num) throws SQLException {
return recommend(userId).subList(0, num);
}
}