public List<RecommendedItem> recommendedBecause(long userID, long itemID, int howMany)
throws NoSuchUserException, NoSuchItemException, NotReadyException {
Preconditions.checkArgument(howMany > 0, "howMany must be positive");
Generation generation = getCurrentGeneration();
FastByIDMap<FastIDSet> knownItemIDs = generation.getKnownItemIDs();
if (knownItemIDs == null) {
throw new UnsupportedOperationException("No known item IDs available");
}
Lock knownItemLock = generation.getKnownItemLock().readLock();
FastIDSet userKnownItemIDs;
knownItemLock.lock();
try {
userKnownItemIDs = knownItemIDs.get(userID);
} finally {
knownItemLock.unlock();
}
if (userKnownItemIDs == null) {
throw new NoSuchUserException(userID);
}
FastByIDMap<float[]> Y = generation.getY();
Lock yLock = generation.getYLock().readLock();
yLock.lock();
try {
float[] features = Y.get(itemID);
if (features == null) {
throw new NoSuchItemException(itemID);
}
FastByIDMap<float[]> toFeatures;
synchronized (userKnownItemIDs) {
toFeatures = new FastByIDMap<float[]>(userKnownItemIDs.size());
LongPrimitiveIterator it = userKnownItemIDs.iterator();
while (it.hasNext()) {
long fromItemID = it.nextLong();
float[] fromFeatures = Y.get(fromItemID);
toFeatures.put(fromItemID, fromFeatures);
}
}
return TopN.selectTopN(new RecommendedBecauseIterator(toFeatures.entrySet().iterator(),
generation.getUserTagIDs(),
features),
howMany);
} finally {
yLock.unlock();
}