You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by th...@apache.org on 2015/02/05 23:06:13 UTC

svn commit: r1657701 - in /lucene/dev/branches/branch_5x: ./ solr/ solr/CHANGES.txt solr/core/ solr/core/src/java/org/apache/solr/search/JoinQParserPlugin.java solr/core/src/test/org/apache/solr/cloud/DistribJoinFromCollectionTest.java

Author: thelabdude
Date: Thu Feb  5 22:06:12 2015
New Revision: 1657701

URL: http://svn.apache.org/r1657701
Log:
SOLR-4905: Allow fromIndex parameter to JoinQParserPlugin to refer to a single-sharded collection that has a replica on all nodes

Added:
    lucene/dev/branches/branch_5x/solr/core/src/test/org/apache/solr/cloud/DistribJoinFromCollectionTest.java
      - copied unchanged from r1656622, lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/DistribJoinFromCollectionTest.java
Modified:
    lucene/dev/branches/branch_5x/   (props changed)
    lucene/dev/branches/branch_5x/solr/   (props changed)
    lucene/dev/branches/branch_5x/solr/CHANGES.txt
    lucene/dev/branches/branch_5x/solr/core/   (props changed)
    lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/search/JoinQParserPlugin.java

Modified: lucene/dev/branches/branch_5x/solr/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_5x/solr/CHANGES.txt?rev=1657701&r1=1657700&r2=1657701&view=diff
==============================================================================
--- lucene/dev/branches/branch_5x/solr/CHANGES.txt (original)
+++ lucene/dev/branches/branch_5x/solr/CHANGES.txt Thu Feb  5 22:06:12 2015
@@ -45,6 +45,10 @@ New Features
   deprecated in favour of close(). (Mark Miller, Tomás Fernández Löbbe, Alan
   Woodward)
 
+* SOLR-4905: Allow fromIndex parameter to JoinQParserPlugin to refer to a single-sharded
+  collection that has a replica on all nodes where there is a replica in the to index
+  (Jack Lo, Timothy Potter)
+
 * SOLR-6648: Add support in AnalyzingInfixLookupFactory and BlendedInfixLookupFactory 
   for setting 'highlight' and 'allTermsRequired' in the suggester configuration.
   (Boon Low, Varun Thacker via Tomás Fernández Löbbe)

Modified: lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/search/JoinQParserPlugin.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/search/JoinQParserPlugin.java?rev=1657701&r1=1657700&r2=1657701&view=diff
==============================================================================
--- lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/search/JoinQParserPlugin.java (original)
+++ lucene/dev/branches/branch_5x/solr/core/src/java/org/apache/solr/search/JoinQParserPlugin.java Thu Feb  5 22:06:12 2015
@@ -21,6 +21,7 @@ import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 import org.apache.lucene.index.LeafReaderContext;
@@ -44,7 +45,13 @@ import org.apache.lucene.util.Bits;
 import org.apache.lucene.util.BytesRef;
 import org.apache.lucene.util.FixedBitSet;
 import org.apache.lucene.util.StringHelper;
+import org.apache.solr.cloud.ZkController;
 import org.apache.solr.common.SolrException;
+import org.apache.solr.common.cloud.Aliases;
+import org.apache.solr.common.cloud.Replica;
+import org.apache.solr.common.cloud.Slice;
+import org.apache.solr.common.cloud.ZkCoreNodeProps;
+import org.apache.solr.common.cloud.ZkStateReader;
 import org.apache.solr.common.params.SolrParams;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.SimpleOrderedMap;
@@ -80,13 +87,45 @@ public class JoinQParserPlugin extends Q
         if (fromIndex != null && !fromIndex.equals(req.getCore().getCoreDescriptor().getName()) ) {
           CoreContainer container = req.getCore().getCoreDescriptor().getCoreContainer();
 
-          final SolrCore fromCore = container.getCore(fromIndex);
-          RefCounted<SolrIndexSearcher> fromHolder = null;
-
-          if (fromCore == null) {
-            throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Cross-core join: no such core " + fromIndex);
+          // if in SolrCloud mode, fromIndex should be the name of a single-sharded collection
+          if (container.isZooKeeperAware()) {
+            ZkController zkController = container.getZkController();
+            if (!zkController.getClusterState().hasCollection(fromIndex)) {
+              // collection not found ... but it might be an alias?
+              String resolved = null;
+              Aliases aliases = zkController.getZkStateReader().getAliases();
+              if (aliases != null) {
+                Map<String, String> collectionAliases = aliases.getCollectionAliasMap();
+                resolved = (collectionAliases != null) ? collectionAliases.get(fromIndex) : null;
+                if (resolved != null) {
+                  // ok, was an alias, but if the alias points to multiple collections, then we don't support that yet
+                  if (resolved.split(",").length > 1)
+                    throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
+                        "SolrCloud join: Collection alias '" + fromIndex +
+                            "' maps to multiple collections ("+resolved+
+                            "), which is not currently supported for joins.");
+                }
+              }
+
+              if (resolved == null)
+                throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
+                  "SolrCloud join: Collection '" + fromIndex + "' not found!");
+
+              // ok, resolved to an alias
+              fromIndex = resolved;
+            }
+
+            // the fromIndex is a local replica for a single-sharded collection with replicas
+            // across all nodes that have replicas for the collection we're joining with
+            fromIndex = findLocalReplicaForFromIndex(zkController, fromIndex);
           }
 
+          final SolrCore fromCore = container.getCore(fromIndex);
+          if (fromCore == null)
+            throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
+                "Cross-core join: no such core " + fromIndex);
+
+          RefCounted<SolrIndexSearcher> fromHolder = null;
           LocalSolrQueryRequest otherReq = new LocalSolrQueryRequest(fromCore, params);
           try {
             QParser parser = QParser.getParser(v, "lucene", otherReq);
@@ -109,6 +148,39 @@ public class JoinQParserPlugin extends Q
       }
     };
   }
+
+  protected String findLocalReplicaForFromIndex(ZkController zkController, String fromIndex) {
+    String fromReplica = null;
+
+    String nodeName = zkController.getNodeName();
+    for (Slice slice : zkController.getClusterState().getActiveSlices(fromIndex)) {
+      if (fromReplica != null)
+        throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
+            "SolrCloud join: multiple shards not yet supported " + fromIndex);
+
+      for (Replica replica : slice.getReplicas()) {
+        if (replica.getNodeName().equals(nodeName)) {
+          fromReplica = replica.getStr(ZkStateReader.CORE_NAME_PROP);
+
+          // found local replica, but is it Active?
+          ZkCoreNodeProps replicaCoreProps = new ZkCoreNodeProps(replica);
+          if (!ZkStateReader.ACTIVE.equals(replicaCoreProps.getState()))
+            throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
+                "SolrCloud join: "+fromIndex+" has a local replica ("+fromReplica+
+                    ") on "+nodeName+", but it is "+replicaCoreProps.getState());
+
+          break;
+        }
+      }
+    }
+
+    if (fromReplica == null)
+      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
+          "SolrCloud join: No active replicas for "+fromIndex+
+              " found in node " + nodeName);
+
+    return fromReplica;
+  }
 }