@Override protected FastIDSet doGetCandidateItems(long[] preferredItemIDs, DataModel dataModel) throws TasteException { FastIDSet candidateItemIDs = new FastIDSet(); for (long itemID : preferredItemIDs) { candidateItemIDs.addAll(similarity.allSimilarItemIDs(itemID)); } candidateItemIDs.removeAll(preferredItemIDs); return candidateItemIDs; } }
public boolean retainAll(FastIDSet c) { boolean changed = false; for (int i = 0; i < keys.length; i++) { long k = keys[i]; if (k != NULL && k != REMOVED && !c.contains(k)) { keys[i] = REMOVED; numEntries--; changed = true; } } return changed; }
/** * This exists because FastIDSet has 'retainAll' as MASK, but there is * no count of the number of items in the set. size() is supposed to do * this but does not work. */ private static int mask(FastIDSet commonSet, FastIDSet otherSet, long maxItemID) { int count = 0; for (int i = 0; i <= maxItemID; i++) { if (commonSet.contains(i)) { if (otherSet.contains(i)) { count++; } else { commonSet.remove(i); } } } return count; }
@Override public List<RecommendedItem> recommendedBecause(long userID, long itemID, int howMany) throws TasteException { Preconditions.checkArgument(howMany >= 1, "howMany must be at least 1"); DataModel model = getDataModel(); TopItems.Estimator<Long> estimator = new RecommendedBecauseEstimator(userID, itemID); PreferenceArray prefs = model.getPreferencesFromUser(userID); int size = prefs.length(); FastIDSet allUserItems = new FastIDSet(size); for (int i = 0; i < size; i++) { allUserItems.add(prefs.getItemID(i)); } allUserItems.remove(itemID); return TopItems.getTopItems(howMany, allUserItems.iterator(), null, estimator); }
private void addSomeOf(FastIDSet possibleItemIDs, FastIDSet itemIDs) { if (itemIDs.size() > maxItemsPerUser) { LongPrimitiveIterator it = new SamplingLongPrimitiveIterator(itemIDs.iterator(), (double) maxItemsPerUser / itemIDs.size()); while (it.hasNext()) { possibleItemIDs.add(it.nextLong()); } } else { possibleItemIDs.addAll(itemIDs); } }
@Override public int getNumUsersWithPreferenceFor(long itemID1, long itemID2) { FastIDSet userIDs1 = preferenceForItems.get(itemID1); if (userIDs1 == null) { return 0; } FastIDSet userIDs2 = preferenceForItems.get(itemID2); if (userIDs2 == null) { return 0; } return userIDs1.size() < userIDs2.size() ? userIDs2.intersectionSize(userIDs1) : userIDs1.intersectionSize(userIDs2); }
public boolean add(long key) { Preconditions.checkArgument(key != NULL && key != REMOVED); // If less than half the slots are open, let's clear it up if (numSlotsUsed * loadFactor >= keys.length) { // If over half the slots used are actual entries, let's grow if (numEntries * loadFactor >= numSlotsUsed) { growAndRehash(); } else { // Otherwise just rehash to clear REMOVED entries and don't grow rehash(); } } // Here we may later consider implementing Brent's variation described on page 532 int index = findForAdd(key); long keyIndex = keys[index]; if (keyIndex != key) { keys[index] = key; numEntries++; if (keyIndex == NULL) { numSlotsUsed++; } return true; } return false; }
public static FastIDSet[] parseMenWomen(File genderFile) throws IOException { FastIDSet men = new FastIDSet(50000); FastIDSet women = new FastIDSet(50000); for (String line : new FileLineIterable(genderFile)) { int comma = line.indexOf(','); char gender = line.charAt(comma + 1); if (gender == 'U') { continue; } long profileID = Long.parseLong(line.substring(0, comma)); if (gender == 'M') { men.add(profileID); } else { women.add(profileID); } } men.rehash(); women.rehash(); return new FastIDSet[] { men, women }; }
@Override public long[] allSimilarItemIDs(long itemID) throws TasteException { FastIDSet allSimilarItemIDs = new FastIDSet(); LongPrimitiveIterator allItemIDs = dataModel.getItemIDs(); while (allItemIDs.hasNext()) { long possiblySimilarItemID = allItemIDs.nextLong(); if (!Double.isNaN(itemSimilarity(itemID, possiblySimilarItemID))) { allSimilarItemIDs.add(possiblySimilarItemID); } } return allSimilarItemIDs.toArray(); }
public static DataModel getBooleanDataModel(long[] userIDs, boolean[][] prefs) { FastByIDMap<FastIDSet> result = new FastByIDMap<FastIDSet>(); for (int i = 0; i < userIDs.length; i++) { FastIDSet prefsSet = new FastIDSet(); for (int j = 0; j < prefs[i].length; j++) { if (prefs[i][j]) { prefsSet.add(j); } } if (!prefsSet.isEmpty()) { result.put(userIDs[i], prefsSet); } } return new GenericBooleanPrefDataModel(result); }
@Test public void testUserItemFilter() throws Exception { Configuration conf = getConfiguration(); IDReader idReader = new IDReader(conf); Map<Long, FastIDSet> userItemFilter = Maps.newHashMap(); long user1 = 1; long user2 = 2; idReader.addUserAndItemIdToUserItemFilter(userItemFilter, user1, 100L); idReader.addUserAndItemIdToUserItemFilter(userItemFilter, user1, 200L); idReader.addUserAndItemIdToUserItemFilter(userItemFilter, user2, 300L); FastIDSet userIds = IDReader.extractAllUserIdsFromUserItemFilter(userItemFilter); assertEquals(2, userIds.size()); assertTrue(userIds.contains(user1)); assertTrue(userIds.contains(user1)); setField(idReader, USER_ITEM_FILTER_FIELD, userItemFilter); FastIDSet itemsForUser1 = idReader.getItemsToRecommendForUser(user1); assertEquals(2, itemsForUser1.size()); assertTrue(itemsForUser1.contains(100L)); assertTrue(itemsForUser1.contains(200L)); FastIDSet itemsForUser2 = idReader.getItemsToRecommendForUser(user2); assertEquals(1, itemsForUser2.size()); assertTrue(itemsForUser2.contains(300L)); FastIDSet itemsForNonExistingUser = idReader.getItemsToRecommendForUser(3L); assertTrue(itemsForNonExistingUser.isEmpty()); }
@Override public List<RecommendedItem> recommend(long userID, int howMany, IDRescorer rescorer) throws TasteException { Preconditions.checkArgument(howMany >= 1, "howMany must be at least 1"); log.debug("Recommending items for user ID '{}'", userID); PreferenceArray preferencesFromUser = getDataModel().getPreferencesFromUser(userID); FastIDSet possibleItemIDs = getAllOtherItems(userID, preferencesFromUser); TopItems.Estimator<Long> estimator = new Estimator(userID); List<RecommendedItem> topItems = TopItems.getTopItems(howMany, possibleItemIDs.iterator(), rescorer, estimator); log.debug("Recommendations are: {}", topItems); return topItems; }
private void growAndRehash() { if (keys.length * loadFactor >= RandomUtils.MAX_INT_SMALLER_TWIN_PRIME) { throw new IllegalStateException("Can't grow any more"); } rehash(RandomUtils.nextTwinPrime((int) (loadFactor * keys.length))); }