boolean considerKnownItems,
IDRescorer rescorer) throws NoSuchUserException, NotReadyException {
Preconditions.checkArgument(howMany > 0, "howMany must be positive");
Generation generation = getCurrentGeneration();
FastByIDMap<float[]> X = generation.getX();
Lock xLock = generation.getXLock().readLock();
List<float[]> userFeatures = Lists.newArrayListWithCapacity(userIDs.length);
xLock.lock();
try {
for (long userID : userIDs) {
float[] theUserFeatures = X.get(userID);
if (theUserFeatures != null) {
userFeatures.add(theUserFeatures);
}
}
} finally {
xLock.unlock();
}
if (userFeatures.isEmpty()) {
throw new NoSuchUserException(Arrays.toString(userIDs));
}
FastByIDMap<FastIDSet> knownItemIDs = generation.getKnownItemIDs();
if (knownItemIDs == null && !considerKnownItems) {
throw new UnsupportedOperationException("Can't ignore known items because no known items available");
}
FastIDSet usersKnownItemIDs = null;
if (!considerKnownItems) {
Lock knownItemLock = generation.getKnownItemLock().readLock();
knownItemLock.lock();
try {
for (long userID : userIDs) {
FastIDSet theKnownItemIDs = knownItemIDs.get(userID);
if (theKnownItemIDs == null) {
continue;
}
if (usersKnownItemIDs == null) {
usersKnownItemIDs = theKnownItemIDs;
} else {
LongPrimitiveIterator it = usersKnownItemIDs.iterator();
while (it.hasNext()) {
if (!theKnownItemIDs.contains(it.nextLong())) {
it.remove();
}
}
}
if (usersKnownItemIDs.isEmpty()) {
break;
}
}
} finally {
knownItemLock.unlock();
}
}
float[][] userFeaturesArray = userFeatures.toArray(new float[userFeatures.size()][]);
Lock yLock = generation.getYLock().readLock();
yLock.lock();
try {
return multithreadedTopN(userFeaturesArray,
usersKnownItemIDs,
generation.getUserTagIDs(),
rescorer,
howMany,
generation.getCandidateFilter());
} finally {
yLock.unlock();
}
}