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.ChangeData;
|
||||||
import com.google.gerrit.server.query.change.ChangeDataSource;
|
import com.google.gerrit.server.query.change.ChangeDataSource;
|
||||||
import com.google.gerrit.server.query.change.IndexRewriteImpl;
|
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.OrmException;
|
||||||
import com.google.gwtorm.server.ResultSet;
|
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;
|
||||||
import org.apache.lucene.document.Field.Store;
|
import org.apache.lucene.document.Field.Store;
|
||||||
import org.apache.lucene.document.IntField;
|
import org.apache.lucene.document.IntField;
|
||||||
|
import org.apache.lucene.document.LongField;
|
||||||
import org.apache.lucene.document.StringField;
|
import org.apache.lucene.document.StringField;
|
||||||
import org.apache.lucene.index.IndexWriter;
|
import org.apache.lucene.index.IndexWriter;
|
||||||
import org.apache.lucene.index.IndexWriterConfig;
|
import org.apache.lucene.index.IndexWriterConfig;
|
||||||
@@ -261,6 +263,8 @@ public class LuceneChangeIndex implements ChangeIndex, LifecycleListener {
|
|||||||
return exactQuery(p);
|
return exactQuery(p);
|
||||||
} else if (p.getType() == FieldType.PREFIX) {
|
} else if (p.getType() == FieldType.PREFIX) {
|
||||||
return prefixQuery(p);
|
return prefixQuery(p);
|
||||||
|
} else if (p instanceof SortKeyPredicate) {
|
||||||
|
return sortKeyQuery((SortKeyPredicate) p);
|
||||||
} else {
|
} else {
|
||||||
throw badFieldType(p.getType());
|
throw badFieldType(p.getType());
|
||||||
}
|
}
|
||||||
@@ -285,6 +289,14 @@ public class LuceneChangeIndex implements ChangeIndex, LifecycleListener {
|
|||||||
return new TermQuery(intTerm(p.getOperator(), value));
|
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)
|
private static Query timestampQuery(IndexPredicate<ChangeData> p)
|
||||||
throws QueryParseException {
|
throws QueryParseException {
|
||||||
if (p instanceof TimestampRangePredicate) {
|
if (p instanceof TimestampRangePredicate) {
|
||||||
@@ -442,6 +454,10 @@ public class LuceneChangeIndex implements ChangeIndex, LifecycleListener {
|
|||||||
for (Object value : values) {
|
for (Object value : values) {
|
||||||
doc.add(new IntField(name, (Integer) value, store));
|
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) {
|
} else if (f.getType() == FieldType.TIMESTAMP) {
|
||||||
for (Object v : values) {
|
for (Object v : values) {
|
||||||
doc.add(new IntField(name, toIndexTime((Timestamp) v), store));
|
doc.add(new IntField(name, toIndexTime((Timestamp) v), store));
|
||||||
|
|||||||
@@ -450,16 +450,15 @@ public class ChangeUtil {
|
|||||||
return r.toString();
|
return r.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Timestamp timeFromSortKey(String sortKey) {
|
public static long parseSortKey(String sortKey) {
|
||||||
if ("z".equals(sortKey)) {
|
if ("z".equals(sortKey)) {
|
||||||
return new Timestamp(Long.MAX_VALUE);
|
return Long.MAX_VALUE;
|
||||||
}
|
}
|
||||||
String ts = sortKey.substring(0, 8);
|
String ts = sortKey.substring(0, 8);
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (i < 8 && ts.charAt(i) == '0')
|
while (i < 8 && ts.charAt(i) == '0')
|
||||||
i++;
|
i++;
|
||||||
long v = Long.parseLong(ts.substring(i), 16) * 60;
|
return Long.parseLong(ts.substring(i), 16);
|
||||||
return new Timestamp((v + SORT_KEY_EPOCH) * 1000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void computeSortKey(final Change c) {
|
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.common.collect.Sets;
|
||||||
import com.google.gerrit.reviewdb.client.PatchSetApproval;
|
import com.google.gerrit.reviewdb.client.PatchSetApproval;
|
||||||
import com.google.gerrit.reviewdb.client.PatchSet;
|
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.ChangeData;
|
||||||
import com.google.gerrit.server.query.change.ChangeQueryBuilder;
|
import com.google.gerrit.server.query.change.ChangeQueryBuilder;
|
||||||
import com.google.gerrit.server.query.change.ChangeStatusPredicate;
|
import com.google.gerrit.server.query.change.ChangeStatusPredicate;
|
||||||
@@ -43,7 +44,7 @@ import java.util.Set;
|
|||||||
*/
|
*/
|
||||||
public class ChangeField {
|
public class ChangeField {
|
||||||
/** Increment whenever making schema changes. */
|
/** Increment whenever making schema changes. */
|
||||||
public static final int SCHEMA_VERSION = 5;
|
public static final int SCHEMA_VERSION = 6;
|
||||||
|
|
||||||
/** Legacy change ID. */
|
/** Legacy change ID. */
|
||||||
public static final FieldDef<ChangeData, Integer> 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. */
|
/** List of filenames modified in the current patch set. */
|
||||||
public static final FieldDef<ChangeData, Iterable<String>> FILE =
|
public static final FieldDef<ChangeData, Iterable<String>> FILE =
|
||||||
new FieldDef.Repeatable<ChangeData, String>(
|
new FieldDef.Repeatable<ChangeData, String>(
|
||||||
|
|||||||
@@ -23,6 +23,10 @@ public class FieldType<T> {
|
|||||||
public static final FieldType<Integer> INTEGER =
|
public static final FieldType<Integer> INTEGER =
|
||||||
new 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. */
|
/** A single date/time-valued field. */
|
||||||
public static final FieldType<Timestamp> TIMESTAMP =
|
public static final FieldType<Timestamp> TIMESTAMP =
|
||||||
new 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.reviewdb.server.ReviewDb;
|
||||||
import com.google.gerrit.server.ChangeUtil;
|
import com.google.gerrit.server.ChangeUtil;
|
||||||
import com.google.gerrit.server.index.ChangeField;
|
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.gwtorm.server.OrmException;
|
||||||
import com.google.inject.Provider;
|
import com.google.inject.Provider;
|
||||||
|
|
||||||
import java.sql.Timestamp;
|
public abstract class SortKeyPredicate extends IndexPredicate<ChangeData> {
|
||||||
|
|
||||||
public abstract class SortKeyPredicate extends
|
|
||||||
TimestampRangePredicate<ChangeData> {
|
|
||||||
protected final Provider<ReviewDb> dbProvider;
|
protected final Provider<ReviewDb> dbProvider;
|
||||||
|
|
||||||
SortKeyPredicate(Provider<ReviewDb> dbProvider, String name, String value) {
|
SortKeyPredicate(Provider<ReviewDb> dbProvider, String name, String value) {
|
||||||
super(ChangeField.UPDATED, name, value);
|
super(ChangeField.SORTKEY, name, value);
|
||||||
this.dbProvider = dbProvider;
|
this.dbProvider = dbProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,19 +35,22 @@ public abstract class SortKeyPredicate extends
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract long getMinValue();
|
||||||
|
public abstract long getMaxValue();
|
||||||
|
|
||||||
public static class Before extends SortKeyPredicate {
|
public static class Before extends SortKeyPredicate {
|
||||||
Before(Provider<ReviewDb> dbProvider, String value) {
|
Before(Provider<ReviewDb> dbProvider, String value) {
|
||||||
super(dbProvider, "sortkey_before", value);
|
super(dbProvider, "sortkey_before", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Timestamp getMinTimestamp() {
|
public long getMinValue() {
|
||||||
return new Timestamp(0);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Timestamp getMaxTimestamp() {
|
public long getMaxValue() {
|
||||||
return ChangeUtil.timeFromSortKey(getValue());
|
return ChangeUtil.parseSortKey(getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -66,13 +66,13 @@ public abstract class SortKeyPredicate extends
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Timestamp getMinTimestamp() {
|
public long getMinValue() {
|
||||||
return ChangeUtil.timeFromSortKey(getValue());
|
return ChangeUtil.parseSortKey(getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Timestamp getMaxTimestamp() {
|
public long getMaxValue() {
|
||||||
return new Timestamp(Long.MAX_VALUE);
|
return Long.MAX_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
Reference in New Issue
Block a user