/* TagRecommender: A framework to implement and evaluate algorithms for the recommendation of tags. Copyright (C) 2013 Dominik Kowald This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ package engine; import processing.BLLCalculator; import common.CooccurenceMatrix; import common.DoubleMapComparator; import common.Utilities; import file.BookmarkReader; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.TreeMap; public class BaseLevelLearningEngine implements EngineInterface { private BookmarkReader reader; private final Map<String, Map<Integer, Double>> userMaps; private final Map<String, Map<Integer, Double>> userCounts; private final Map<String, Map<Integer, Double>> resMaps; private final Map<String, Map<Integer, Double>> resCounts; private final Map<Integer, Double> topTags; private CooccurenceMatrix rMatrix; public BaseLevelLearningEngine() { userMaps = new HashMap<>(); userCounts = new HashMap<>(); resMaps = new HashMap<>(); resCounts = new HashMap<>(); topTags = new LinkedHashMap<>(); reader = null; } public void loadFile(String path, String filename) throws Exception { BookmarkReader reader = EngineUtils.getSortedBookmarkReader(path, filename); Map<String, Map<Integer, Double>> userMaps = new HashMap<>(); Map<String, Map<Integer, Double>> userCounts = new HashMap<>(); Map<String, Map<Integer, Double>> resMaps = new HashMap<>(); Map<String, Map<Integer, Double>> resCounts = new HashMap<>(); List<Map<Integer, Double>> userRecencies = BLLCalculator.getArtifactMaps(reader, reader.getBookmarks(), null, false, new ArrayList<Long>(), new ArrayList<Double>(), 0.5, true, null); List<Map<Integer, Double>> userFrequencies = Utilities.getRelativeTagMaps(reader.getBookmarks(), false); int i = 0; for (Map<Integer, Double> map : userRecencies) { userMaps.put(reader.getUsers().get(i++), map); } i = 0; for (Map<Integer, Double> map : userFrequencies) { userCounts.put(reader.getUsers().get(i++), map); } List<Map<Integer, Double>> resRecencies = BLLCalculator.getArtifactMaps(reader, reader.getBookmarks(), null, true, new ArrayList<Long>(), new ArrayList<Double>(), 0.0, true, null); List<Map<Integer, Double>> resFrequencies = Utilities.getRelativeTagMaps(reader.getBookmarks(), true); i = 0; for (Map<Integer, Double> map : resRecencies) { resMaps.put(reader.getResources().get(i++), map); } i = 0; for (Map<Integer, Double> map : resFrequencies) { resCounts.put(reader.getResources().get(i++), map); } Map<Integer, Double> topTags = EngineUtils.calcTopEntities(reader, EntityType.TAG); //System.out.println("calculate associative component for BLLac"); CooccurenceMatrix matrix = new CooccurenceMatrix(reader.getBookmarks(), reader.getTagCounts(), true); resetStructures(userMaps, resMaps, reader, topTags, matrix, userCounts, resCounts); } public synchronized Map<String, Double> getEntitiesWithLikelihood(String user, String resource, List<String> topics, Integer count, Boolean filterOwnEntities, Algorithm algorithm, EntityType type) { if (count == null || count.doubleValue() < 1) { count = 10; } Map<Integer, Double> userMap = this.userMaps.get(user); Map<Integer, Double> userCountMap = this.userCounts.get(user); if (filterOwnEntities == null) { filterOwnEntities = true; } List<Integer> filterTags = EngineUtils.getFilterTags(filterOwnEntities, this.reader, user, resource); // get personalized tag recommendations Map<Integer, Double> resultMap = new LinkedHashMap<Integer, Double>(); if (algorithm == null || algorithm != Algorithm.MP) { Map<Integer, Double> resMap = this.resMaps.get(resource); Map<Integer, Double> resCountMap = this.resCounts.get(resource); // user-based and resource-based if (userMap != null) { for (Map.Entry<Integer, Double> entry : userMap.entrySet()) { if (!filterTags.contains(entry.getKey())) { resultMap.put(entry.getKey(), entry.getValue().doubleValue()); } } if (resCountMap != null && (algorithm == null || algorithm == Algorithm.BLLac || algorithm == Algorithm.BLLacMPr)) { Map<Integer, Double> associativeValues = this.rMatrix.calculateAssociativeComponentsWithTagAssosiation(userCountMap, resCountMap, false, true, false); for (Map.Entry<Integer, Double> entry : associativeValues.entrySet()) { Double val = resultMap.get(entry.getKey()); if (!filterTags.contains(entry.getKey())) { resultMap.put(entry.getKey(), val == null ? entry.getValue().doubleValue() : val.doubleValue() + entry.getValue().doubleValue()); } } double denom = 0.0; for (Map.Entry<Integer, Double> entry : resultMap.entrySet()) { double val = Math.log(entry.getValue()); denom += Math.exp(val); } for (Map.Entry<Integer, Double> entry : resultMap.entrySet()) { entry.setValue(Math.exp(Math.log(entry.getValue())) / denom); } } } if ((algorithm == null || algorithm == Algorithm.BLLacMPr) && resMap != null) { for (Map.Entry<Integer, Double> entry : resMap.entrySet()) { if (!filterTags.contains(entry.getKey())) { double resVal = entry.getValue().doubleValue(); Double val = resultMap.get(entry.getKey()); resultMap.put(entry.getKey(), val == null ? resVal : val.doubleValue() + resVal); } } } } // add MP tags if necessary if (resultMap.size() < count) { for (Map.Entry<Integer, Double> t : this.topTags.entrySet()) { if (resultMap.size() < count) { if (!resultMap.containsKey(t.getKey()) && !filterTags.contains(t.getKey())) { resultMap.put(t.getKey(), t.getValue()); } } else { break; } } } // sort Map<Integer, Double> sortedResultMap = new TreeMap<Integer, Double>(new DoubleMapComparator(resultMap)); sortedResultMap.putAll(resultMap); // map tag-ids back to strings Map<String, Double> tagMap = new LinkedHashMap<>(); int i = 0; for (Map.Entry<Integer, Double> entry : sortedResultMap.entrySet()) { if (i++ < count) { tagMap.put(this.reader.getTags().get(entry.getKey()), (double) entry.getValue()); } else { break; } } return tagMap; } private synchronized void resetStructures(Map<String, Map<Integer, Double>> userMaps, Map<String, Map<Integer, Double>> resMaps, BookmarkReader reader, Map<Integer, Double> topTags, CooccurenceMatrix matrix, Map<String, Map<Integer, Double>> userCounts, Map<String, Map<Integer, Double>> resCounts) { this.reader = reader; this.userMaps.clear(); this.userMaps.putAll(userMaps); this.userCounts.clear(); this.userCounts.putAll(userCounts); this.resMaps.clear(); this.resMaps.putAll(resMaps); this.resCounts.clear(); this.resCounts.putAll(resCounts); this.topTags.clear(); this.topTags.putAll(topTags); this.rMatrix = matrix; } }