use of com.google.gerrit.server.change.SuggestedReviewer in project gerrit by GerritCodeReview.
the class ReviewerRecommender method suggestReviewers.
public List<Account.Id> suggestReviewers(ChangeNotes changeNotes, SuggestReviewers suggestReviewers, ProjectControl projectControl, List<Account.Id> candidateList) throws OrmException {
String query = suggestReviewers.getQuery();
double baseWeight = config.getInt("addReviewer", "baseWeight", 1);
Map<Account.Id, MutableDouble> reviewerScores;
if (Strings.isNullOrEmpty(query)) {
reviewerScores = baseRankingForEmptyQuery(baseWeight);
} else {
reviewerScores = baseRankingForCandidateList(candidateList, projectControl, baseWeight);
}
// Send the query along with a candidate list to all plugins and merge the
// results. Plugins don't necessarily need to use the candidates list, they
// can also return non-candidate account ids.
List<Callable<Set<SuggestedReviewer>>> tasks = new ArrayList<>(reviewerSuggestionPluginMap.plugins().size());
List<Double> weights = new ArrayList<>(reviewerSuggestionPluginMap.plugins().size());
for (DynamicMap.Entry<ReviewerSuggestion> plugin : reviewerSuggestionPluginMap) {
tasks.add(() -> plugin.getProvider().get().suggestReviewers(projectControl.getProject().getNameKey(), changeNotes.getChangeId(), query, reviewerScores.keySet()));
String pluginWeight = config.getString("addReviewer", plugin.getPluginName() + "-" + plugin.getExportName(), "weight");
if (Strings.isNullOrEmpty(pluginWeight)) {
pluginWeight = "1";
}
try {
weights.add(Double.parseDouble(pluginWeight));
} catch (NumberFormatException e) {
log.error("Exception while parsing weight for " + plugin.getPluginName() + "-" + plugin.getExportName(), e);
weights.add(1d);
}
}
try {
List<Future<Set<SuggestedReviewer>>> futures = workQueue.getDefaultQueue().invokeAll(tasks, PLUGIN_QUERY_TIMEOUT, TimeUnit.MILLISECONDS);
Iterator<Double> weightIterator = weights.iterator();
for (Future<Set<SuggestedReviewer>> f : futures) {
double weight = weightIterator.next();
for (SuggestedReviewer s : f.get()) {
if (reviewerScores.containsKey(s.account)) {
reviewerScores.get(s.account).add(s.score * weight);
} else {
reviewerScores.put(s.account, new MutableDouble(s.score * weight));
}
}
}
} catch (ExecutionException | InterruptedException e) {
log.error("Exception while suggesting reviewers", e);
return ImmutableList.of();
}
if (changeNotes != null) {
// Remove change owner
reviewerScores.remove(changeNotes.getChange().getOwner());
// Remove existing reviewers
reviewerScores.keySet().removeAll(approvalsUtil.getReviewers(dbProvider.get(), changeNotes).byState(REVIEWER));
}
// Sort results
Stream<Entry<Account.Id, MutableDouble>> sorted = reviewerScores.entrySet().stream().sorted(Collections.reverseOrder(Map.Entry.comparingByValue()));
List<Account.Id> sortedSuggestions = sorted.map(Map.Entry::getKey).collect(toList());
return sortedSuggestions;
}
use of com.google.gerrit.server.change.SuggestedReviewer in project gerrit by GerritCodeReview.
the class ReviewerRecommender method suggestReviewers.
public List<Account.Id> suggestReviewers(ReviewerState reviewerState, @Nullable ChangeNotes changeNotes, SuggestReviewers suggestReviewers, ProjectState projectState, List<Account.Id> candidateList) throws IOException, ConfigInvalidException {
logger.atFine().log("Candidates %s", candidateList);
String query = suggestReviewers.getQuery();
logger.atFine().log("query: %s", query);
double baseWeight = config.getInt("addReviewer", "baseWeight", 1);
logger.atFine().log("base weight: %s", baseWeight);
Map<Account.Id, MutableDouble> reviewerScores = baseRanking(baseWeight, query, candidateList);
logger.atFine().log("Base reviewer scores: %s", reviewerScores);
// Send the query along with a candidate list to all plugins and merge the
// results. Plugins don't necessarily need to use the candidates list, they
// can also return non-candidate account ids.
List<Callable<Set<SuggestedReviewer>>> tasks = new ArrayList<>(reviewerSuggestionPluginMap.plugins().size());
List<Double> weights = new ArrayList<>(reviewerSuggestionPluginMap.plugins().size());
reviewerSuggestionPluginMap.runEach(extension -> {
tasks.add(() -> extension.get().suggestReviewers(projectState.getNameKey(), changeNotes != null ? changeNotes.getChangeId() : null, query, reviewerScores.keySet()));
String key = extension.getPluginName() + "-" + extension.getExportName();
String pluginWeight = config.getString("addReviewer", key, "weight");
if (Strings.isNullOrEmpty(pluginWeight)) {
pluginWeight = "1";
}
logger.atFine().log("weight for %s: %s", key, pluginWeight);
try {
weights.add(Double.parseDouble(pluginWeight));
} catch (NumberFormatException e) {
logger.atSevere().withCause(e).log("Exception while parsing weight for %s", key);
weights.add(1d);
}
});
try {
List<Future<Set<SuggestedReviewer>>> futures = executor.invokeAll(tasks, PLUGIN_QUERY_TIMEOUT, TimeUnit.MILLISECONDS);
Iterator<Double> weightIterator = weights.iterator();
for (Future<Set<SuggestedReviewer>> f : futures) {
double weight = weightIterator.next();
for (SuggestedReviewer s : f.get()) {
if (reviewerScores.containsKey(s.account)) {
reviewerScores.get(s.account).add(s.score * weight);
} else {
reviewerScores.put(s.account, new MutableDouble(s.score * weight));
}
}
}
logger.atFine().log("Reviewer scores: %s", reviewerScores);
} catch (ExecutionException | InterruptedException e) {
logger.atSevere().withCause(e).log("Exception while suggesting reviewers");
return ImmutableList.of();
}
if (changeNotes != null) {
// Remove change owner
if (reviewerScores.remove(changeNotes.getChange().getOwner()) != null) {
logger.atFine().log("Remove change owner %s", changeNotes.getChange().getOwner());
}
// Remove existing reviewers
approvalsUtil.getReviewers(changeNotes).byState(ReviewerStateInternal.fromReviewerState(reviewerState)).forEach(r -> {
if (reviewerScores.remove(r) != null) {
logger.atFine().log("Remove existing reviewer %s", r);
}
});
}
// Sort results
Stream<Map.Entry<Account.Id, MutableDouble>> sorted = reviewerScores.entrySet().stream().sorted(Map.Entry.comparingByValue(Collections.reverseOrder()));
List<Account.Id> sortedSuggestions = sorted.map(Map.Entry::getKey).collect(toList());
logger.atFine().log("Sorted suggestions: %s", sortedSuggestions);
return sortedSuggestions;
}
Aggregations