SOLR-15049: Add TopLevelJoinQuery optimization for 'self-joins' (#2146)

This commit is contained in:
Jason Gerlowski 2020-12-22 08:32:52 -05:00 committed by GitHub
parent d905a7ba8e
commit 8b272a0960
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 41 additions and 3 deletions

View File

@ -230,6 +230,8 @@ Optimizations
---------------------
* SOLR-14975: Optimize CoreContainer.getAllCoreNames, getLoadedCoreNames and getCoreDescriptors. (Bruno Roustant)
* SOLR-15049: Optimize same-core, same-field joins in TopLevelJoinQuery (Jason Gerlowski)
Bug Fixes
---------------------
* SOLR-14946: Fix responseHeader being returned in response when omitHeader=true and EmbeddedSolrServer is used

View File

@ -90,7 +90,7 @@ public class JoinQParserPlugin extends QParserPlugin {
@Override
Query makeFilter(QParser qparser, JoinQParserPlugin plugin) throws SyntaxError {
final JoinParams jParams = parseJoin(qparser);
final JoinQuery q = new TopLevelJoinQuery(jParams.fromField, jParams.toField, jParams.fromCore, jParams.fromQuery);
final JoinQuery q = createTopLevelJoin(jParams);
q.fromCoreOpenTime = jParams.fromCoreOpenTime;
return q;
}
@ -99,6 +99,18 @@ public class JoinQParserPlugin extends QParserPlugin {
Query makeJoinDirectFromParams(JoinParams jParams) {
return new TopLevelJoinQuery(jParams.fromField, jParams.toField, null, jParams.fromQuery);
}
private JoinQuery createTopLevelJoin(JoinParams jParams) {
if (isSelfJoin(jParams)) {
return new TopLevelJoinQuery.SelfJoin(jParams.fromField, jParams.fromQuery);
}
return new TopLevelJoinQuery(jParams.fromField, jParams.toField, jParams.fromCore, jParams.fromQuery);
}
private boolean isSelfJoin(JoinParams jparams) {
return jparams.fromCore == null &&
(jparams.fromField != null && jparams.fromField.equals(jparams.toField));
}
},
crossCollection {
@Override

View File

@ -162,7 +162,7 @@ public class TopLevelJoinQuery extends JoinQuery {
return fromOrdBitSet;
}
private BitsetBounds convertFromOrdinalsIntoToField(LongBitSet fromOrdBitSet, SortedSetDocValues fromDocValues,
protected BitsetBounds convertFromOrdinalsIntoToField(LongBitSet fromOrdBitSet, SortedSetDocValues fromDocValues,
LongBitSet toOrdBitSet, SortedSetDocValues toDocValues) throws IOException {
long fromOrdinal = 0;
long firstToOrd = BitsetBounds.NO_MATCHES;
@ -208,7 +208,7 @@ public class TopLevelJoinQuery extends JoinQuery {
return -(low + 1); // key not found.
}
private static class BitsetBounds {
protected static class BitsetBounds {
public static final long NO_MATCHES = -1L;
public final long lower;
public final long upper;
@ -218,4 +218,28 @@ public class TopLevelJoinQuery extends JoinQuery {
this.upper = upper;
}
}
/**
* A {@link TopLevelJoinQuery} implementation optimized for when 'from' and 'to' cores and fields match and no ordinal-
* conversion is necessary.
*/
static class SelfJoin extends TopLevelJoinQuery {
public SelfJoin(String joinField, Query subQuery) {
super(joinField, joinField, null, subQuery);
}
protected BitsetBounds convertFromOrdinalsIntoToField(LongBitSet fromOrdBitSet, SortedSetDocValues fromDocValues,
LongBitSet toOrdBitSet, SortedSetDocValues toDocValues) throws IOException {
// 'from' and 'to' ordinals are identical for self-joins.
toOrdBitSet.or(fromOrdBitSet);
// Calculate boundary ords used for other optimizations
final long firstToOrd = toOrdBitSet.nextSetBit(0);
final long lastToOrd = toOrdBitSet.prevSetBit(toOrdBitSet.length() - 1);
return new BitsetBounds(firstToOrd, lastToOrd);
}
}
}