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

madhan pushed a commit to branch branch-2.0
in repository https://gitbox.apache.org/repos/asf/atlas.git


The following commit(s) were added to refs/heads/branch-2.0 by this push:
     new cfca38d  ATLAS-3654: enable support for solr in standalone mode
cfca38d is described below

commit cfca38d0ca39d6cc3abbc6d6f54ad1c9d3355045
Author: Damian Warszawski <[email protected]>
AuthorDate: Tue May 19 23:57:56 2020 +0200

    ATLAS-3654: enable support for solr in standalone mode
    
    Signed-off-by: Madhan Neethiraj <[email protected]>
    (cherry picked from commit 6248e361fc01256ba263a6f4523c50541f6fc86b)
---
 distro/src/bin/atlas_config.py                     | 13 +++-
 .../src/documents/Setup/InstallationInstruction.md | 17 ++++-
 .../graphdb/janus/AtlasJanusGraphIndexClient.java  | 74 +++++++++++++++-------
 .../janusgraph/diskstorage/solr/Solr6Index.java    | 16 ++++-
 4 files changed, 91 insertions(+), 29 deletions(-)

diff --git a/distro/src/bin/atlas_config.py b/distro/src/bin/atlas_config.py
index f09026f..2d61433 100755
--- a/distro/src/bin/atlas_config.py
+++ b/distro/src/bin/atlas_config.py
@@ -66,7 +66,9 @@ CONF_FILE="atlas-application.properties"
 STORAGE_BACKEND_CONF="atlas.graph.storage.backend"
 HBASE_STORAGE_LOCAL_CONF_ENTRY="atlas.graph.storage.hostname\s*=\s*localhost"
 SOLR_INDEX_CONF_ENTRY="atlas.graph.index.search.backend\s*=\s*solr"
-SOLR_INDEX_LOCAL_CONF_ENTRY="atlas.graph.index.search.solr.zookeeper-url\s*=\s*localhost"
+SOLR_INDEX_MODE_CONF_ENTRY="atlas.graph.index.search.solr.mode"
+SOLR_INDEX_LOCAL_STANDALONE_CONF_ENTRY="atlas.graph.index.search.solr.http-urls\s*=(http|https)://localhost"
+SOLR_INDEX_LOCAL_CLOUD_CONF_ENTRY="atlas.graph.index.search.solr.zookeeper-url\s*=\s*localhost"
 SOLR_INDEX_ZK_URL="atlas.graph.index.search.solr.zookeeper-url"
 TOPICS_TO_CREATE="atlas.notification.topics"
 ATLAS_HTTP_PORT="atlas.server.http.port"
@@ -453,7 +455,14 @@ def is_solr_local(confdir):
         return False
 
     confdir = os.path.join(confdir, CONF_FILE)
-    return grep(confdir, SOLR_INDEX_CONF_ENTRY) is not None and grep(confdir, 
SOLR_INDEX_LOCAL_CONF_ENTRY) is not None
+    return is_solr_local_cloud_mode(confdir) or 
is_solr_local_standalone_mode(confdir)
+
+def is_solr_local_cloud_mode(confdir):
+    return grep(confdir, SOLR_INDEX_CONF_ENTRY) is not None and 
getConfig(confdir, SOLR_INDEX_MODE_CONF_ENTRY) == 'cloud' and grep(confdir, 
SOLR_INDEX_LOCAL_CLOUD_CONF_ENTRY) is not None
+
+
+def is_solr_local_standalone_mode(confdir):
+    return grep(confdir, SOLR_INDEX_CONF_ENTRY) is not None and 
getConfig(confdir, SOLR_INDEX_MODE_CONF_ENTRY) == 'http' and grep(confdir, 
SOLR_INDEX_LOCAL_STANDALONE_CONF_ENTRY) is not None
 
 def is_elasticsearch_local():
     if os.environ.get(MANAGE_LOCAL_ELASTICSEARCH, "False").lower() == 'false':
diff --git a/docs/src/documents/Setup/InstallationInstruction.md 
b/docs/src/documents/Setup/InstallationInstruction.md
index d1b22d6..d22cb0c 100644
--- a/docs/src/documents/Setup/InstallationInstruction.md
+++ b/docs/src/documents/Setup/InstallationInstruction.md
@@ -150,7 +150,7 @@ By default, Apache Atlas uses JanusGraph as the graph 
repository and is the only
 * Start Apache Solr in cloud mode.
 
 SolrCloud mode uses a ZooKeeper Service as a highly available, central 
