Parameterize Lucene's QueryBuilder

Change-Id: I02f2e7b7b929f5cb25b56a642f89c56dce85a405
This commit is contained in:
Dave Borowitz
2016-03-16 13:15:51 +01:00
parent 1068a6904f
commit aa01c29b5b
2 changed files with 50 additions and 47 deletions

View File

@@ -126,6 +126,14 @@ public class LuceneChangeIndex implements ChangeIndex {
private static final String ID_SORT_FIELD =
sortFieldName(ChangeField.LEGACY_ID);
static Term idTerm(ChangeData cd) {
return QueryBuilder.intTerm(LEGACY_ID.getName(), cd.getId().get());
}
static Term idTerm(Change.Id id) {
return QueryBuilder.intTerm(LEGACY_ID.getName(), id.get());
}
private static String sortFieldName(FieldDef<?, ?> f) {
return f.getName() + "_SORT";
}
@@ -140,7 +148,7 @@ public class LuceneChangeIndex implements ChangeIndex {
private final Provider<ReviewDb> db;
private final ChangeData.Factory changeDataFactory;
private final Schema<ChangeData> schema;
private final QueryBuilder queryBuilder;
private final QueryBuilder<ChangeData> queryBuilder;
private final ChangeSubIndex openIndex;
private final ChangeSubIndex closedIndex;
@@ -165,7 +173,7 @@ public class LuceneChangeIndex implements ChangeIndex {
GerritIndexWriterConfig closedConfig =
new GerritIndexWriterConfig(cfg, "changes_closed");
queryBuilder = new QueryBuilder(openConfig.getAnalyzer());
queryBuilder = new QueryBuilder<>(schema, openConfig.getAnalyzer());
SearcherFactory searcherFactory = new SearcherFactory();
if (LuceneIndexModule.isInMemoryTest(cfg)) {
@@ -207,7 +215,7 @@ public class LuceneChangeIndex implements ChangeIndex {
@Override
public void replace(ChangeData cd) throws IOException {
Term id = QueryBuilder.idTerm(cd);
Term id = LuceneChangeIndex.idTerm(cd);
Document doc = toDocument(cd);
try {
if (cd.change().getStatus().isOpen()) {
@@ -226,7 +234,7 @@ public class LuceneChangeIndex implements ChangeIndex {
@Override
public void delete(Change.Id id) throws IOException {
Term idTerm = QueryBuilder.idTerm(id);
Term idTerm = LuceneChangeIndex.idTerm(id);
try {
Futures.allAsList(
openIndex.delete(idTerm),
@@ -498,12 +506,12 @@ public class LuceneChangeIndex implements ChangeIndex {
return result;
}
private void add(Document doc, Values<ChangeData> values) {
private static <V> void add(Document doc, Values<V> values) {
String name = values.getField().getName();
FieldType<?> type = values.getField().getType();
Store store = store(values.getField());
FieldDef<ChangeData, ?> f = values.getField();
FieldDef<V, ?> f = values.getField();
// Add separate DocValues fields for those fields needed for sorting.
if (f == ChangeField.LEGACY_ID) {

View File

@@ -14,24 +14,23 @@
package com.google.gerrit.lucene;
import static com.google.gerrit.server.index.change.ChangeField.LEGACY_ID;
import static com.google.common.base.Preconditions.checkArgument;
import static org.apache.lucene.search.BooleanClause.Occur.MUST;
import static org.apache.lucene.search.BooleanClause.Occur.MUST_NOT;
import static org.apache.lucene.search.BooleanClause.Occur.SHOULD;
import com.google.common.collect.Lists;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.server.index.FieldType;
import com.google.gerrit.server.index.IndexPredicate;
import com.google.gerrit.server.index.IntegerRangePredicate;
import com.google.gerrit.server.index.RegexPredicate;
import com.google.gerrit.server.index.Schema;
import com.google.gerrit.server.index.TimestampRangePredicate;
import com.google.gerrit.server.query.AndPredicate;
import com.google.gerrit.server.query.NotPredicate;
import com.google.gerrit.server.query.OrPredicate;
import com.google.gerrit.server.query.Predicate;
import com.google.gerrit.server.query.QueryParseException;
import com.google.gerrit.server.query.change.ChangeData;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.index.Term;
@@ -48,23 +47,22 @@ import org.apache.lucene.util.NumericUtils;
import java.util.Date;
import java.util.List;
public class QueryBuilder {
public static Term idTerm(ChangeData cd) {
return intTerm(LEGACY_ID.getName(), cd.getId().get());
}
public static Term idTerm(Change.Id id) {
return intTerm(LEGACY_ID.getName(), id.get());
public class QueryBuilder<V> {
static Term intTerm(String name, int value) {
BytesRefBuilder builder = new BytesRefBuilder();
NumericUtils.intToPrefixCodedBytes(value, 0, builder);
return new Term(name, builder.get());
}
private final Schema<V> schema;
private final org.apache.lucene.util.QueryBuilder queryBuilder;
public QueryBuilder(Analyzer analyzer) {
public QueryBuilder(Schema<V> schema, Analyzer analyzer) {
this.schema = schema;
queryBuilder = new org.apache.lucene.util.QueryBuilder(analyzer);
}
public Query toQuery(Predicate<ChangeData> p) throws QueryParseException {
public Query toQuery(Predicate<V> p) throws QueryParseException {
if (p instanceof AndPredicate) {
return and(p);
} else if (p instanceof OrPredicate) {
@@ -72,13 +70,13 @@ public class QueryBuilder {
} else if (p instanceof NotPredicate) {
return not(p);
} else if (p instanceof IndexPredicate) {
return fieldQuery((IndexPredicate<ChangeData>) p);
return fieldQuery((IndexPredicate<V>) p);
} else {
throw new QueryParseException("cannot create query for index: " + p);
}
}
private Query or(Predicate<ChangeData> p)
private Query or(Predicate<V> p)
throws QueryParseException {
try {
BooleanQuery.Builder q = new BooleanQuery.Builder();
@@ -91,17 +89,17 @@ public class QueryBuilder {
}
}
private Query and(Predicate<ChangeData> p)
private Query and(Predicate<V> p)
throws QueryParseException {
try {
BooleanQuery.Builder b = new BooleanQuery.Builder();
List<Query> not = Lists.newArrayListWithCapacity(p.getChildCount());
for (int i = 0; i < p.getChildCount(); i++) {
Predicate<ChangeData> c = p.getChild(i);
Predicate<V> c = p.getChild(i);
if (c instanceof NotPredicate) {
Predicate<ChangeData> n = c.getChild(0);
Predicate<V> n = c.getChild(0);
if (n instanceof TimestampRangePredicate) {
b.add(notTimestamp((TimestampRangePredicate<ChangeData>) n), MUST);
b.add(notTimestamp((TimestampRangePredicate<V>) n), MUST);
} else {
not.add(toQuery(n));
}
@@ -118,11 +116,11 @@ public class QueryBuilder {
}
}
private Query not(Predicate<ChangeData> p)
private Query not(Predicate<V> p)
throws QueryParseException {
Predicate<ChangeData> n = p.getChild(0);
Predicate<V> n = p.getChild(0);
if (n instanceof TimestampRangePredicate) {
return notTimestamp((TimestampRangePredicate<ChangeData>) n);
return notTimestamp((TimestampRangePredicate<V>) n);
}
// Lucene does not support negation, start with all and subtract.
@@ -132,8 +130,11 @@ public class QueryBuilder {
.build();
}
private Query fieldQuery(IndexPredicate<ChangeData> p)
private Query fieldQuery(IndexPredicate<V> p)
throws QueryParseException {
checkArgument(schema.hasField(p.getField()),
"field not in schema v%s: %s", schema.getVersion(),
p.getField().getName());
if (p.getType() == FieldType.INTEGER) {
return intQuery(p);
} else if (p.getType() == FieldType.INTEGER_RANGE) {
@@ -151,13 +152,7 @@ public class QueryBuilder {
}
}
private static Term intTerm(String name, int value) {
BytesRefBuilder builder = new BytesRefBuilder();
NumericUtils.intToPrefixCodedBytes(value, 0, builder);
return new Term(name, builder.get());
}
private Query intQuery(IndexPredicate<ChangeData> p)
private Query intQuery(IndexPredicate<V> p)
throws QueryParseException {
int value;
try {
@@ -170,11 +165,11 @@ public class QueryBuilder {
return new TermQuery(intTerm(p.getField().getName(), value));
}
private Query intRangeQuery(IndexPredicate<ChangeData> p)
private Query intRangeQuery(IndexPredicate<V> p)
throws QueryParseException {
if (p instanceof IntegerRangePredicate) {
IntegerRangePredicate<ChangeData> r =
(IntegerRangePredicate<ChangeData>) p;
IntegerRangePredicate<V> r =
(IntegerRangePredicate<V>) p;
int minimum = r.getMinimumValue();
int maximum = r.getMaximumValue();
if (minimum == maximum) {
@@ -192,11 +187,11 @@ public class QueryBuilder {
throw new QueryParseException("not an integer range: " + p);
}
private Query timestampQuery(IndexPredicate<ChangeData> p)
private Query timestampQuery(IndexPredicate<V> p)
throws QueryParseException {
if (p instanceof TimestampRangePredicate) {
TimestampRangePredicate<ChangeData> r =
(TimestampRangePredicate<ChangeData>) p;
TimestampRangePredicate<V> r =
(TimestampRangePredicate<V>) p;
return NumericRangeQuery.newLongRange(
r.getField().getName(),
r.getMinTimestamp().getTime(),
@@ -206,7 +201,7 @@ public class QueryBuilder {
throw new QueryParseException("not a timestamp: " + p);
}
private Query notTimestamp(TimestampRangePredicate<ChangeData> r)
private Query notTimestamp(TimestampRangePredicate<V> r)
throws QueryParseException {
if (r.getMinTimestamp().getTime() == 0) {
return NumericRangeQuery.newLongRange(
@@ -218,7 +213,7 @@ public class QueryBuilder {
throw new QueryParseException("cannot negate: " + r);
}
private Query exactQuery(IndexPredicate<ChangeData> p) {
private Query exactQuery(IndexPredicate<V> p) {
if (p instanceof RegexPredicate<?>) {
return regexQuery(p);
} else {
@@ -226,7 +221,7 @@ public class QueryBuilder {
}
}
private Query regexQuery(IndexPredicate<ChangeData> p) {
private Query regexQuery(IndexPredicate<V> p) {
String re = p.getValue();
if (re.startsWith("^")) {
re = re.substring(1);
@@ -237,11 +232,11 @@ public class QueryBuilder {
return new RegexpQuery(new Term(p.getField().getName(), re));
}
private Query prefixQuery(IndexPredicate<ChangeData> p) {
private Query prefixQuery(IndexPredicate<V> p) {
return new PrefixQuery(new Term(p.getField().getName(), p.getValue()));
}
private Query fullTextQuery(IndexPredicate<ChangeData> p)
private Query fullTextQuery(IndexPredicate<V> p)
throws QueryParseException {
String value = p.getValue();
if (value == null) {