ATLAS-1818: basic-search enhancements to improve search performance
Signed-off-by: Madhan Neethiraj <madhan@apache.org>
diff --git a/distro/src/conf/atlas-application.properties b/distro/src/conf/atlas-application.properties
index b2b8e74..5e59528 100755
--- a/distro/src/conf/atlas-application.properties
+++ b/distro/src/conf/atlas-application.properties
@@ -62,6 +62,8 @@
${titan.index.properties}
+# Solr-specific configuration property
+atlas.graph.index.search.max-result-set-size=150
######### Notification Configs #########
atlas.notification.embedded=true
diff --git a/distro/src/conf/solr/solrconfig.xml b/distro/src/conf/solr/solrconfig.xml
index ce2e20b..1d414f7 100644
--- a/distro/src/conf/solr/solrconfig.xml
+++ b/distro/src/conf/solr/solrconfig.xml
@@ -277,19 +277,19 @@
and old cache.
-->
<filterCache class="solr.FastLRUCache"
- size="512"
- initialSize="512"
- autowarmCount="0"/>
+ size="2000"
+ initialSize="2000"
+ autowarmCount="1000"/>
<!-- Query Result Cache
Caches results of searches - ordered lists of document ids
(DocList) based on a query, a sort, and the range of documents requested.
-->
- <queryResultCache class="solr.LRUCache"
- size="512"
- initialSize="512"
- autowarmCount="0"/>
+ <queryResultCache class="solr.FastLRUCache"
+ size="26000"
+ initialSize="26000"
+ autowarmCount="400"/>
<!-- Document Cache
@@ -297,10 +297,10 @@
document). Since Lucene internal document ids are transient,
this cache will not be autowarmed.
-->
- <documentCache class="solr.LRUCache"
- size="512"
- initialSize="512"
- autowarmCount="0"/>
+ <documentCache class="solr.FastLRUCache"
+ size="26000"
+ initialSize="26000"
+ autowarmCount="400"/>
<!-- custom cache currently used by block join -->
<cache name="perSegFilter"
diff --git a/graphdb/api/src/main/java/org/apache/atlas/repository/graphdb/AtlasGraph.java b/graphdb/api/src/main/java/org/apache/atlas/repository/graphdb/AtlasGraph.java
index a3a27bf..dded76f 100644
--- a/graphdb/api/src/main/java/org/apache/atlas/repository/graphdb/AtlasGraph.java
+++ b/graphdb/api/src/main/java/org/apache/atlas/repository/graphdb/AtlasGraph.java
@@ -158,6 +158,20 @@
AtlasIndexQuery<V, E> indexQuery(String indexName, String queryString);
/**
+ * Creates an index query.
+ *
+ * @param indexName index name
+ * @param queryString the query
+ * @param offset specify the offset that should be applied for the query. This is useful for paging through
+ * list of results
+ *
+ * @see <a
+ * href="https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl.html">
+ * Elastic Search Reference</a> for query syntax
+ */
+ AtlasIndexQuery<V, E> indexQuery(String indexName, String queryString, int offset);
+
+ /**
* Gets the management object associated with this graph and opens a transaction
* for changes that are made.
* @return
diff --git a/graphdb/titan0/src/main/java/org/apache/atlas/repository/graphdb/titan0/Titan0Graph.java b/graphdb/titan0/src/main/java/org/apache/atlas/repository/graphdb/titan0/Titan0Graph.java
index 9624c99..2408287 100644
--- a/graphdb/titan0/src/main/java/org/apache/atlas/repository/graphdb/titan0/Titan0Graph.java
+++ b/graphdb/titan0/src/main/java/org/apache/atlas/repository/graphdb/titan0/Titan0Graph.java
@@ -17,39 +17,6 @@
*/
package org.apache.atlas.repository.graphdb.titan0;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.script.Bindings;
-import javax.script.ScriptContext;
-import javax.script.ScriptEngine;
-import javax.script.ScriptEngineManager;
-import javax.script.ScriptException;
-
-import org.apache.atlas.AtlasErrorCode;
-import org.apache.atlas.exception.AtlasBaseException;
-import org.apache.atlas.groovy.GroovyExpression;
-import org.apache.atlas.repository.graphdb.AtlasEdge;
-import org.apache.atlas.repository.graphdb.AtlasGraph;
-import org.apache.atlas.repository.graphdb.AtlasGraphManagement;
-import org.apache.atlas.repository.graphdb.AtlasGraphQuery;
-import org.apache.atlas.repository.graphdb.AtlasIndexQuery;
-import org.apache.atlas.repository.graphdb.AtlasSchemaViolationException;
-import org.apache.atlas.repository.graphdb.AtlasVertex;
-import org.apache.atlas.repository.graphdb.GremlinVersion;
-import org.apache.atlas.repository.graphdb.titan0.query.Titan0GraphQuery;
-import org.apache.atlas.repository.graphdb.utils.IteratorToIterableAdapter;
-import org.apache.atlas.typesystem.types.IDataType;
-
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
@@ -65,9 +32,40 @@
import com.tinkerpop.blueprints.Vertex;
import com.tinkerpop.blueprints.util.io.graphson.GraphSONWriter;
import com.tinkerpop.pipes.util.structures.Row;
+import org.apache.atlas.AtlasErrorCode;
+import org.apache.atlas.exception.AtlasBaseException;
+import org.apache.atlas.groovy.GroovyExpression;
+import org.apache.atlas.repository.graphdb.AtlasEdge;
+import org.apache.atlas.repository.graphdb.AtlasGraph;
+import org.apache.atlas.repository.graphdb.AtlasGraphManagement;
+import org.apache.atlas.repository.graphdb.AtlasGraphQuery;
+import org.apache.atlas.repository.graphdb.AtlasIndexQuery;
+import org.apache.atlas.repository.graphdb.AtlasSchemaViolationException;
+import org.apache.atlas.repository.graphdb.AtlasVertex;
+import org.apache.atlas.repository.graphdb.GremlinVersion;
+import org.apache.atlas.repository.graphdb.titan0.query.Titan0GraphQuery;
+import org.apache.atlas.repository.graphdb.utils.IteratorToIterableAdapter;
+import org.apache.atlas.typesystem.types.IDataType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import javax.script.Bindings;
+import javax.script.ScriptContext;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+import javax.script.ScriptException;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
/**
* Titan 0.5.4 implementation of AtlasGraph.
@@ -163,7 +161,12 @@
@Override
public AtlasIndexQuery<Titan0Vertex, Titan0Edge> indexQuery(String fulltextIndex, String graphQuery) {
- TitanIndexQuery query = getGraph().indexQuery(fulltextIndex, graphQuery);
+ return indexQuery(fulltextIndex, graphQuery, 0);
+ }
+
+ @Override
+ public AtlasIndexQuery<Titan0Vertex, Titan0Edge> indexQuery(String fulltextIndex, String graphQuery, int offset) {
+ TitanIndexQuery query = getGraph().indexQuery(fulltextIndex, graphQuery).offset(offset);
return new Titan0IndexQuery(this, query);
}
diff --git a/graphdb/titan0/src/test/resources/atlas-application.properties b/graphdb/titan0/src/test/resources/atlas-application.properties
index 636a9ff..3058330 100644
--- a/graphdb/titan0/src/test/resources/atlas-application.properties
+++ b/graphdb/titan0/src/test/resources/atlas-application.properties
@@ -50,6 +50,8 @@
atlas.graph.index.search.solr.mode=cloud
atlas.graph.index.search.solr.zookeeper-url=${solr.zk.address}
+# Solr-specific configuration property
+atlas.graph.index.search.max-result-set-size=150
######### Hive Lineage Configs #########
# This models reflects the base super types for Data and Process
diff --git a/graphdb/titan1/src/main/java/org/apache/atlas/repository/graphdb/titan1/Titan1Graph.java b/graphdb/titan1/src/main/java/org/apache/atlas/repository/graphdb/titan1/Titan1Graph.java
index 6a61075..e829d91 100644
--- a/graphdb/titan1/src/main/java/org/apache/atlas/repository/graphdb/titan1/Titan1Graph.java
+++ b/graphdb/titan1/src/main/java/org/apache/atlas/repository/graphdb/titan1/Titan1Graph.java
@@ -17,19 +17,18 @@
*/
package org.apache.atlas.repository.graphdb.titan1;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.script.Bindings;
-import javax.script.ScriptEngine;
-import javax.script.ScriptException;
-
+import com.google.common.base.Function;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.thinkaurelius.titan.core.Cardinality;
+import com.thinkaurelius.titan.core.PropertyKey;
+import com.thinkaurelius.titan.core.SchemaViolationException;
+import com.thinkaurelius.titan.core.TitanGraph;
+import com.thinkaurelius.titan.core.TitanIndexQuery;
+import com.thinkaurelius.titan.core.schema.TitanGraphIndex;
+import com.thinkaurelius.titan.core.schema.TitanManagement;
+import com.thinkaurelius.titan.core.util.TitanCleanup;
import org.apache.atlas.AtlasErrorCode;
import org.apache.atlas.exception.AtlasBaseException;
import org.apache.atlas.groovy.GroovyExpression;
@@ -57,18 +56,17 @@
import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONMapper;
import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONWriter;
-import com.google.common.base.Function;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.thinkaurelius.titan.core.Cardinality;
-import com.thinkaurelius.titan.core.PropertyKey;
-import com.thinkaurelius.titan.core.SchemaViolationException;
-import com.thinkaurelius.titan.core.TitanGraph;
-import com.thinkaurelius.titan.core.TitanIndexQuery;
-import com.thinkaurelius.titan.core.schema.TitanGraphIndex;
-import com.thinkaurelius.titan.core.schema.TitanManagement;
-import com.thinkaurelius.titan.core.util.TitanCleanup;
+import javax.script.Bindings;
+import javax.script.ScriptEngine;
+import javax.script.ScriptException;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
/**
* Titan 1.0.0 implementation of AtlasGraph.
@@ -179,7 +177,12 @@
@Override
public AtlasIndexQuery<Titan1Vertex, Titan1Edge> indexQuery(String fulltextIndex, String graphQuery) {
- TitanIndexQuery query = getGraph().indexQuery(fulltextIndex, graphQuery);
+ return indexQuery(fulltextIndex, graphQuery, 0);
+ }
+
+ @Override
+ public AtlasIndexQuery<Titan1Vertex, Titan1Edge> indexQuery(String fulltextIndex, String graphQuery, int offset) {
+ TitanIndexQuery query = getGraph().indexQuery(fulltextIndex, graphQuery).offset(offset);
return new Titan1IndexQuery(this, query);
}
diff --git a/repository/src/main/java/org/apache/atlas/discovery/EntityDiscoveryService.java b/repository/src/main/java/org/apache/atlas/discovery/EntityDiscoveryService.java
index e6a06c3..1b4583a 100644
--- a/repository/src/main/java/org/apache/atlas/discovery/EntityDiscoveryService.java
+++ b/repository/src/main/java/org/apache/atlas/discovery/EntityDiscoveryService.java
@@ -17,14 +17,16 @@
*/
package org.apache.atlas.discovery;
+import org.apache.atlas.ApplicationProperties;
import org.apache.atlas.AtlasConfiguration;
import org.apache.atlas.AtlasErrorCode;
-import org.apache.atlas.model.discovery.AtlasSearchResult.AtlasFullTextResult;
-import org.apache.atlas.model.discovery.AtlasSearchResult.AtlasQueryType;
-import org.apache.atlas.model.discovery.AtlasSearchResult.AttributeSearchResult;
+import org.apache.atlas.AtlasException;
import org.apache.atlas.discovery.graph.DefaultGraphPersistenceStrategy;
import org.apache.atlas.exception.AtlasBaseException;
import org.apache.atlas.model.discovery.AtlasSearchResult;
+import org.apache.atlas.model.discovery.AtlasSearchResult.AtlasFullTextResult;
+import org.apache.atlas.model.discovery.AtlasSearchResult.AtlasQueryType;
+import org.apache.atlas.model.discovery.AtlasSearchResult.AttributeSearchResult;
import org.apache.atlas.model.instance.AtlasEntity.Status;
import org.apache.atlas.model.instance.AtlasEntityHeader;
import org.apache.atlas.query.Expressions.AliasExpression;
@@ -83,14 +85,20 @@
private final EntityGraphRetriever entityRetriever;
private final AtlasGremlinQueryProvider gremlinQueryProvider;
private final AtlasTypeRegistry typeRegistry;
+ private final int maxResultSetSize;
+ private final int maxTypesCountInIdxQuery;
+ private final int maxTagsCountInIdxQuery;
@Inject
- EntityDiscoveryService(MetadataRepository metadataRepository, AtlasTypeRegistry typeRegistry) {
+ EntityDiscoveryService(MetadataRepository metadataRepository, AtlasTypeRegistry typeRegistry) throws AtlasException {
this.graph = AtlasGraphProvider.getGraphInstance();
this.graphPersistenceStrategy = new DefaultGraphPersistenceStrategy(metadataRepository);
this.entityRetriever = new EntityGraphRetriever(typeRegistry);
this.gremlinQueryProvider = AtlasGremlinQueryProvider.INSTANCE;
this.typeRegistry = typeRegistry;
+ this.maxResultSetSize = ApplicationProperties.get().getInt("atlas.graph.index.search.max-result-set-size", 150);
+ this.maxTypesCountInIdxQuery = ApplicationProperties.get().getInt("atlas.graph.index.search.max-types-count", 10);
+ this.maxTagsCountInIdxQuery = ApplicationProperties.get().getInt("atlas.graph.index.search.max-tags-count", 10);
}
@Override
@@ -217,7 +225,7 @@
if (attribute == null) {
throw new AtlasBaseException(AtlasErrorCode.UNKNOWN_ATTRIBUTE, attrName, typeName);
}
-
+
} else {
// if attrName is null|empty iterate defaultAttrNames to get attribute value
final List<String> defaultAttrNames = new ArrayList<>(Arrays.asList("qualifiedName", "name"));
@@ -238,7 +246,7 @@
} else {
attrQualifiedName = attribute.getQualifiedName();
- String attrQuery = String.format("%s AND (%s *)", attrName, attrValuePrefix.replaceAll("\\.", " "));
+ String attrQuery = String.format("%s AND (%s *)", attrName, attrValuePrefix.replaceAll("\\.", " "));
query = StringUtils.isEmpty(query) ? attrQuery : String.format("(%s) AND (%s)", query, attrQuery);
}
@@ -252,59 +260,72 @@
// if query was provided, perform indexQuery and filter for typeName & classification in memory; this approach
// results in a faster and accurate results than using CONTAINS/CONTAINS_PREFIX filter on entityText property
if (StringUtils.isNotEmpty(query)) {
- final String idxQuery = String.format("v.\"%s\":(%s)", Constants.ENTITY_TEXT_PROPERTY_KEY, query);
- final Iterator<Result<?,?>> qryResult = graph.indexQuery(Constants.FULLTEXT_INDEX, idxQuery).vertices();
- final int startIdx = params.offset();
- final int resultSize = params.limit();
+ final String idxQuery = getQueryForFullTextSearch(query, typeName, classification);
+ final int startIdx = params.offset();
+ final int resultSize = params.limit();
+ int resultIdx = 0;
- int resultIdx = 0;
+ for (int indexQueryOffset = 0; ; indexQueryOffset += getMaxResultSetSize()) {
+ final Iterator<Result<?, ?>> qryResult = graph.indexQuery(Constants.FULLTEXT_INDEX, idxQuery, indexQueryOffset).vertices();
- while (qryResult.hasNext()) {
- AtlasVertex<?,?> vertex = qryResult.next().getVertex();
-
- String vertexTypeName = GraphHelper.getTypeName(vertex);
-
- // skip non-entity vertices
- if (StringUtils.isEmpty(vertexTypeName) || StringUtils.isEmpty(GraphHelper.getGuid(vertex))) {
- continue;
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("indexQuery: query=" + idxQuery + "; offset=" + indexQueryOffset);
}
- if (typeNames != null && !typeNames.contains(vertexTypeName)) {
- continue;
+ if(!qryResult.hasNext()) {
+ break;
}
- if (classificationNames != null) {
- List<String> traitNames = GraphHelper.getTraitNames(vertex);
+ while (qryResult.hasNext()) {
+ AtlasVertex<?, ?> vertex = qryResult.next().getVertex();
+ String vertexTypeName = GraphHelper.getTypeName(vertex);
- if (CollectionUtils.isEmpty(traitNames) ||
- !CollectionUtils.containsAny(classificationNames, traitNames)) {
+ // skip non-entity vertices
+ if (StringUtils.isEmpty(vertexTypeName) || StringUtils.isEmpty(GraphHelper.getGuid(vertex))) {
continue;
}
+
+ if (typeNames != null && !typeNames.contains(vertexTypeName)) {
+ continue;
+ }
+
+ if (classificationNames != null) {
+ List<String> traitNames = GraphHelper.getTraitNames(vertex);
+
+ if (CollectionUtils.isEmpty(traitNames) ||
+ !CollectionUtils.containsAny(classificationNames, traitNames)) {
+ continue;
+ }
+ }
+
+ if (isAttributeSearch) {
+ String vertexAttrValue = vertex.getProperty(attrQualifiedName, String.class);
+
+ if (StringUtils.isNotEmpty(vertexAttrValue) && !vertexAttrValue.startsWith(attrValuePrefix)) {
+ continue;
+ }
+ }
+
+ if (skipDeletedEntities(excludeDeletedEntities, vertex)) {
+ continue;
+ }
+
+ resultIdx++;
+
+ if (resultIdx <= startIdx) {
+ continue;
+ }
+
+ AtlasEntityHeader header = entityRetriever.toAtlasEntityHeader(vertex);
+
+ ret.addEntity(header);
+
+ if (ret.getEntities().size() == resultSize) {
+ break;
+ }
}
- if (isAttributeSearch) {
- String vertexAttrValue = vertex.getProperty(attrQualifiedName, String.class);
-
- if (StringUtils.isNotEmpty(vertexAttrValue) && !vertexAttrValue.startsWith(attrValuePrefix)) {
- continue;
- }
- }
-
- if (skipDeletedEntities(excludeDeletedEntities, vertex)) {
- continue;
- }
-
- resultIdx++;
-
- if (resultIdx <= startIdx) {
- continue;
- }
-
- AtlasEntityHeader header = entityRetriever.toAtlasEntityHeader(vertex);
-
- ret.addEntity(header);
-
- if (ret.getEntities().size() == resultSize) {
+ if (ret.getEntities() != null && ret.getEntities().size() == resultSize) {
break;
}
}
@@ -347,7 +368,7 @@
Object result = graph.executeGremlinScript(scriptEngine, bindings, basicQuery, false);
if (result instanceof List && CollectionUtils.isNotEmpty((List) result)) {
- List queryResult = (List) result;
+ List queryResult = (List) result;
Object firstElement = queryResult.get(0);
if (firstElement instanceof AtlasVertex) {
@@ -371,6 +392,57 @@
return ret;
}
+ private String getQueryForFullTextSearch(String userKeyedString, String typeName, String classification) {
+ String typeFilter = getTypeFilter(typeRegistry, typeName, maxTypesCountInIdxQuery);
+ String classficationFilter = getClassificationFilter(typeRegistry, classification, maxTagsCountInIdxQuery);
+
+ StringBuilder queryText = new StringBuilder();
+
+ if (! StringUtils.isEmpty(userKeyedString)) {
+ queryText.append(userKeyedString);
+ }
+
+ if (! StringUtils.isEmpty(typeFilter)) {
+ if (queryText.length() > 0) {
+ queryText.append(" AND ");
+ }
+
+ queryText.append(typeFilter);
+ }
+
+ if (! StringUtils.isEmpty(classficationFilter)) {
+ if (queryText.length() > 0) {
+ queryText.append(" AND ");
+ }
+
+ queryText.append(classficationFilter);
+ }
+
+ return String.format("v.\"%s\":(%s)", Constants.ENTITY_TEXT_PROPERTY_KEY, queryText.toString());
+ }
+
+ private static String getClassificationFilter(AtlasTypeRegistry typeRegistry, String classificationName, int maxTypesCountInIdxQuery) {
+ AtlasClassificationType classification = typeRegistry.getClassificationTypeByName(classificationName);
+ Set<String> typeAndSubTypes = classification != null ? classification.getTypeAndAllSubTypes() : null;
+
+ if(CollectionUtils.isNotEmpty(typeAndSubTypes) && typeAndSubTypes.size() <= maxTypesCountInIdxQuery) {
+ return String.format("(%s)", StringUtils.join(typeAndSubTypes, " "));
+ }
+
+ return "";
+ }
+
+ private static String getTypeFilter(AtlasTypeRegistry typeRegistry, String typeName, int maxTypesCountInIdxQuery) {
+ AtlasEntityType type = typeRegistry.getEntityTypeByName(typeName);
+ Set<String> typeAndSubTypes = type != null ? type.getTypeAndAllSubTypes() : null;
+
+ if(CollectionUtils.isNotEmpty(typeAndSubTypes) && typeAndSubTypes.size() <= maxTypesCountInIdxQuery) {
+ return String.format("(%s)", StringUtils.join(typeAndSubTypes, " "));
+ }
+
+ return "";
+ }
+
private List<AtlasFullTextResult> getIndexQueryResults(AtlasIndexQuery query, QueryParams params, boolean excludeDeletedEntities) throws AtlasBaseException {
List<AtlasFullTextResult> ret = new ArrayList<>();
Iterator<Result> iter = query.vertices();
@@ -471,4 +543,8 @@
private boolean skipDeletedEntities(boolean excludeDeletedEntities, AtlasVertex<?, ?> vertex) {
return excludeDeletedEntities && GraphHelper.getStatus(vertex) == Status.DELETED;
}
+
+ public int getMaxResultSetSize() {
+ return maxResultSetSize;
+ }
}
diff --git a/repository/src/test/java/org/apache/atlas/services/EntityDiscoveryServiceTest.java b/repository/src/test/java/org/apache/atlas/services/EntityDiscoveryServiceTest.java
new file mode 100644
index 0000000..d503ef7
--- /dev/null
+++ b/repository/src/test/java/org/apache/atlas/services/EntityDiscoveryServiceTest.java
@@ -0,0 +1,124 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.atlas.services;
+
+import org.apache.atlas.TestOnlyModule;
+import org.apache.atlas.discovery.EntityDiscoveryService;
+import org.apache.atlas.exception.AtlasBaseException;
+import org.apache.atlas.model.typedef.AtlasEntityDef;
+import org.apache.atlas.type.AtlasTypeRegistry;
+import org.apache.commons.lang.StringUtils;
+import org.powermock.reflect.Whitebox;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Guice;
+import org.testng.annotations.Test;
+
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.testng.Assert.assertEquals;
+
+@Guice(modules = TestOnlyModule.class)
+public class EntityDiscoveryServiceTest {
+
+ private final String TEST_TYPE = "test";
+ private final String TEST_TYPE1 = "test1";
+ private final String TEST_TYPE2 = "test2";
+ private final String TEST_TYPE3 = "test3";
+ private final String TEST_TYPE_WITH_SUB_TYPES = "testTypeWithSubTypes";
+ private AtlasTypeRegistry typeRegistry = new AtlasTypeRegistry();
+
+ AtlasEntityDef typeTest = null;
+ AtlasEntityDef typeTest1 = null;
+ AtlasEntityDef typeTest2 = null;
+ AtlasEntityDef typeTest3 = null;
+ AtlasEntityDef typeWithSubTypes = null;
+
+ private final int maxTypesCountInIdxQuery = 10;
+
+
+ @BeforeClass
+ public void init() throws AtlasBaseException {
+ typeTest = new AtlasEntityDef(TEST_TYPE);
+ typeTest1 = new AtlasEntityDef(TEST_TYPE1);
+ typeTest2 = new AtlasEntityDef(TEST_TYPE2);
+ typeTest3 = new AtlasEntityDef(TEST_TYPE3);
+ typeWithSubTypes = new AtlasEntityDef(TEST_TYPE_WITH_SUB_TYPES);
+
+ typeTest1.addSuperType(TEST_TYPE_WITH_SUB_TYPES);
+ typeTest2.addSuperType(TEST_TYPE_WITH_SUB_TYPES);
+ typeTest3.addSuperType(TEST_TYPE_WITH_SUB_TYPES);
+
+ AtlasTypeRegistry.AtlasTransientTypeRegistry ttr = typeRegistry.lockTypeRegistryForUpdate();
+
+ ttr.addType(typeTest);
+ ttr.addType(typeWithSubTypes);
+ ttr.addType(typeTest1);
+ ttr.addType(typeTest2);
+ ttr.addType(typeTest3);
+
+ typeRegistry.releaseTypeRegistryForUpdate(ttr, true);
+ }
+
+ @Test
+ public void getSubTypesForType_NullStringReturnsEmptyString() throws Exception {
+ invokeGetSubTypesForType(null, maxTypesCountInIdxQuery);
+ }
+
+ @Test
+ public void getSubTypesForType_BlankStringReturnsEmptyString() throws Exception {
+ invokeGetSubTypesForType(" ", maxTypesCountInIdxQuery);
+ }
+
+ @Test
+ public void getSubTypesForType_EmptyStringReturnsEmptyString() throws Exception {
+ invokeGetSubTypesForType("", maxTypesCountInIdxQuery);
+ }
+
+ @Test
+ public void getSubTypeForTypeWithNoSubType_ReturnsTypeString() throws Exception {
+ String s = invokeGetSubTypesForType(TEST_TYPE, 10);
+
+ assertEquals(s, "(" + TEST_TYPE + ")");
+ }
+
+ @Test
+ public void getSubTypeForTypeWithSubTypes_ReturnsOrClause() throws Exception {
+ String s = invokeGetSubTypesForType(TEST_TYPE_WITH_SUB_TYPES, maxTypesCountInIdxQuery);
+
+ assertTrue(s.startsWith("(" + TEST_TYPE_WITH_SUB_TYPES));
+ assertTrue(s.contains(" " + TEST_TYPE1));
+ assertTrue(s.contains(" " + TEST_TYPE2));
+ assertTrue(s.contains(" " + TEST_TYPE3));
+ assertTrue(s.endsWith(")"));
+ }
+
+ @Test
+ public void getSubTypeForTypeWithSubTypes_ReturnsEmptyString() throws Exception {
+ String s = invokeGetSubTypesForType(TEST_TYPE_WITH_SUB_TYPES, 2);
+
+ assertTrue(StringUtils.isBlank(s));
+ }
+
+ private String invokeGetSubTypesForType(String inputString, int maxSubTypes) throws Exception {
+ String s = Whitebox.invokeMethod(EntityDiscoveryService.class, "getTypeFilter", typeRegistry, inputString, maxSubTypes);
+
+ assertNotNull(s);
+ return s;
+ }
+}
diff --git a/typesystem/src/test/resources/atlas-application.properties b/typesystem/src/test/resources/atlas-application.properties
index 5ffde5e..c4ce5ea 100644
--- a/typesystem/src/test/resources/atlas-application.properties
+++ b/typesystem/src/test/resources/atlas-application.properties
@@ -72,7 +72,7 @@
# Solr cloud mode properties
atlas.graph.index.search.solr.mode=cloud
atlas.graph.index.search.solr.zookeeper-url=${solr.zk.address}
-
+atlas.graph.index.search.max-result-set-size=150
######### Hive Lineage Configs #########
## Schema