Join starred changes with other operators in Lucene

Express the starredby:X operator as an OR tree of each legacy ID the
user has starred.  We assume users star relatively few changes and
therefore the number of candidates that Lucene will need to lookup is
low.  Passing in the legacy IDs allows the starred table in the SQL
database to remain the source of truth, until we find a strong case
for users having hundreds of starred changes and needing to modify the
query processing.

Extending OrPredicate allows this operator to be seen by the query
rewriters and ChangeIndex as though the user had searched for the
specific ids, "(change:1 OR change:2 OR change:3)".

Change-Id: I2b8f85891c0f5266507eabd75f53bc1ad056f142
This commit is contained in:
Shawn Pearce
2013-06-25 23:36:28 -06:00
parent e39b40a265
commit 889126bc46
2 changed files with 30 additions and 7 deletions

View File

@@ -45,9 +45,6 @@ public class OrPredicate<T> extends Predicate<T> {
c += p.getCost();
}
}
if (t.size() < 2) {
throw new IllegalArgumentException("Need at least two predicates");
}
children = t;
cost = c;
}
@@ -101,7 +98,7 @@ public class OrPredicate<T> extends Predicate<T> {
}
@Override
public final String toString() {
public String toString() {
final StringBuilder r = new StringBuilder();
r.append("(");
for (int i = 0; i < getChildCount(); i++) {

View File

@@ -14,15 +14,21 @@
package com.google.gerrit.server.query.change;
import com.google.common.collect.Lists;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.query.OperatorPredicate;
import com.google.gerrit.server.query.OrPredicate;
import com.google.gerrit.server.query.Predicate;
import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.ResultSet;
import com.google.inject.Provider;
class IsStarredByPredicate extends OperatorPredicate<ChangeData> implements
import java.util.List;
import java.util.Set;
class IsStarredByPredicate extends OrPredicate<ChangeData> implements
ChangeDataSource {
private static String describe(CurrentUser user) {
if (user instanceof IdentifiedUser) {
@@ -31,11 +37,21 @@ class IsStarredByPredicate extends OperatorPredicate<ChangeData> implements
return user.toString();
}
private static List<Predicate<ChangeData>> predicates(
Provider<ReviewDb> db,
Set<Change.Id> ids) {
List<Predicate<ChangeData>> r = Lists.newArrayListWithCapacity(ids.size());
for (Change.Id id : ids) {
r.add(new LegacyChangeIdPredicate(db, id));
}
return r;
}
private final Provider<ReviewDb> db;
private final CurrentUser user;
IsStarredByPredicate(Provider<ReviewDb> db, CurrentUser user) {
super(ChangeQueryBuilder.FIELD_STARREDBY, describe(user));
super(predicates(db, user.getStarredChanges()));
this.db = db;
this.user = user;
}
@@ -65,4 +81,14 @@ class IsStarredByPredicate extends OperatorPredicate<ChangeData> implements
public int getCost() {
return ChangeCosts.cost(ChangeCosts.IDS_MEMORY, getCardinality());
}
@Override
public String toString() {
String val = describe(user);
if (val.indexOf(' ') < 0) {
return ChangeQueryBuilder.FIELD_STARREDBY + ":" + val;
} else {
return ChangeQueryBuilder.FIELD_STARREDBY + ":\"" + val + "\"";
}
}
}