Exactly index sortkey with Lucene
Store sortkey as a long and implement the before and after operators as numeric range queries. This is a short-term hack until we have a better idea of how to handle pagination without relying on a made up string value stored on the change object. Change-Id: Ibf7a8be281da8cd9e7ccc08bba600bbc2e0e962c
This commit is contained in:
@@ -44,6 +44,7 @@ import com.google.gerrit.server.query.QueryParseException;
|
||||
import com.google.gerrit.server.query.change.ChangeData;
|
||||
import com.google.gerrit.server.query.change.ChangeDataSource;
|
||||
import com.google.gerrit.server.query.change.IndexRewriteImpl;
|
||||
import com.google.gerrit.server.query.change.SortKeyPredicate;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
import com.google.gwtorm.server.ResultSet;
|
||||
|
||||
@@ -52,6 +53,7 @@ import org.apache.lucene.document.Document;
|
||||
import org.apache.lucene.document.Field;
|
||||
import org.apache.lucene.document.Field.Store;
|
||||
import org.apache.lucene.document.IntField;
|
||||
import org.apache.lucene.document.LongField;
|
||||
import org.apache.lucene.document.StringField;
|
||||
import org.apache.lucene.index.IndexWriter;
|
||||
import org.apache.lucene.index.IndexWriterConfig;
|
||||
@@ -261,6 +263,8 @@ public class LuceneChangeIndex implements ChangeIndex, LifecycleListener {
|
||||
return exactQuery(p);
|
||||
} else if (p.getType() == FieldType.PREFIX) {
|
||||
return prefixQuery(p);
|
||||
} else if (p instanceof SortKeyPredicate) {
|
||||
return sortKeyQuery((SortKeyPredicate) p);
|
||||
} else {
|
||||
throw badFieldType(p.getType());
|
||||
}
|
||||
@@ -285,6 +289,14 @@ public class LuceneChangeIndex implements ChangeIndex, LifecycleListener {
|
||||
return new TermQuery(intTerm(p.getOperator(), value));
|
||||
}
|
||||
|
||||
private static Query sortKeyQuery(SortKeyPredicate p) {
|
||||
return NumericRangeQuery.newLongRange(
|
||||
p.getField().getName(),
|
||||
p.getMinValue(),
|
||||
p.getMaxValue(),
|
||||
true, true);
|
||||
}
|
||||
|
||||
private static Query timestampQuery(IndexPredicate<ChangeData> p)
|
||||
throws QueryParseException {
|
||||
if (p instanceof TimestampRangePredicate) {
|
||||
@@ -442,6 +454,10 @@ public class LuceneChangeIndex implements ChangeIndex, LifecycleListener {
|
||||
for (Object value : values) {
|
||||
doc.add(new IntField(name, (Integer) value, store));
|
||||
}
|
||||
} else if (f.getType() == FieldType.LONG) {
|
||||
for (Object value : values) {
|
||||
doc.add(new LongField(name, (Long) value, store));
|
||||
}
|
||||
} else if (f.getType() == FieldType.TIMESTAMP) {
|
||||
for (Object v : values) {
|
||||
doc.add(new IntField(name, toIndexTime((Timestamp) v), store));
|
||||
|
||||
@@ -450,16 +450,15 @@ public class ChangeUtil {
|
||||
return r.toString();
|
||||
}
|
||||
|
||||
public static Timestamp timeFromSortKey(String sortKey) {
|
||||
public static long parseSortKey(String sortKey) {
|
||||
if ("z".equals(sortKey)) {
|
||||
return new Timestamp(Long.MAX_VALUE);
|
||||
return Long.MAX_VALUE;
|
||||
}
|
||||
String ts = sortKey.substring(0, 8);
|
||||
int i = 0;
|
||||
while (i < 8 && ts.charAt(i) == '0')
|
||||
i++;
|
||||
long v = Long.parseLong(ts.substring(i), 16) * 60;
|
||||
return new Timestamp((v + SORT_KEY_EPOCH) * 1000);
|
||||
return Long.parseLong(ts.substring(i), 16);
|
||||
}
|
||||
|
||||
public static void computeSortKey(final Change c) {
|
||||
|
||||
@@ -19,6 +19,7 @@ import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.gerrit.reviewdb.client.PatchSetApproval;
|
||||
import com.google.gerrit.reviewdb.client.PatchSet;
|
||||
import com.google.gerrit.server.ChangeUtil;
|
||||
import com.google.gerrit.server.query.change.ChangeData;
|
||||
import com.google.gerrit.server.query.change.ChangeQueryBuilder;
|
||||
import com.google.gerrit.server.query.change.ChangeStatusPredicate;
|
||||
@@ -43,7 +44,7 @@ import java.util.Set;
|
||||
*/
|
||||
public class ChangeField {
|
||||
/** Increment whenever making schema changes. */
|
||||
public static final int SCHEMA_VERSION = 5;
|
||||
public static final int SCHEMA_VERSION = 6;
|
||||
|
||||
/** Legacy change ID. */
|
||||
public static final FieldDef<ChangeData, Integer> CHANGE_ID =
|
||||
@@ -111,6 +112,18 @@ public class ChangeField {
|
||||
}
|
||||
};
|
||||
|
||||
/** Sort key field, duplicates {@link #UPDATED}. */
|
||||
@Deprecated
|
||||
public static final FieldDef<ChangeData, Long> SORTKEY =
|
||||
new FieldDef.Single<ChangeData, Long>(
|
||||
"sortkey", FieldType.LONG, true) {
|
||||
@Override
|
||||
public Long get(ChangeData input, FillArgs args)
|
||||
throws OrmException {
|
||||
return ChangeUtil.parseSortKey(input.change(args.db).getSortKey());
|
||||
}
|
||||
};
|
||||
|
||||
/** List of filenames modified in the current patch set. */
|
||||
public static final FieldDef<ChangeData, Iterable<String>> FILE =
|
||||
new FieldDef.Repeatable<ChangeData, String>(
|
||||
|
||||
@@ -23,6 +23,10 @@ public class FieldType<T> {
|
||||
public static final FieldType<Integer> INTEGER =
|
||||
new FieldType<Integer>("INTEGER");
|
||||
|
||||
/** A single integer-valued field. */
|
||||
public static final FieldType<Long> LONG =
|
||||
new FieldType<Long>("LONG");
|
||||
|
||||
/** A single date/time-valued field. */
|
||||
public static final FieldType<Timestamp> TIMESTAMP =
|
||||
new FieldType<Timestamp>("TIMESTAMP");
|
||||
|
||||
@@ -18,18 +18,15 @@ import com.google.gerrit.reviewdb.client.Change;
|
||||
import com.google.gerrit.reviewdb.server.ReviewDb;
|
||||
import com.google.gerrit.server.ChangeUtil;
|
||||
import com.google.gerrit.server.index.ChangeField;
|
||||
import com.google.gerrit.server.index.TimestampRangePredicate;
|
||||
import com.google.gerrit.server.index.IndexPredicate;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
import com.google.inject.Provider;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
|
||||
public abstract class SortKeyPredicate extends
|
||||
TimestampRangePredicate<ChangeData> {
|
||||
public abstract class SortKeyPredicate extends IndexPredicate<ChangeData> {
|
||||
protected final Provider<ReviewDb> dbProvider;
|
||||
|
||||
SortKeyPredicate(Provider<ReviewDb> dbProvider, String name, String value) {
|
||||
super(ChangeField.UPDATED, name, value);
|
||||
super(ChangeField.SORTKEY, name, value);
|
||||
this.dbProvider = dbProvider;
|
||||
}
|
||||
|
||||
@@ -38,19 +35,22 @@ public abstract class SortKeyPredicate extends
|
||||
return 1;
|
||||
}
|
||||
|
||||
public abstract long getMinValue();
|
||||
public abstract long getMaxValue();
|
||||
|
||||
public static class Before extends SortKeyPredicate {
|
||||
Before(Provider<ReviewDb> dbProvider, String value) {
|
||||
super(dbProvider, "sortkey_before", value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Timestamp getMinTimestamp() {
|
||||
return new Timestamp(0);
|
||||
public long getMinValue() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Timestamp getMaxTimestamp() {
|
||||
return ChangeUtil.timeFromSortKey(getValue());
|
||||
public long getMaxValue() {
|
||||
return ChangeUtil.parseSortKey(getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -66,13 +66,13 @@ public abstract class SortKeyPredicate extends
|
||||
}
|
||||
|
||||
@Override
|
||||
public Timestamp getMinTimestamp() {
|
||||
return ChangeUtil.timeFromSortKey(getValue());
|
||||
public long getMinValue() {
|
||||
return ChangeUtil.parseSortKey(getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Timestamp getMaxTimestamp() {
|
||||
return new Timestamp(Long.MAX_VALUE);
|
||||
public long getMaxValue() {
|
||||
return Long.MAX_VALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user