location for cluster management. For a small cluster, running with an existing 
ZooKeeper quorum should be fine. For larger clusters, you would want to run 
separate multiple ZooKeeper quorum with at least 3 servers.
-  Note: Apache Atlas currently supports Apache Solr in "cloud" mode only. 
"http" mode is not supported. For more information, refer Apache Solr 
documentation - https://cwiki.apache.org/confluence/display/solr/SolrCloud
+  For more information, refer Apache Solr documentation - 
https://cwiki.apache.org/confluence/display/solr/SolrCloud
 
 
    * For e.g., to bring up an Apache Solr node listening on port 8983 on a 
machine, you can use the command:
@@ -197,6 +197,21 @@ Pre-requisites for running Apache Solr in cloud mode
   * SolrCloud has support for replication and sharding. It is highly 
recommended to use SolrCloud with at least two Apache Solr nodes running on 
different servers with replication enabled.
     If using SolrCloud, then you also need ZooKeeper installed and configured 
with 3 or 5 ZooKeeper nodes
 
+  * Start Apache Solr in http mode - alternative setup to Solr in cloud mode.
+
+  Solr Standalone is used for a single instance, and it keeps configuration 
information on the file system. It does not require zookeeper and provides high 
performance for medium size index.
+  Can be consider as a good option for fast prototyping as well as valid 
configuration for development environments. In some cases it demonstrates a 
better performance than solr cloud mode in production grade setup of Atlas.
+
+   * Change ATLAS configuration to point to Standalone Apache Solr instance 
setup. Please make sure the following configurations are set to the below 
values in ATLAS_HOME/conf/atlas-application.properties
+
+<SyntaxHighlighter wrapLines={true} language="powershell" style={theme.dark}>
+{`atlas.graph.index.search.backend=solr
+atlas.graph.index.search.solr.mode=http
+atlas.graph.index.search.solr.http-urls=<a single or list of URLs for the Solr 
instances must be provided.> eg: localhost:2181,10.1.6.5:2181`}
+</SyntaxHighlighter>
+
+  Note: Solr standalone can be run in embedded mode using 
`embedded-hbase-solr` profile.
+
 *Configuring Elasticsearch as the indexing backend for the Graph Repository 
