You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ge...@apache.org on 2020/12/22 14:15:30 UTC

[lucene-solr] branch branch_8x updated: SOLR-15049: Add TopLevelJoinQuery optimization for 'self-joins'

This is an automated email from the ASF dual-hosted git repository.

gerlowskija pushed a commit to branch branch_8x
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git


The following commit(s) were added to refs/heads/branch_8x by this push:
     new 7f8e260  SOLR-15049: Add TopLevelJoinQuery optimization for 'self-joins'
7f8e260 is described below

commit 7f8e260c124e94ddd5033ee30249cf56f813729e
Author: Jason Gerlowski <ge...@apache.org>
AuthorDate: Tue Dec 22 08:32:52 2020 -0500

    SOLR-15049: Add TopLevelJoinQuery optimization for 'self-joins'
---
 solr/CHANGES.txt                                   |  2 ++
 .../org/apache/solr/search/JoinQParserPlugin.java  | 14 ++++++++++-
 .../org/apache/solr/search/TopLevelJoinQuery.java  | 28 ++++++++++++++++++++--
 3 files changed, 41 insertions(+), 3 deletions(-)

diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index 27dd68e..1bee192 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -45,6 +45,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
diff --git a/solr/core/src/java/org/apache/solr/search/JoinQParserPlugin.java b/solr/core/src/java/org/apache/solr/search/JoinQParserPlugin.java
index 76544d5..367af5e 100644
--- a/solr/core/src/java/org/apache/solr/search/JoinQParserPlugin.java
+++ b/solr/core/src/java/org/apache/solr/search/JoinQParserPlugin.java
@@ -121,7 +121,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;
       }
@@ -130,6 +130,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
diff --git a/solr/core/src/java/org/apache/solr/search/TopLevelJoinQuery.java b/solr/core/src/java/org/apache/solr/search/TopLevelJoinQuery.java
index 428c229..8ae1d48 100644
--- a/solr/core/src/java/org/apache/solr/search/TopLevelJoinQuery.java
+++ b/solr/core/src/java/org/apache/solr/search/TopLevelJoinQuery.java
@@ -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);
+    }
+  }
 }
+
+