(Tech Preview)*
 
 By default, Apache Atlas uses [JanusGraph](https://janusgraph.org/) as the 
graph repository and is the only graph repository implementation available 
currently. For configuring [JanusGraph](https://janusgraph.org/) to work with 
Elasticsearch, please follow the instructions below
diff --git 
a/graphdb/janus/src/main/java/org/apache/atlas/repository/graphdb/janus/AtlasJanusGraphIndexClient.java
 
b/graphdb/janus/src/main/java/org/apache/atlas/repository/graphdb/janus/AtlasJanusGraphIndexClient.java
index ba65f3d..29bd2a4 100644
--- 
a/graphdb/janus/src/main/java/org/apache/atlas/repository/graphdb/janus/AtlasJanusGraphIndexClient.java
+++ 
b/graphdb/janus/src/main/java/org/apache/atlas/repository/graphdb/janus/AtlasJanusGraphIndexClient.java
@@ -32,14 +32,17 @@ import org.apache.commons.lang.StringUtils;
 import org.apache.solr.client.solrj.SolrClient;
 import org.apache.solr.client.solrj.SolrQuery;
 import org.apache.solr.client.solrj.SolrRequest;
+import org.apache.solr.client.solrj.SolrResponse;
 import org.apache.solr.client.solrj.SolrServerException;
+import org.apache.solr.client.solrj.request.GenericSolrRequest;
 import org.apache.solr.client.solrj.request.V2Request;
-import org.apache.solr.client.solrj.response.V2Response;
-import org.apache.solr.common.util.NamedList;
 import org.apache.solr.client.solrj.response.FacetField;
 import org.apache.solr.client.solrj.response.QueryResponse;
 import org.apache.solr.client.solrj.response.TermsResponse;
+import org.apache.solr.client.solrj.util.ClientUtils;
 import org.apache.solr.common.params.CommonParams;
+import org.apache.solr.common.util.ContentStream;
+import org.apache.solr.common.util.NamedList;
 import org.janusgraph.diskstorage.solr.Solr6Index;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -79,6 +82,8 @@ public class AtlasJanusGraphIndexClient implements 
AtlasGraphIndexClient {
                 return;
             }
 
+            Solr6Index.Mode solrMode = Solr6Index.getSolrMode();
+
             //1) try updating request handler
             //2) if update fails, try creating request handler
 
@@ -100,7 +105,7 @@ public class AtlasJanusGraphIndexClient implements 
AtlasGraphIndexClient {
                 try {
                     LOG.info("Attempting to update free text request handler 
{} for collection {}", FREETEXT_REQUEST_HANDLER, collectionName);
 
-                    updateFreeTextRequestHandler(solrClient, collectionName, 
indexFieldName2SearchWeightMap);
+                    updateFreeTextRequestHandler(solrClient, collectionName, 
indexFieldName2SearchWeightMap, solrMode);
 
                     LOG.info("Successfully updated free text request handler 
{} for collection {}..", FREETEXT_REQUEST_HANDLER, collectionName);
 
@@ -114,7 +119,7 @@ public class AtlasJanusGraphIndexClient implements 
AtlasGraphIndexClient {
                 try {
                     LOG.info("Attempting to create free text request handler 
{} for collection {}", FREETEXT_REQUEST_HANDLER, collectionName);
 
-                    createFreeTextRequestHandler(solrClient, collectionName, 
indexFieldName2SearchWeightMap);
+                    createFreeTextRequestHandler(solrClient, collectionName, 
indexFieldName2SearchWeightMap, solrMode);
                     LOG.info("Successfully created free text request handler 
{} for collection {}", FREETEXT_REQUEST_HANDLER, collectionName);
 
                     return;
@@ -256,10 +261,13 @@ public class AtlasJanusGraphIndexClient implements 
AtlasGraphIndexClient {
                 return;
             }
 
+            Solr6Index.Mode solrMode = Solr6Index.getSolrMode();
+
             //update the request handler
             performRequestHandlerAction(collectionName,
                                         solrClient,
-                                        
generatePayLoadForSuggestions(generateSuggestionsString(suggestionProperties)));
+                                        
generatePayLoadForSuggestions(generateSuggestionsString(suggestionProperties)),
+                                        solrMode);
         } catch (Throwable t) {
             String msg = String.format("Error encountered in creating the 
request handler '%s' for collection '%s'", Constants.TERMS_REQUEST_HANDLER, 
collectionName);
 
@@ -458,35 +466,53 @@ public class AtlasJanusGraphIndexClient implements 
AtlasGraphIndexClient {
         return ret.toString();
     }
 
-    private V2Response updateFreeTextRequestHandler(SolrClient solrClient, 
String collectionName,
-                                                    Map<String, Integer> 
indexFieldName2SearchWeightMap) throws IOException, SolrServerException, 
AtlasBaseException {
+    private SolrResponse updateFreeTextRequestHandler(SolrClient solrClient, 
String collectionName,
+                                                    Map<String, Integer> 
indexFieldName2SearchWeightMap,
+                                                    Solr6Index.Mode mode) 
throws IOException, SolrServerException, AtlasBaseException {
         String searchWeightString = 
generateSearchWeightString(indexFieldName2SearchWeightMap);
         String payLoadString      = 
generatePayLoadForFreeText("update-requesthandler", searchWeightString);
 
-        return performRequestHandlerAction(collectionName, solrClient, 
payLoadString);
+        return performRequestHandlerAction(collectionName, solrClient, 
payLoadString, mode);
     }
 
-    private V2Response createFreeTextRequestHandler(SolrClient solrClient, 
String collectionName,
-                                                    Map<String, Integer> 
indexFieldName2SearchWeightMap) throws IOException, SolrServerException, 
AtlasBaseException {
+    private SolrResponse createFreeTextRequestHandler(SolrClient solrClient, 
String collectionName,
+                                                    Map<String, Integer> 
indexFieldName2SearchWeightMap,
+                                                    Solr6Index.Mode mode) 
throws IOException, SolrServerException, AtlasBaseException {
         String searchWeightString = 
generateSearchWeightString(indexFieldName2SearchWeightMap);
         String payLoadString      = 
generatePayLoadForFreeText("create-requesthandler", searchWeightString);
 
-        return performRequestHandlerAction(collectionName, solrClient, 
payLoadString);
+        return performRequestHandlerAction(collectionName, solrClient, 
payLoadString, mode);
     }
 
-    private V2Response performRequestHandlerAction(String collectionName,
+    private SolrResponse performRequestHandlerAction(String collectionName,
                                                    SolrClient solrClient,
-                                                   String actionPayLoad) 
throws IOException, SolrServerException, AtlasBaseException {
-        V2Request v2Request = new 
V2Request.Builder(String.format("/collections/%s/config", collectionName))
-                                                    
.withMethod(SolrRequest.METHOD.POST)
-                                                    .withPayload(actionPayLoad)
-                                                    .build();
+                                                   String actionPayLoad,
+                                                   Solr6Index.Mode mode) 
throws IOException, SolrServerException, AtlasBaseException {
+        switch (mode) {
+            case CLOUD:
+                V2Request v2request = new 
V2Request.Builder(String.format("/collections/%s/config", collectionName))
+                                                            
.withMethod(SolrRequest.METHOD.POST)
+                                                            
.withPayload(actionPayLoad)
+                                                            .build();
+
+                return 
validateResponseForSuccess(v2request.process(solrClient));
 
-        return validateResponseForSuccess(v2Request.process(solrClient));
+            case HTTP:
+                Collection<ContentStream> contentStreams = 
ClientUtils.toContentStreams(actionPayLoad, "application/json; charset=UTF-8");
+                GenericSolrRequest        request        = new 
GenericSolrRequest(SolrRequest.METHOD.POST, String.format("/%s/config", 
collectionName), null);
+
+                request.setContentStreams(contentStreams);
+                request.setUseV2(false);
+
+                return validateResponseForSuccess(request.process(solrClient));
+
+            default:
+                throw new IllegalArgumentException("Unsupported Solr operation 
mode: " + mode);
+        }
     }
 
-    private V2Response validateResponseForSuccess(V2Response v2Response) 
throws AtlasBaseException {
-        if(v2Response == null) {
+    private SolrResponse validateResponseForSuccess(SolrResponse solrResponse) 
throws AtlasBaseException {
+        if(solrResponse == null) {
             String msg = "Received null response .";
 
             LOG.error(msg);
@@ -495,10 +521,10 @@ public class AtlasJanusGraphIndexClient implements 
AtlasGraphIndexClient {
         }
 
         if (LOG.isDebugEnabled()) {
-            LOG.debug("V2 Response is {}", v2Response.toString());
+            LOG.debug("V2 Response is {}", solrResponse.toString());
         }
 
-        NamedList<Object> response = v2Response.getResponse();
+        NamedList<Object> response = solrResponse.getResponse();
 
         if(response != null) {
             Object errorMessages = response.get("errorMessages");
@@ -523,7 +549,7 @@ public class AtlasJanusGraphIndexClient implements 
AtlasGraphIndexClient {
                 throw new AtlasBaseException(msg);
             } else {
                 if(LOG.isDebugEnabled()) {
-                    LOG.debug("Successfully performed response handler action. 
V2 Response is {}", v2Response.toString());
+                    LOG.debug("Successfully performed response handler action. 
V2 Response is {}", solrResponse.toString());
                 }
             }
 
@@ -533,7 +559,7 @@ public class AtlasJanusGraphIndexClient implements 
AtlasGraphIndexClient {
             }
         }
 
-        return v2Response;
+        return solrResponse;
     }
 
         static final class TermFreq {
diff --git 
a/graphdb/janus/src/main/java/org/janusgraph/diskstorage/solr/Solr6Index.java 
b/graphdb/janus/src/main/java/org/janusgraph/diskstorage/solr/Solr6Index.java
index 484c161..6509fef 100644
--- 
a/graphdb/janus/src/main/java/org/janusgraph/diskstorage/solr/Solr6Index.java
+++ 
b/graphdb/janus/src/main/java/org/janusgraph/diskstorage/solr/Solr6Index.java
@@ -143,7 +143,7 @@ public class Solr6Index implements IndexProvider {
     private static Solr6Index instance = null;
     public static final ConfigOption<Boolean> CREATE_SOLR_CLIENT_PER_REQUEST = 
new ConfigOption(SOLR_NS, "create-client-per-request", "when false, allows the 
sharing of solr client across other components.", 
org.janusgraph.diskstorage.configuration.ConfigOption.Type.LOCAL, false);
 
-    private enum Mode {
+    public enum Mode {
         HTTP, CLOUD;
 
         public static Mode parse(String mode) {
@@ -183,7 +183,6 @@ public class Solr6Index implements IndexProvider {
     private final boolean waitSearcher;
     private final boolean kerberosEnabled;
 
-
     public Solr6Index(final Configuration config) throws BackendException {
         // Add Kerberos-enabled SolrHttpClientBuilder
         HttpClientUtil.setHttpClientBuilder(new 
Krb5HttpClientBuilder().getBuilder());
@@ -217,6 +216,19 @@ public class Solr6Index implements IndexProvider {
         Solr6Index.instance = this;
     }
 
+    public static Mode getSolrMode() {
+        Solr6Index solr6Index = Solr6Index.instance;
+        Mode       ret        = (solr6Index != null) ? 
Mode.parse(solr6Index.configuration.get(SOLR_MODE)) : null;
+
+        if (ret == null) {
+            logger.warn("SolrMode is not set. Assuming {}", Mode.CLOUD);
+
+            ret = Mode.CLOUD;
+        }
+
+        return ret;
+    }
+
     public static SolrClient getSolrClient() {
         if (Solr6Index.instance != null) {
             if (createSolrClientPerRequest) {

Reply via email to