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

sarath pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/atlas.git


The following commit(s) were added to refs/heads/master by this push:
     new 8b5cb9d  ATLAS-3838: Support multiple tag/classification in 
basic/quick search API ATLAS-3652: Quick Search: API requirement for GET 
request on multiple entity types
8b5cb9d is described below

commit 8b5cb9d9aa9f977ba5dfc455dfe440dd55eace06
Author: Pinal Shah <[email protected]>
AuthorDate: Fri Jun 26 11:24:46 2020 +0530

    ATLAS-3838: Support multiple tag/classification in basic/quick search API
    ATLAS-3652: Quick Search: API requirement for GET request on multiple 
entity types
    
    Signed-off-by: Sarath Subramanian <[email protected]>
    
    both JIRA's addressed in the same commit.
---
 .../repository/graphdb/AggregationContext.java     |  38 +--
 .../graphdb/janus/AtlasJanusGraphIndexClient.java  |   2 +-
 .../graphdb/janus/AtlasSolrQueryBuilder.java       | 151 +++++----
 .../graphdb/janus/AtlasSolrQueryBuilderTest.java   |  54 +++-
 .../src/test/resources/searchparameters2Types.json |  19 ++
 .../discovery/ClassificationSearchProcessor.java   |  34 +-
 .../atlas/discovery/EntityDiscoveryService.java    |   8 +-
 .../atlas/discovery/EntitySearchProcessor.java     |  53 ++--
 .../atlas/discovery/FreeTextSearchProcessor.java   |   7 +-
 .../atlas/discovery/FullTextSearchProcessor.java   |  19 +-
 .../atlas/discovery/GraphIndexQueryBuilder.java    |  25 +-
 .../atlas/discovery/SearchAggregatorImpl.java      |   7 +-
 .../org/apache/atlas/discovery/SearchContext.java  | 253 +++++++++++----
 .../apache/atlas/discovery/SearchProcessor.java    | 343 +++++++++++++--------
 .../atlas/discovery/EntitySearchProcessorTest.java | 114 ++++++-
 15 files changed, 750 insertions(+), 377 deletions(-)

diff --git 
a/graphdb/api/src/main/java/org/apache/atlas/repository/graphdb/AggregationContext.java
 
b/graphdb/api/src/main/java/org/apache/atlas/repository/graphdb/AggregationContext.java
index 6006fef..efde79b 100644
--- 
a/graphdb/api/src/main/java/org/apache/atlas/repository/graphdb/AggregationContext.java
+++ 
b/graphdb/api/src/main/java/org/apache/atlas/repository/graphdb/AggregationContext.java
@@ -25,14 +25,14 @@ import java.util.Map;
 import java.util.Set;
 
 public class AggregationContext {
-    private final String              queryString;
-    private final FilterCriteria      filterCriteria;
-    private final AtlasEntityType     searchForEntityType;
-    private final Set<String>         aggregationFieldNames;
-    private final Set<AtlasAttribute> aggregationAttributes;
-    private final Map<String, String> indexFieldNameCache;
-    private final boolean             excludeDeletedEntities;
-    private final boolean             includeSubTypes;
+    private final String               queryString;
+    private final FilterCriteria       filterCriteria;
+    private final Set<AtlasEntityType> searchForEntityTypes;
+    private final Set<String>          aggregationFieldNames;
+    private final Set<AtlasAttribute>  aggregationAttributes;
+    private final Map<String, String>  indexFieldNameCache;
+    private final boolean              excludeDeletedEntities;
+    private final boolean              includeSubTypes;
 
     /**
      * @param queryString the query string whose aggregation metrics need to 
be retrieved.
@@ -41,17 +41,17 @@ public class AggregationContext {
      * @param indexFieldNameCache
      * @param excludeDeletedEntities a boolean flag to indicate if the deleted 
entities need to be excluded in search
      */
-    public AggregationContext(String              queryString,
-                              FilterCriteria      filterCriteria,
-                              AtlasEntityType     searchForEntityType,
-                              Set<String>         aggregationFieldNames,
-                              Set<AtlasAttribute> aggregationAttributes,
-                              Map<String, String> indexFieldNameCache,
-                              boolean             excludeDeletedEntities,
-                              boolean             includeSubTypes) {
+    public AggregationContext(String               queryString,
+                              FilterCriteria       filterCriteria,
+                              Set<AtlasEntityType> searchForEntityType,
+                              Set<String>          aggregationFieldNames,
+                              Set<AtlasAttribute>  aggregationAttributes,
+                              Map<String, String>  indexFieldNameCache,
+                              boolean              excludeDeletedEntities,
+                              boolean              includeSubTypes) {
         this.queryString            = queryString;
         this.filterCriteria         = filterCriteria;
-        this.searchForEntityType    = searchForEntityType;
+        this.searchForEntityTypes   = searchForEntityType;
         this.aggregationFieldNames  = aggregationFieldNames;
         this.aggregationAttributes  = aggregationAttributes;
         this.indexFieldNameCache    = indexFieldNameCache;
@@ -67,8 +67,8 @@ public class AggregationContext {
         return filterCriteria;
     }
 
-    public AtlasEntityType getSearchForEntityType() {
-        return searchForEntityType;
+    public Set<AtlasEntityType> getSearchForEntityTypes() {
+        return searchForEntityTypes;
     }
 
     public Set<String> getAggregationFieldNames() {
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 29bd2a4..8142514 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
@@ -175,7 +175,7 @@ public class AtlasJanusGraphIndexClient implements 
AtlasGraphIndexClient {
             Map<String, String>   indexFieldName2PropertyKeyNameMap = new 
HashMap<>();
             AtlasSolrQueryBuilder solrQueryBuilder                  = new 
AtlasSolrQueryBuilder();
 
-            
solrQueryBuilder.withEntityType(aggregationContext.getSearchForEntityType())
+            
solrQueryBuilder.withEntityTypes(aggregationContext.getSearchForEntityTypes())
                             
.withQueryString(aggregationContext.getQueryString())
                             
.withCriteria(aggregationContext.getFilterCriteria())
                             
.withExcludedDeletedEntities(aggregationContext.isExcludeDeletedEntities())
diff --git 
a/graphdb/janus/src/main/java/org/apache/atlas/repository/graphdb/janus/AtlasSolrQueryBuilder.java
 
b/graphdb/janus/src/main/java/org/apache/atlas/repository/graphdb/janus/AtlasSolrQueryBuilder.java
index b8fd4a0..6c06a3c 100644
--- 
a/graphdb/janus/src/main/java/org/apache/atlas/repository/graphdb/janus/AtlasSolrQueryBuilder.java
+++ 
b/graphdb/janus/src/main/java/org/apache/atlas/repository/graphdb/janus/AtlasSolrQueryBuilder.java
@@ -29,31 +29,28 @@ import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 
 import static 
org.apache.atlas.repository.Constants.CUSTOM_ATTRIBUTES_PROPERTY_KEY;
 
 public class AtlasSolrQueryBuilder {
     private static final Logger LOG = 
LoggerFactory.getLogger(AtlasSolrQueryBuilder.class);
 
-    private AtlasEntityType     entityType;
-    private String              queryString;
-    private FilterCriteria      criteria;
-    private boolean             excludeDeletedEntities;
-    private boolean             includeSubtypes;
-    private Map<String, String> indexFieldNameCache;
-    public static final char    CUSTOM_ATTR_SEPARATOR      = '=';
-    public static final String  CUSTOM_ATTR_SEARCH_FORMAT  = 
"\"\\\"%s\\\":\\\"%s\\\"\"";
+    private Set<AtlasEntityType> entityTypes;
+    private String               queryString;
+    private FilterCriteria       criteria;
+    private boolean              excludeDeletedEntities;
+    private boolean              includeSubtypes;
+    private Map<String, String>  indexFieldNameCache;
+    public static final char     CUSTOM_ATTR_SEPARATOR      = '=';
+    public static final String   CUSTOM_ATTR_SEARCH_FORMAT  = 
"\"\\\"%s\\\":\\\"%s\\\"\"";
 
 
     public AtlasSolrQueryBuilder() {
     }
 
-    public AtlasSolrQueryBuilder withEntityType(AtlasEntityType 
searchForEntityType) {
-        this.entityType = searchForEntityType;
+    public AtlasSolrQueryBuilder withEntityTypes(Set<AtlasEntityType> 
searchForEntityTypes) {
+        this.entityTypes = searchForEntityTypes;
 
         return this;
     }
@@ -112,7 +109,7 @@ public class AtlasSolrQueryBuilder {
             isAndNeeded = true;
         }
 
-        if (entityType != null) {
+        if (CollectionUtils.isNotEmpty(entityTypes)) {
             if (isAndNeeded) {
                 queryBuilder.append(" AND ");
             }
@@ -140,29 +137,25 @@ public class AtlasSolrQueryBuilder {
     }
 
     private void buildForEntityType(StringBuilder queryBuilder) {
-        if (LOG.isDebugEnabled()) {
-            LOG.debug("Search is being done for entities of type {}", 
entityType.getTypeName());
-        }
 
         String typeIndexFieldName = 
indexFieldNameCache.get(Constants.ENTITY_TYPE_PROPERTY_KEY);
 
         queryBuilder.append(" +")
                     .append(typeIndexFieldName)
-                    .append(":(")
-                    .append(entityType.getTypeName())
-                    .append(" ");
+                    .append(":(");
 
-        if (includeSubtypes) {
-            Set<String> allSubTypes = entityType.getAllSubTypes();
+        Set<String> typesToSearch = new HashSet<>();
+        for (AtlasEntityType type : entityTypes) {
 
-            if(allSubTypes.size() != 0 ) {
-                for(String subTypeName: allSubTypes) {
-                    queryBuilder.append(subTypeName).append(" ");
-                }
+            if (includeSubtypes) {
+                typesToSearch.addAll(type.getTypeAndAllSubTypes());
+            } else {
+                typesToSearch.add(type.getTypeName());
             }
         }
 
-        queryBuilder.append(" ) ");
+        queryBuilder.append(StringUtils.join(typesToSearch, " ")).append(" ) 
");
+
     }
 
     private void dropDeletedEntities(StringBuilder queryBuilder) throws 
AtlasBaseException {
@@ -173,9 +166,8 @@ public class AtlasSolrQueryBuilder {
         String indexFieldName = 
indexFieldNameCache.get(Constants.STATE_PROPERTY_KEY);
 
         if (indexFieldName == null) {
-            String msg = String.format("There is no index field name defined 
for attribute '%s' for entity '%s'",
-                                       Constants.STATE_PROPERTY_KEY,
-                                       entityType.getTypeName());
+            String msg = String.format("There is no index field name defined 
for attribute '%s'",
+                                       Constants.STATE_PROPERTY_KEY);
 
             LOG.error(msg);
 
@@ -187,10 +179,46 @@ public class AtlasSolrQueryBuilder {
 
     private  AtlasSolrQueryBuilder withCriteria(StringBuilder queryBuilder, 
FilterCriteria criteria) throws AtlasBaseException {
         List<FilterCriteria> criterion = criteria.getCriterion();
+        Set<String> indexAttributes    = new HashSet<>();
+        if (StringUtils.isNotEmpty(criteria.getAttributeName()) && 
CollectionUtils.isEmpty(criterion)) { // no child criterion
+
+            String   attributeName  = criteria.getAttributeName();
+            String   attributeValue = criteria.getAttributeValue();
+            Operator operator       = criteria.getOperator();
+
+            ArrayList<StringBuilder> orExpQuery = new ArrayList<>();
+
+            for (AtlasEntityType type : entityTypes) {
+                String indexAttributeName = getIndexAttributeName(type, 
attributeName);
+
+                //check to remove duplicate attribute query (for eg. name)
+                if (!indexAttributes.contains(indexAttributeName)) {
+                    StringBuilder sb   = new StringBuilder();
+
+                    if (attributeName.equals(CUSTOM_ATTRIBUTES_PROPERTY_KEY) 
&& operator.equals(Operator.CONTAINS)) {
+                        // CustomAttributes stores key value pairs in String 
format, so ideally it should be 'contains' operator to search for one pair,
+                        // for use-case, E1 having key1=value1 and E2 having 
key1=value2, searching key1=value1 results both E1,E2
+                        // surrounding inverted commas to attributeValue works
+                        operator       = Operator.EQ;
+                        attributeValue = 
getIndexQueryAttributeValue(attributeValue);
+                    }
+
+                    withPropertyCondition(sb, indexAttributeName, operator, 
attributeValue);
+                    indexAttributes.add(indexAttributeName);
+                    orExpQuery.add(sb);
+                }
+            }
+
+            if (CollectionUtils.isNotEmpty(orExpQuery)) {
+                if (orExpQuery.size() > 1) {
+                    String orExpStr = StringUtils.join(orExpQuery, 
FilterCriteria.Condition.OR.name());
+                    queryBuilder.append(" ( ").append(orExpStr).append(" ) ");
+                } else {
+                    queryBuilder.append(orExpQuery.iterator().next());
+                }
+            }
 
-        if(criterion == null || 
CollectionUtils.isEmpty(criteria.getCriterion())) { // no child criterion
-            withPropertyCondition(queryBuilder, criteria.getAttributeName(), 
criteria.getOperator(), criteria.getAttributeValue());
-        } else {
+        } else if (CollectionUtils.isNotEmpty(criterion)) {
             beginCriteria(queryBuilder);
 
             for (Iterator<FilterCriteria> iterator = criterion.iterator(); 
iterator.hasNext(); ) {
@@ -209,40 +237,12 @@ public class AtlasSolrQueryBuilder {
         return this;
     }
 
-    private void withPropertyCondition(StringBuilder queryBuilder, String 
attributeName, Operator operator, String attributeValue) throws 
AtlasBaseException {
-        if (StringUtils.isNotEmpty(attributeName) && operator != null) {
+    private void withPropertyCondition(StringBuilder queryBuilder, String 
indexFieldName, Operator operator, String attributeValue) throws 
AtlasBaseException {
+        if (StringUtils.isNotEmpty(indexFieldName) && operator != null) {
             if (attributeValue != null) {
                 attributeValue = attributeValue.trim();
             }
 
-            if (attributeName.equals(CUSTOM_ATTRIBUTES_PROPERTY_KEY) && 
operator.equals(Operator.CONTAINS)) {
-                // CustomAttributes stores key value pairs in String format, 
so ideally it should be 'contains' operator to search for one pair,
-                // for use-case, E1 having key1=value1 and E2 having 
key1=value2, searching key1=value1 results both E1,E2
-                // surrounding inverted commas to attributeValue works
-                operator       = Operator.EQ;
-                attributeValue = getIndexQueryAttributeValue(attributeValue);
-            }
-
-            AtlasAttribute attribute = entityType.getAttribute(attributeName);
-
-            if (attribute == null) {
-                String msg = String.format("Received unknown attribute '%s' 
for type '%s'.", attributeName, entityType.getTypeName());
-
-                LOG.error(msg);
-
-                throw new AtlasBaseException(msg);
-            }
-
-            String indexFieldName = attribute.getIndexFieldName();
-
-            if (indexFieldName == null) {
-                String msg = String.format("Received non-index attribute %s 
for type %s.", attributeName, entityType.getTypeName());
-
-                LOG.error(msg);
-
-                throw new AtlasBaseException(msg);
-            }
-
             beginCriteria(queryBuilder);
 
             switch (operator) {
@@ -308,6 +308,29 @@ public class AtlasSolrQueryBuilder {
         return attributeValue;
     }
 
+    private String getIndexAttributeName(AtlasEntityType type, String 
attrName) throws AtlasBaseException {
+        AtlasAttribute ret = type.getAttribute(attrName);
+
+        if (ret == null) {
+            String msg = String.format("Received unknown attribute '%s' for 
type '%s'.", attrName, type.getTypeName());
+
+            LOG.error(msg);
+
+            throw new AtlasBaseException(msg);
+        }
+
+        String indexFieldName = ret.getIndexFieldName();
+
+        if (indexFieldName == null) {
+            String msg = String.format("Received non-index attribute %s for 
type %s.", attrName, type.getTypeName());
+
+            LOG.error(msg);
+
+            throw new AtlasBaseException(msg);
+        }
+
+        return indexFieldName;
+    }
 
     private void beginCriteria(StringBuilder queryBuilder) {
         queryBuilder.append("( ");
diff --git 
a/graphdb/janus/src/test/java/org/apache/atlas/repository/graphdb/janus/AtlasSolrQueryBuilderTest.java
 
b/graphdb/janus/src/test/java/org/apache/atlas/repository/graphdb/janus/AtlasSolrQueryBuilderTest.java
index 60d8610..06c7221 100644
--- 
a/graphdb/janus/src/test/java/org/apache/atlas/repository/graphdb/janus/AtlasSolrQueryBuilderTest.java
+++ 
b/graphdb/janus/src/test/java/org/apache/atlas/repository/graphdb/janus/AtlasSolrQueryBuilderTest.java
@@ -33,8 +33,10 @@ import org.testng.annotations.Test;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import static org.mockito.Mockito.when;
 
@@ -45,6 +47,9 @@ public class AtlasSolrQueryBuilderTest {
     private AtlasEntityType hiveTableEntityTypeMock;
 
     @Mock
+    private AtlasEntityType hiveTableEntityTypeMock2;
+
+    @Mock
     private AtlasStructType.AtlasAttribute nameAttributeMock;
 
     @Mock
@@ -95,6 +100,7 @@ public class AtlasSolrQueryBuilderTest {
 
 
         when(hiveTableEntityTypeMock.getTypeName()).thenReturn("hive_table");
+        when(hiveTableEntityTypeMock2.getTypeName()).thenReturn("hive_db");
 
         when(nameAttributeMock.getIndexFieldName()).thenReturn("name_index");
         
when(commentAttributeMock.getIndexFieldName()).thenReturn("comment_index");
@@ -114,7 +120,7 @@ public class AtlasSolrQueryBuilderTest {
 
         processSearchParameters(fileName, underTest);
 
-        Assert.assertEquals(underTest.build(), "+t  AND  
-__state_index:DELETED AND  +__typeName__index:(hive_table  )  AND  ( ( 
+name_index:t10  ) OR ( +comment_index:*t10*  ) )");
+        Assert.assertEquals(underTest.build(), "+t  AND  
-__state_index:DELETED AND  +__typeName__index:(hive_table )  AND  ( ( 
+name_index:t10  ) OR ( +comment_index:*t10*  ) )");
     }
 
     @Test
@@ -124,7 +130,7 @@ public class AtlasSolrQueryBuilderTest {
 
         processSearchParameters(fileName, underTest);
 
-        Assert.assertEquals(underTest.build(), "+t  AND  
-__state_index:DELETED AND  +__typeName__index:(hive_table  )  AND  ( ( 
+name_index:t10  ) )");
+        Assert.assertEquals(underTest.build(), "+t  AND  
-__state_index:DELETED AND  +__typeName__index:(hive_table )  AND  ( ( 
+name_index:t10  ) )");
     }
 
     @Test
@@ -134,7 +140,7 @@ public class AtlasSolrQueryBuilderTest {
 
         processSearchParameters(fileName, underTest);
 
-        Assert.assertEquals(underTest.build(), "+t  AND  
-__state_index:DELETED AND  +__typeName__index:(hive_table  )  AND  ( ( 
+name_index:t10  ) AND ( +comment_index:*t10*  ) )");
+        Assert.assertEquals(underTest.build(), "+t  AND  
-__state_index:DELETED AND  +__typeName__index:(hive_table )  AND  ( ( 
+name_index:t10  ) AND ( +comment_index:*t10*  ) )");
     }
 
     @Test
@@ -144,7 +150,7 @@ public class AtlasSolrQueryBuilderTest {
 
         processSearchParameters(fileName, underTest);
 
-        Assert.assertEquals(underTest.build(), "+t  AND  
-__state_index:DELETED AND  +__typeName__index:(hive_table  )  AND  ( ( 
+name_index:t10  ) )");
+        Assert.assertEquals(underTest.build(), "+t  AND  
-__state_index:DELETED AND  +__typeName__index:(hive_table )  AND  ( ( 
+name_index:t10  ) )");
     }
 
     @Test
@@ -154,7 +160,7 @@ public class AtlasSolrQueryBuilderTest {
 
         processSearchParameters(fileName, underTest);
 
-        Assert.assertEquals(underTest.build(), "+t  AND  
-__state_index:DELETED AND  +__typeName__index:(hive_table  )  AND  ( 
+name_index:t10  )");
+        Assert.assertEquals(underTest.build(), "+t  AND  
-__state_index:DELETED AND  +__typeName__index:(hive_table )  AND  ( 
+name_index:t10  )");
     }
 
     @Test
@@ -164,7 +170,7 @@ public class AtlasSolrQueryBuilderTest {
 
         processSearchParameters(fileName, underTest);
 
-        Assert.assertEquals(underTest.build(), "+t10  AND  
-__state_index:DELETED AND  +__typeName__index:(hive_table  )  AND  ( ( 
+comment_index:*United States*  ) AND ( +descrption__index:*nothing*  ) AND ( 
+name_index:*t100*  ) )");
+        Assert.assertEquals(underTest.build(), "+t10  AND  
-__state_index:DELETED AND  +__typeName__index:(hive_table )  AND  ( ( 
+comment_index:*United States*  ) AND ( +descrption__index:*nothing*  ) AND ( 
+name_index:*t100*  ) )");
     }
 
     @Test
@@ -174,7 +180,7 @@ public class AtlasSolrQueryBuilderTest {
 
         processSearchParameters(fileName, underTest);
 
-        Assert.assertEquals(underTest.build(), "+t10  AND  
-__state_index:DELETED AND  +__typeName__index:(hive_table  )  AND  ( ( 
+created__index:{ 100 TO * ]  ) )");
+        Assert.assertEquals(underTest.build(), "+t10  AND  
-__state_index:DELETED AND  +__typeName__index:(hive_table )  AND  ( ( 
+created__index:{ 100 TO * ]  ) )");
     }
 
     @Test
@@ -184,7 +190,7 @@ public class AtlasSolrQueryBuilderTest {
 
         processSearchParameters(fileName, underTest);
 
-        Assert.assertEquals(underTest.build(), "+t10  AND  
-__state_index:DELETED AND  +__typeName__index:(hive_table  )  AND  ( ( 
+created__index:[ 100 TO * ]  ) AND ( +started__index:[ 100 TO * ]  ) )");
+        Assert.assertEquals(underTest.build(), "+t10  AND  
-__state_index:DELETED AND  +__typeName__index:(hive_table )  AND  ( ( 
+created__index:[ 100 TO * ]  ) AND ( +started__index:[ 100 TO * ]  ) )");
     }
 
     @Test
@@ -194,7 +200,7 @@ public class AtlasSolrQueryBuilderTest {
 
         processSearchParameters(fileName, underTest);
 
-        Assert.assertEquals(underTest.build(), "+t10  AND  
-__state_index:DELETED AND  +__typeName__index:(hive_table  )  AND  ( ( 
+created__index:[ * TO100}  ) )");
+        Assert.assertEquals(underTest.build(), "+t10  AND  
-__state_index:DELETED AND  +__typeName__index:(hive_table )  AND  ( ( 
+created__index:[ * TO100}  ) )");
     }
 
     @Test
@@ -204,7 +210,7 @@ public class AtlasSolrQueryBuilderTest {
 
         processSearchParameters(fileName, underTest);
 
-        Assert.assertEquals(underTest.build(), "+t10  AND  
-__state_index:DELETED AND  +__typeName__index:(hive_table  )  AND  ( ( 
+created__index:[ * TO 100 ]  ) AND ( +started__index:[ * TO 100 ]  ) )");
+        Assert.assertEquals(underTest.build(), "+t10  AND  
-__state_index:DELETED AND  +__typeName__index:(hive_table )  AND  ( ( 
+created__index:[ * TO 100 ]  ) AND ( +started__index:[ * TO 100 ]  ) )");
     }
 
     @Test
@@ -214,9 +220,18 @@ public class AtlasSolrQueryBuilderTest {
 
         processSearchParameters(fileName, underTest);
 
-        Assert.assertEquals(underTest.build(), " -__state_index:DELETED AND  
+__typeName__index:(hive_table  )  AND  ( ( +qualifiedName__index:testdb.t1*  ) 
)");
+        Assert.assertEquals(underTest.build(), " -__state_index:DELETED AND  
+__typeName__index:(hive_table )  AND  ( ( +qualifiedName__index:testdb.t1*  ) 
)");
     }
 
+    @Test
+    public void testGenerateSolrQueryString2TypeNames() throws IOException, 
AtlasBaseException {
+        final String fileName = 
"src/test/resources/searchparameters2Types.json";
+        AtlasSolrQueryBuilder underTest = new AtlasSolrQueryBuilder();
+
+        processSearchParametersForMultipleTypeNames(fileName, underTest);
+
+        Assert.assertEquals(underTest.build(), "+t  AND  
-__state_index:DELETED AND  +__typeName__index:(hive_table hive_db ) ");
+    }
 
 
 
@@ -243,8 +258,23 @@ public class AtlasSolrQueryBuilderTest {
         ObjectMapper mapper = new ObjectMapper();
         SearchParameters searchParameters =  mapper.readValue(new 
FileInputStream(fileName), SearchParameters.class);
 
+        Set<AtlasEntityType> hiveTableEntityTypeMocks = new HashSet<>();
+        hiveTableEntityTypeMocks.add(hiveTableEntityTypeMock);
+        underTest.withEntityTypes(hiveTableEntityTypeMocks)
+                .withQueryString(searchParameters.getQuery())
+                .withCriteria(searchParameters.getEntityFilters())
+                
.withExcludedDeletedEntities(searchParameters.getExcludeDeletedEntities())
+                .withCommonIndexFieldNames(indexFieldNamesMap);
+    }
+
+    private void processSearchParametersForMultipleTypeNames(String fileName, 
AtlasSolrQueryBuilder underTest) throws IOException, AtlasBaseException {
+        ObjectMapper mapper = new ObjectMapper();
+        SearchParameters searchParameters =  mapper.readValue(new 
FileInputStream(fileName), SearchParameters.class);
 
-        underTest.withEntityType(hiveTableEntityTypeMock)
+        Set<AtlasEntityType> hiveTableEntityTypeMocks = new HashSet<>();
+        hiveTableEntityTypeMocks.add(hiveTableEntityTypeMock);
+        hiveTableEntityTypeMocks.add(hiveTableEntityTypeMock2);
+        underTest.withEntityTypes(hiveTableEntityTypeMocks)
                 .withQueryString(searchParameters.getQuery())
                 .withCriteria(searchParameters.getEntityFilters())
                 
.withExcludedDeletedEntities(searchParameters.getExcludeDeletedEntities())
diff --git a/graphdb/janus/src/test/resources/searchparameters2Types.json 
b/graphdb/janus/src/test/resources/searchparameters2Types.json
new file mode 100644
index 0000000..77fc70f
--- /dev/null
+++ b/graphdb/janus/src/test/resources/searchparameters2Types.json
@@ -0,0 +1,19 @@
+
+{
+  "excludeDeletedEntities":true,
+  "includeSubClassifications":true,
+  "includeSubTypes":true,
+  "includeClassificationAttributes":true,
+  "entityFilters":{
+  },
+  "tagFilters":null,
+  "attributes":[
+    "comment"
+  ],
+  "query":"t",
+  "limit":25,
+  "offset":0,
+  "typeName":"hive_table,hive_db",
+  "classification":null,
+  "termName":null
+}
diff --git 
a/repository/src/main/java/org/apache/atlas/discovery/ClassificationSearchProcessor.java
 
b/repository/src/main/java/org/apache/atlas/discovery/ClassificationSearchProcessor.java
index 5dd0d7f..9c72cd4 100644
--- 
a/repository/src/main/java/org/apache/atlas/discovery/ClassificationSearchProcessor.java
+++ 
b/repository/src/main/java/org/apache/atlas/discovery/ClassificationSearchProcessor.java
@@ -67,17 +67,16 @@ public class ClassificationSearchProcessor extends 
SearchProcessor {
     public ClassificationSearchProcessor(SearchContext context) {
         super(context);
 
-        final AtlasClassificationType classificationType    = 
context.getClassificationType();
         final FilterCriteria          filterCriteria        = 
context.getSearchParameters().getTagFilters();
         final Set<String>             indexAttributes       = new HashSet<>();
         final Set<String>             graphAttributes       = new HashSet<>();
         final Set<String>             allAttributes         = new HashSet<>();
-        final Set<String>             typeAndSubTypes       = 
context.getClassificationTypes();
+        final Set<String>             typeAndSubTypes       = 
context.getClassificationTypeNames();
         final String                  typeAndSubTypesQryStr = 
context.getClassificationTypesQryStr();
-        final boolean isBuiltInType                         = 
context.isBuiltInClassificationType();
         final boolean isWildcardSearch                      = 
context.isWildCardSearch();
+        final Set<AtlasClassificationType> classificationTypes = 
context.getClassificationTypes();
 
-        processSearchAttributes(classificationType, filterCriteria, 
indexAttributes, graphAttributes, allAttributes);
+        processSearchAttributes(classificationTypes, filterCriteria, 
indexAttributes, graphAttributes, allAttributes);
 
         /* for classification search, if any attribute can't be handled by 
index query - switch to all filter by Graph query
            There are four cases in the classification type :
@@ -87,19 +86,25 @@ public class ClassificationSearchProcessor extends 
SearchProcessor {
            4. classification is not present in the search parameter
            each of above cases with either has empty/or not tagFilters
          */
-        final boolean useIndexSearchForEntity = (classificationType != null || 
isWildcardSearch) &&
+        final boolean useIndexSearchForEntity = 
(CollectionUtils.isNotEmpty(classificationTypes) || isWildcardSearch) &&
                                                 
!context.hasAttributeFilter(filterCriteria)  &&
                                                 
(typeAndSubTypesQryStr.length() <= MAX_QUERY_STR_LENGTH_TAGS);
 
         /* If classification's attributes can be applied index filter, we can 
use direct index
          * to query classification index as well.
          */
-        final boolean useIndexSearchForClassification = (!isBuiltInType && 
!isWildcardSearch) &&
+        final boolean useIndexSearchForClassification = 
(CollectionUtils.isNotEmpty(classificationTypes) &&
+                                                         
classificationTypes.iterator().next() != SearchContext.MATCH_ALL_NOT_CLASSIFIED 
&&
+                                                          !isWildcardSearch) &&
                                                         
(typeAndSubTypesQryStr.length() <= MAX_QUERY_STR_LENGTH_TAGS) &&
                                                         
CollectionUtils.isNotEmpty(indexAttributes) &&
-                                                        
canApplyIndexFilter(classificationType, filterCriteria, false);
+                                                        
canApplyIndexFilter(classificationTypes, filterCriteria, false);
 
-        traitPredicate    = buildTraitPredict(classificationType);
+        final boolean useGraphSearchForClassification = 
(CollectionUtils.isNotEmpty(classificationTypes) &&
+                                                        
classificationTypes.iterator().next() != SearchContext.MATCH_ALL_NOT_CLASSIFIED 
&&
+                                                        !isWildcardSearch && 
CollectionUtils.isNotEmpty(graphAttributes));
+
+        traitPredicate    = buildTraitPredict(classificationTypes);
         isEntityPredicate = 
SearchPredicateUtil.generateIsEntityVertexPredicate(context.getTypeRegistry());
 
         AtlasGraph graph = context.getGraph();
@@ -115,8 +120,7 @@ public class ClassificationSearchProcessor extends 
SearchProcessor {
                 // tagFilters is not allowed in wildcard search
                 
graphIndexQueryBuilder.addClassificationTypeFilter(queryString);
             } else {
-                if (isBuiltInType) {
-
+                if (classificationTypes.iterator().next() == 
SearchContext.MATCH_ALL_NOT_CLASSIFIED) {
                     // tagFilters is not allowed in unique classificationType 
search
                     
graphIndexQueryBuilder.addClassificationFilterForBuiltInTypes(queryString);
 
@@ -146,7 +150,7 @@ public class ClassificationSearchProcessor extends 
SearchProcessor {
             graphIndexQueryBuilder.addActiveStateQueryFilter(queryString);
             graphIndexQueryBuilder.addTypeAndSubTypesQueryFilter(queryString, 
typeAndSubTypesQryStr);
 
-            constructFilterQuery(queryString, classificationType, 
filterCriteria, indexAttributes);
+            constructFilterQuery(queryString, classificationTypes, 
filterCriteria, indexAttributes);
 
             String indexQueryString = 
STRAY_AND_PATTERN.matcher(queryString).replaceAll(")");
             indexQueryString = 
STRAY_OR_PATTERN.matcher(indexQueryString).replaceAll(")");
@@ -158,7 +162,7 @@ public class ClassificationSearchProcessor extends 
SearchProcessor {
                 inMemoryPredicate = inMemoryPredicate == null ? 
typeNamePredicate : PredicateUtils.andPredicate(inMemoryPredicate, 
typeNamePredicate);
             }
 
-            Predicate attributePredicate = 
constructInMemoryPredicate(classificationType, filterCriteria, indexAttributes);
+            Predicate attributePredicate = 
constructInMemoryPredicate(classificationTypes, filterCriteria, 
indexAttributes);
 
             if (attributePredicate != null) {
                 inMemoryPredicate = inMemoryPredicate == null ? 
attributePredicate : PredicateUtils.andPredicate(inMemoryPredicate, 
attributePredicate);
@@ -170,7 +174,7 @@ public class ClassificationSearchProcessor extends 
SearchProcessor {
         }
 
         // only registered classification will search with tag filters
-        if (!isWildcardSearch && !isBuiltInType && !graphAttributes.isEmpty()) 
{
+        if (useGraphSearchForClassification) {
 
             AtlasGremlinQueryProvider queryProvider = 
AtlasGremlinQueryProvider.INSTANCE;
             AtlasGraphQuery query = graph.query();
@@ -179,7 +183,7 @@ public class ClassificationSearchProcessor extends 
SearchProcessor {
                 query.in(Constants.TYPE_NAME_PROPERTY_KEY, typeAndSubTypes);
             }
 
-            tagGraphQueryWithAttributes = 
toGraphFilterQuery(classificationType, filterCriteria, allAttributes, query);
+            tagGraphQueryWithAttributes = 
toGraphFilterQuery(classificationTypes, filterCriteria, allAttributes, query);
             gremlinQueryBindings       = new HashMap<>();
             StringBuilder gremlinQuery = new StringBuilder();
 
@@ -188,7 +192,7 @@ public class ClassificationSearchProcessor extends 
SearchProcessor {
             gremlinQuery.append(".as('e').filter(out()");
             
gremlinQuery.append(queryProvider.getQuery(AtlasGremlinQueryProvider.AtlasGremlinQuery.BASIC_SEARCH_TYPE_FILTER));
 
-            constructGremlinFilterQuery(gremlinQuery, gremlinQueryBindings, 
context.getClassificationType(), context.getSearchParameters().getTagFilters());
+           // constructGremlinFilterQuery(gremlinQuery, gremlinQueryBindings, 
context.getClassificationType(), context.getSearchParameters().getTagFilters());
 
             // After filtering on tags go back to e and output the list of 
entity vertices
             gremlinQuery.append(").toList()");
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 dd4d1b4..b2737af 100644
--- 
a/repository/src/main/java/org/apache/atlas/discovery/EntityDiscoveryService.java
+++ 
b/repository/src/main/java/org/apache/atlas/discovery/EntityDiscoveryService.java
@@ -486,9 +486,11 @@ public class EntityDiscoveryService implements 
AtlasDiscoveryService {
                 resultAttributes.addAll(searchContext.getEntityAttributes());
             }
 
-            AtlasEntityType entityType = searchContext.getEntityType();
-            if (entityType != null) {
-                for (String resultAttribute : resultAttributes) {
+            if (CollectionUtils.isNotEmpty(searchContext.getEntityTypes())) {
+
+                AtlasEntityType entityType = 
searchContext.getEntityTypes().iterator().next();
+
+               for (String resultAttribute : resultAttributes) {
                     AtlasAttribute  attribute  = 
entityType.getAttribute(resultAttribute);
 
                     if (attribute == null) {
diff --git 
a/repository/src/main/java/org/apache/atlas/discovery/EntitySearchProcessor.java
 
b/repository/src/main/java/org/apache/atlas/discovery/EntitySearchProcessor.java
index 56956e6..5dcff3b 100644
--- 
a/repository/src/main/java/org/apache/atlas/discovery/EntitySearchProcessor.java
+++ 
b/repository/src/main/java/org/apache/atlas/discovery/EntitySearchProcessor.java
@@ -31,27 +31,15 @@ import org.apache.atlas.utils.AtlasPerfTracer;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.collections.Predicate;
 import org.apache.commons.collections.PredicateUtils;
-import org.apache.commons.lang.StringUtils;
-import org.apache.tinkerpop.gremlin.process.traversal.Order;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
+import java.util.*;
 import java.util.stream.StreamSupport;
 
 import static org.apache.atlas.SortOrder.ASCENDING;
-import static 
org.apache.atlas.discovery.SearchContext.MATCH_ALL_CLASSIFICATION_TYPES;
-import static org.apache.atlas.discovery.SearchContext.MATCH_ALL_CLASSIFIED;
-import static 
org.apache.atlas.discovery.SearchContext.MATCH_ALL_NOT_CLASSIFIED;
-import static 
org.apache.atlas.discovery.SearchContext.MATCH_ALL_WILDCARD_CLASSIFICATION;
-import static 
org.apache.atlas.repository.Constants.PROPAGATED_TRAIT_NAMES_PROPERTY_KEY;
-import static org.apache.atlas.repository.Constants.TRAIT_NAMES_PROPERTY_KEY;
-import static org.apache.atlas.repository.Constants.TYPE_NAME_PROPERTY_KEY;
+import static org.apache.atlas.discovery.SearchContext.*;
+import static org.apache.atlas.repository.Constants.*;
 import static 
org.apache.atlas.repository.graphdb.AtlasGraphQuery.ComparisionOperator.EQUAL;
 import static 
org.apache.atlas.repository.graphdb.AtlasGraphQuery.ComparisionOperator.NOT_EQUAL;
 import static 
org.apache.atlas.repository.graphdb.AtlasGraphQuery.SortOrder.ASC;
@@ -69,28 +57,28 @@ public class EntitySearchProcessor extends SearchProcessor {
     public EntitySearchProcessor(SearchContext context) {
         super(context);
 
-        final AtlasEntityType entityType      = context.getEntityType();
+        final Set<AtlasEntityType> entityTypes      = context.getEntityTypes();
         final FilterCriteria  filterCriteria  = 
context.getSearchParameters().getEntityFilters();
         final Set<String>     indexAttributes = new HashSet<>();
         final Set<String>     graphAttributes = new HashSet<>();
         final Set<String>     allAttributes   = new HashSet<>();
-        final Set<String>     typeAndSubTypes       = context.getEntityTypes();
+        final Set<String>     typeAndSubTypes       = 
context.getEntityTypeNames();
         final String          typeAndSubTypesQryStr = 
context.getEntityTypesQryStr();
         final String          sortBy                = 
context.getSearchParameters().getSortBy();
         final SortOrder       sortOrder             = 
context.getSearchParameters().getSortOrder();
 
-        final AtlasClassificationType classificationType            = 
context.getClassificationType();
-        final Set<String>             classificationTypeAndSubTypes = 
context.getClassificationTypes();
-        final boolean                 filterClassification;
+        final Set<AtlasClassificationType> classificationTypes           = 
context.getClassificationTypes();
+        final Set<String>                  classificationTypeAndSubTypes = 
context.getClassificationTypeNames();
+        final boolean                      filterClassification;
 
-        if (classificationType != null) {
+        if (CollectionUtils.isNotEmpty(classificationTypes)) {
             filterClassification = !context.needClassificationProcessor();
         } else {
             filterClassification = false;
         }
 
         final Predicate typeNamePredicate;
-        final Predicate traitPredicate    = 
buildTraitPredict(classificationType);
+        final Predicate traitPredicate    = 
buildTraitPredict(classificationTypes);
         final Predicate activePredicate   = 
SearchPredicateUtil.getEQPredicateGenerator()
                                                                
.generatePredicate(Constants.STATE_PROPERTY_KEY, "ACTIVE", String.class);
 
@@ -101,10 +89,10 @@ public class EntitySearchProcessor extends SearchProcessor 
{
             typeNamePredicate = 
SearchPredicateUtil.generateIsEntityVertexPredicate(context.getTypeRegistry());
         }
 
-        processSearchAttributes(entityType, filterCriteria, indexAttributes, 
graphAttributes, allAttributes);
+        processSearchAttributes(entityTypes, filterCriteria, indexAttributes, 
graphAttributes, allAttributes);
 
         final boolean typeSearchByIndex = !filterClassification && 
typeAndSubTypesQryStr.length() <= MAX_QUERY_STR_LENGTH_TYPES;
-        final boolean attrSearchByIndex = !filterClassification && 
CollectionUtils.isNotEmpty(indexAttributes) && canApplyIndexFilter(entityType, 
filterCriteria, false);
+        final boolean attrSearchByIndex = !filterClassification && 
CollectionUtils.isNotEmpty(indexAttributes) && canApplyIndexFilter(entityTypes, 
filterCriteria, false);
 
         StringBuilder indexQuery = new StringBuilder();
 
@@ -116,9 +104,9 @@ public class EntitySearchProcessor extends SearchProcessor {
         }
 
         if (attrSearchByIndex) {
-            constructFilterQuery(indexQuery, entityType, filterCriteria, 
indexAttributes);
+            constructFilterQuery(indexQuery, entityTypes, filterCriteria, 
indexAttributes);
 
-            Predicate attributePredicate = 
constructInMemoryPredicate(entityType, filterCriteria, indexAttributes);
+            Predicate attributePredicate = 
constructInMemoryPredicate(entityTypes, filterCriteria, indexAttributes);
             if (attributePredicate != null) {
                 inMemoryPredicate = 
PredicateUtils.andPredicate(inMemoryPredicate, attributePredicate);
             }
@@ -149,6 +137,7 @@ public class EntitySearchProcessor extends SearchProcessor {
 
             // If we need to filter on the trait names then we need to build 
the query and equivalent in-memory predicate
             if (filterClassification) {
+                AtlasClassificationType classificationType = 
classificationTypes.iterator().next();
                 List<AtlasGraphQuery> orConditions = new LinkedList<>();
 
                 if (classificationType == MATCH_ALL_WILDCARD_CLASSIFICATION || 
classificationType == MATCH_ALL_CLASSIFIED || classificationType == 
MATCH_ALL_CLASSIFICATION_TYPES) {
@@ -176,10 +165,10 @@ public class EntitySearchProcessor extends 
SearchProcessor {
                 }
             }
 
-            graphQuery = toGraphFilterQuery(entityType, filterCriteria, 
graphAttributes, query);
+            graphQuery = toGraphFilterQuery(entityTypes, filterCriteria, 
graphAttributes, query);
 
             // Prepare in-memory predicate for attribute filtering
-            Predicate attributePredicate = 
constructInMemoryPredicate(entityType, filterCriteria, graphAttributes);
+            Predicate attributePredicate = 
constructInMemoryPredicate(entityTypes, filterCriteria, graphAttributes);
 
             if (attributePredicate != null) {
                 if (graphQueryPredicate != null) {
@@ -199,7 +188,8 @@ public class EntitySearchProcessor extends SearchProcessor {
                 }
             }
             if (sortBy != null && !sortBy.isEmpty()) {
-                AtlasAttribute sortByAttribute = 
context.getEntityType().getAttribute(sortBy);
+                final AtlasEntityType entityType = 
context.getEntityTypes().iterator().next();
+                AtlasAttribute sortByAttribute = 
entityType.getAttribute(sortBy);
 
                 if (sortByAttribute != null) {
                     AtlasGraphQuery.SortOrder qrySortOrder = sortOrder == 
SortOrder.ASCENDING ? ASC : DESC;
@@ -215,8 +205,7 @@ public class EntitySearchProcessor extends SearchProcessor {
         // Prepare the graph query and in-memory filter for the filtering phase
         filterGraphQueryPredicate = typeNamePredicate;
 
-
-        Predicate attributesPredicate = constructInMemoryPredicate(entityType, 
filterCriteria, allAttributes);
+        Predicate attributesPredicate = 
constructInMemoryPredicate(entityTypes, filterCriteria, allAttributes);
 
         if (attributesPredicate != null) {
             filterGraphQueryPredicate = filterGraphQueryPredicate == null ? 
attributesPredicate :
@@ -265,7 +254,7 @@ public class EntitySearchProcessor extends SearchProcessor {
             SortOrder sortOrder = context.getSearchParameters().getSortOrder();
             String sortBy = context.getSearchParameters().getSortBy();
 
-            final AtlasEntityType entityType = context.getEntityType();
+            final AtlasEntityType entityType = 
context.getEntityTypes().iterator().next();
             AtlasAttribute sortByAttribute = entityType.getAttribute(sortBy);
             if (sortByAttribute == null) {
                 sortBy = null;
diff --git 
a/repository/src/main/java/org/apache/atlas/discovery/FreeTextSearchProcessor.java
 
b/repository/src/main/java/org/apache/atlas/discovery/FreeTextSearchProcessor.java
index 6e3a760..d9981e6 100644
--- 
a/repository/src/main/java/org/apache/atlas/discovery/FreeTextSearchProcessor.java
+++ 
b/repository/src/main/java/org/apache/atlas/discovery/FreeTextSearchProcessor.java
@@ -18,7 +18,6 @@
 package org.apache.atlas.discovery;
 
 import org.apache.atlas.model.discovery.SearchParameters;
-import org.apache.atlas.model.instance.AtlasEntity;
 import org.apache.atlas.repository.Constants;
 import org.apache.atlas.repository.graph.GraphHelper;
 import org.apache.atlas.repository.graphdb.*;
@@ -53,13 +52,13 @@ public class FreeTextSearchProcessor extends 
SearchProcessor {
 
         queryString.append(searchParameters.getQuery());
 
-        if (CollectionUtils.isNotEmpty(context.getEntityTypes()) && 
context.getEntityTypesQryStr().length() <= MAX_QUERY_STR_LENGTH_TYPES) {
+        if (CollectionUtils.isNotEmpty(context.getEntityTypeNames()) && 
context.getEntityTypesQryStr().length() <= MAX_QUERY_STR_LENGTH_TYPES) {
             queryString.append(AND_STR).append(context.getEntityTypesQryStr());
         }
 
         graphIndexQueryBuilder.addActiveStateQueryFilter(queryString);
 
-        if (CollectionUtils.isNotEmpty(context.getClassificationTypes()) && 
context.getClassificationTypesQryStr().length() <= MAX_QUERY_STR_LENGTH_TYPES) {
+        if (CollectionUtils.isNotEmpty(context.getClassificationTypeNames()) 
&& context.getClassificationTypesQryStr().length() <= 
MAX_QUERY_STR_LENGTH_TYPES) {
             
queryString.append(AND_STR).append(context.getClassificationTypesQryStr());
         }
 
@@ -138,7 +137,7 @@ public class FreeTextSearchProcessor extends 
SearchProcessor {
                             continue;
                         }
 
-                        if (context.getClassificationType() != null) {
+                        if 
(CollectionUtils.isNotEmpty(context.getClassificationTypes())) {
                             List<String> entityClassifications = 
GraphHelper.getAllTraitNames(vertex);
 
                             if 
(!context.includeClassificationTypes(entityClassifications)) {
diff --git 
a/repository/src/main/java/org/apache/atlas/discovery/FullTextSearchProcessor.java
 
b/repository/src/main/java/org/apache/atlas/discovery/FullTextSearchProcessor.java
index 99cb1d0..b37d93a 100644
--- 
a/repository/src/main/java/org/apache/atlas/discovery/FullTextSearchProcessor.java
+++ 
b/repository/src/main/java/org/apache/atlas/discovery/FullTextSearchProcessor.java
@@ -24,6 +24,7 @@ import org.apache.atlas.repository.graphdb.AtlasIndexQuery;
 import org.apache.atlas.repository.graphdb.AtlasVertex;
 import org.apache.atlas.repository.store.graph.v2.AtlasGraphUtilsV2;
 import org.apache.atlas.utils.AtlasPerfTracer;
+import org.apache.commons.collections.CollectionUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -31,10 +32,7 @@ import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 
-import static org.apache.atlas.discovery.SearchContext.MATCH_ALL_CLASSIFIED;
-import static org.apache.atlas.discovery.SearchContext.MATCH_ALL_ENTITY_TYPES;
 import static 
org.apache.atlas.discovery.SearchContext.MATCH_ALL_NOT_CLASSIFIED;
-import static 
org.apache.atlas.discovery.SearchContext.MATCH_ALL_WILDCARD_CLASSIFICATION;
 
 
 public class FullTextSearchProcessor extends SearchProcessor {
@@ -53,29 +51,28 @@ public class FullTextSearchProcessor extends 
SearchProcessor {
 
         // if search includes entity-type criteria, adding a filter here can 
help avoid unnecessary
         // processing (and rejection) by subsequent EntitySearchProcessor
-        if (context.getEntityType() != null && context.getEntityType() != 
MATCH_ALL_ENTITY_TYPES) {
-            String typeAndSubTypeNamesQryStr = 
context.getEntityType().getTypeAndAllSubTypesQryStr();
+        if (CollectionUtils.isNotEmpty(context.getEntityTypes())) {
+            String typeAndSubTypeNamesQryStr = context.getEntityTypesQryStr();
 
             if (typeAndSubTypeNamesQryStr.length() <= 
MAX_QUERY_STR_LENGTH_TYPES) {
                 queryString.append(AND_STR).append(typeAndSubTypeNamesQryStr);
             } else {
                 LOG.warn("'{}' has too many subtypes (query-string-length={}) 
to include in index-query; might cause poor performance",
-                         context.getEntityType().getTypeName(), 
typeAndSubTypeNamesQryStr.length());
+                         searchParameters.getTypeName(), 
typeAndSubTypeNamesQryStr.length());
             }
         }
 
         // if search includes classification criteria, adding a filter here 
can help avoid unnecessary
         // processing (and rejection) by subsequent 
ClassificationSearchProcessor or EntitySearchProcessor
-        if (context.getClassificationType() != null && 
context.getClassificationType() != MATCH_ALL_WILDCARD_CLASSIFICATION &&
-                                                       
context.getClassificationType() != MATCH_ALL_CLASSIFIED &&
-                                                       
context.getClassificationType() != MATCH_ALL_NOT_CLASSIFIED) {
-            String typeAndSubTypeNamesStr = 
context.getClassificationType().getTypeAndAllSubTypesQryStr();
+        if (CollectionUtils.isNotEmpty(context.getClassificationTypes()) &&
+                                                       
context.getClassificationTypes().iterator().next() != MATCH_ALL_NOT_CLASSIFIED) 
{
+            String typeAndSubTypeNamesStr = 
context.getClassificationTypesQryStr();
 
             if (typeAndSubTypeNamesStr.length() <= MAX_QUERY_STR_LENGTH_TAGS) {
                 queryString.append(AND_STR).append(typeAndSubTypeNamesStr);
             } else {
                 LOG.warn("'{}' has too many subtypes (query-string-length={}) 
to include in index-query; might cause poor performance",
-                        context.getClassificationType().getTypeName(), 
typeAndSubTypeNamesStr.length());
+                        searchParameters.getClassification(), 
typeAndSubTypeNamesStr.length());
             }
         }
 
diff --git 
a/repository/src/main/java/org/apache/atlas/discovery/GraphIndexQueryBuilder.java
 
b/repository/src/main/java/org/apache/atlas/discovery/GraphIndexQueryBuilder.java
index 28d2086..35d64b7 100644
--- 
a/repository/src/main/java/org/apache/atlas/discovery/GraphIndexQueryBuilder.java
+++ 
b/repository/src/main/java/org/apache/atlas/discovery/GraphIndexQueryBuilder.java
@@ -26,6 +26,8 @@ import static 
org.apache.atlas.repository.Constants.PROPAGATED_CLASSIFICATION_NA
 import static org.apache.atlas.repository.Constants.STATE_PROPERTY_KEY;
 
 import org.apache.atlas.repository.Constants;
+import org.apache.atlas.type.AtlasStructType;
+import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
 
 public class GraphIndexQueryBuilder {
@@ -36,20 +38,20 @@ public class GraphIndexQueryBuilder {
     }
 
     void addClassificationTypeFilter(StringBuilder indexQuery) {
-        if (indexQuery != null && 
StringUtils.isNotEmpty(context.getSearchParameters().getClassification())) {
-            String classificationName = 
context.getSearchParameters().getClassification();
+        if (indexQuery != null && 
CollectionUtils.isNotEmpty(context.getClassificationNames())) {
+            String classificationNames = 
AtlasStructType.AtlasAttribute.escapeIndexQueryValue(context.getClassificationNames());
             if (indexQuery.length() != 0) {
                 indexQuery.append(" AND ");
             }
 
-            
indexQuery.append("(").append(INDEX_SEARCH_PREFIX).append('\"').append(CLASSIFICATION_NAMES_KEY).append('\"').append(':').append(classificationName)
+            
indexQuery.append("(").append(INDEX_SEARCH_PREFIX).append('\"').append(CLASSIFICATION_NAMES_KEY).append('\"').append(':').append(classificationNames)
                 .append(" OR 
").append(INDEX_SEARCH_PREFIX).append('\"').append(PROPAGATED_CLASSIFICATION_NAMES_KEY)
-                
.append('\"').append(':').append(classificationName).append(")");
+                
.append('\"').append(':').append(classificationNames).append(")");
         }
     }
 
     void addClassificationAndSubTypesQueryFilter(StringBuilder indexQuery) {
-        if (indexQuery != null && 
StringUtils.isNotEmpty(context.getSearchParameters().getClassification())) {
+        if (indexQuery != null && 
CollectionUtils.isNotEmpty(context.getClassificationTypes())) {
             String classificationTypesQryStr = 
context.getClassificationTypesQryStr();
 
             if (indexQuery.length() != 0) {
@@ -63,17 +65,8 @@ public class GraphIndexQueryBuilder {
     }
 
     void addClassificationFilterForBuiltInTypes(StringBuilder indexQuery) {
-        if (indexQuery != null && context.getClassificationType() != null) {
-            if (context.getClassificationType() == 
MATCH_ALL_WILDCARD_CLASSIFICATION || context.getClassificationType() == 
MATCH_ALL_CLASSIFIED) {
-                if (indexQuery.length() != 0) {
-                    indexQuery.append(" AND ");
-                }
-                indexQuery.append("(").append(INDEX_SEARCH_PREFIX).append("\"")
-                    .append(CLASSIFICATION_NAMES_KEY).append("\"").append(":" 
+ "[* TO *]")
-                    .append(" OR ").append(INDEX_SEARCH_PREFIX).append("\"")
-                    
.append(PROPAGATED_CLASSIFICATION_NAMES_KEY).append("\"").append(":" + "[* TO 
*]").append(")");
-
-            } else if (context.getClassificationType() == 
MATCH_ALL_NOT_CLASSIFIED) {
+        if (indexQuery != null && 
CollectionUtils.isNotEmpty(context.getClassificationTypes())) {
+            if (context.getClassificationTypes().iterator().next() == 
MATCH_ALL_NOT_CLASSIFIED) {
                 if (indexQuery.length() != 0) {
                     indexQuery.append(" AND ");
                 }
diff --git 
a/repository/src/main/java/org/apache/atlas/discovery/SearchAggregatorImpl.java 
b/repository/src/main/java/org/apache/atlas/discovery/SearchAggregatorImpl.java
index e8f7dbc..2d095be 100644
--- 
a/repository/src/main/java/org/apache/atlas/discovery/SearchAggregatorImpl.java
+++ 
b/repository/src/main/java/org/apache/atlas/discovery/SearchAggregatorImpl.java
@@ -56,12 +56,7 @@ public class SearchAggregatorImpl implements 
SearchAggregator {
 
         try {
             AtlasGraphIndexClient graphIndexClient    = 
graph.getGraphIndexClient();
-            String                searchedOnTypeName  = 
searchParameters.getTypeName();
-            AtlasEntityType       searchForEntityType = null;
-
-            if (searchedOnTypeName != null) {
-                searchForEntityType = 
typeRegistry.getEntityTypeByName(searchedOnTypeName);
-            }
+            Set<AtlasEntityType>  searchForEntityType = 
searchContext.getEntityTypes();
 
             Map<String, String> indexFieldNameCache = new HashMap<>();
 
diff --git 
a/repository/src/main/java/org/apache/atlas/discovery/SearchContext.java 
b/repository/src/main/java/org/apache/atlas/discovery/SearchContext.java
index 2c2888e..04e8218 100644
--- a/repository/src/main/java/org/apache/atlas/discovery/SearchContext.java
+++ b/repository/src/main/java/org/apache/atlas/discovery/SearchContext.java
@@ -21,7 +21,7 @@ package org.apache.atlas.discovery;
 import org.apache.atlas.AtlasErrorCode;
 import org.apache.atlas.exception.AtlasBaseException;
 import org.apache.atlas.model.discovery.SearchParameters;
-import org.apache.atlas.model.discovery.SearchParameters.FilterCriteria;
+import org.apache.atlas.model.discovery.SearchParameters.*;
 import org.apache.atlas.model.instance.AtlasEntity;
 import org.apache.atlas.model.typedef.AtlasClassificationDef;
 import org.apache.atlas.repository.Constants;
@@ -44,13 +44,10 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.util.*;
+import java.util.stream.Collectors;
 
 import static org.apache.atlas.discovery.SearchProcessor.ALL_TYPE_QUERY;
-import static 
org.apache.atlas.model.discovery.SearchParameters.ALL_CLASSIFICATIONS;
-import static 
org.apache.atlas.model.discovery.SearchParameters.ALL_CLASSIFICATION_TYPES;
-import static 
org.apache.atlas.model.discovery.SearchParameters.ALL_ENTITY_TYPES;
-import static 
org.apache.atlas.model.discovery.SearchParameters.NO_CLASSIFICATIONS;
-import static 
org.apache.atlas.model.discovery.SearchParameters.WILDCARD_CLASSIFICATIONS;
+import static org.apache.atlas.model.discovery.SearchParameters.*;
 
 /*
  * Search context captures elements required for performing a basic search
@@ -62,12 +59,12 @@ public class SearchContext {
 
     private final AtlasTypeRegistry       typeRegistry;
     private final AtlasGraph              graph;
-    private final AtlasEntityType         entityType;
+    private final Set<AtlasEntityType>    entityTypes;
     private final Set<String>             indexedKeys;
     private final Set<String>             entityAttributes;
     private final SearchParameters        searchParameters;
-    private final AtlasClassificationType classificationType;
-    private final String                  classificationName;
+    private final Set<AtlasClassificationType> classificationTypes;
+    private final Set<String>                  classificationNames;
     private final Set<String>             typeAndSubTypes;
     private final Set<String>             classificationTypeAndSubTypes;
     private final String                  typeAndSubTypesQryStr;
@@ -80,27 +77,18 @@ public class SearchContext {
     public final static AtlasClassificationType MATCH_ALL_NOT_CLASSIFIED       
   = new AtlasClassificationType(new 
AtlasClassificationDef(NO_CLASSIFICATIONS));
     public final static AtlasClassificationType MATCH_ALL_CLASSIFICATION_TYPES 
   = AtlasClassificationType.getClassificationRoot();
     public final static AtlasEntityType         MATCH_ALL_ENTITY_TYPES         
   = AtlasEntityType.getEntityRoot();
+    public final static String                  TYPENAME_DELIMITER             
   = ",";
 
 
     public SearchContext(SearchParameters searchParameters, AtlasTypeRegistry 
typeRegistry, AtlasGraph graph, Set<String> indexedKeys) throws 
AtlasBaseException {
-        this.classificationName = searchParameters.getClassification();
         this.searchParameters   = searchParameters;
         this.typeRegistry       = typeRegistry;
         this.graph              = graph;
         this.indexedKeys        = indexedKeys;
         this.entityAttributes   = new HashSet<>();
-        this.entityType         = 
getEntityType(searchParameters.getTypeName());
-        this.classificationType = getClassificationType(classificationName);
-
-        // Validate if the type name exists
-        if (StringUtils.isNotEmpty(searchParameters.getTypeName()) && 
entityType == null) {
-            throw new AtlasBaseException(AtlasErrorCode.UNKNOWN_TYPENAME, 
searchParameters.getTypeName());
-        }
-
-        // Validate if the classification exists
-        if ((StringUtils.isNotEmpty(classificationName) && classificationType 
== null && !classificationName.contains(WILDCARD_CLASSIFICATIONS))) {
-            throw new 
AtlasBaseException(AtlasErrorCode.UNKNOWN_CLASSIFICATION, classificationName);
-        }
+        this.entityTypes        = 
getEntityTypes(searchParameters.getTypeName());
+        this.classificationNames = 
getClassificationNames(searchParameters.getClassification());
+        this.classificationTypes = 
getClassificationTypes(this.classificationNames);
 
         AtlasVertex glossaryTermVertex = 
getGlossaryTermVertex(searchParameters.getTermName());
 
@@ -109,40 +97,77 @@ public class SearchContext {
             throw new AtlasBaseException(AtlasErrorCode.UNKNOWN_GLOSSARY_TERM, 
searchParameters.getTermName());
         }
 
-        // Invalid attributes will raise an exception with 400 error code
-        validateAttributes(entityType, searchParameters.getEntityFilters());
+        // Invalid attributes or unsupported attribute in a type, will raise 
an exception with 400 error code
+        if (CollectionUtils.isNotEmpty(entityTypes)) {
+            for (AtlasEntityType entityType : entityTypes) {
+                validateAttributes(entityType, 
searchParameters.getEntityFilters());
 
-        // Invalid attribute will raise an exception with 400 error code
-        validateAttributes(entityType, searchParameters.getSortBy());
+                validateAttributes(entityType, searchParameters.getSortBy());
+            }
+        }
 
         // Invalid attributes will raise an exception with 400 error code
-        validateAttributes(classificationType, 
searchParameters.getTagFilters());
+        if (CollectionUtils.isNotEmpty(classificationTypes)) {
+            for (AtlasClassificationType classificationType : 
classificationTypes) {
+                validateAttributes(classificationType, 
searchParameters.getTagFilters());
+            }
+        }
 
-        if (classificationType != null && !isBuiltInClassificationType()) {
-            if (classificationType == MATCH_ALL_CLASSIFICATION_TYPES) {
-                classificationTypeAndSubTypes       = Collections.emptySet();
-                classificationTypeAndSubTypesQryStr = ALL_TYPE_QUERY;
-            } else {
-                classificationTypeAndSubTypes       = 
searchParameters.getIncludeSubClassifications() ? 
classificationType.getTypeAndAllSubTypes() : 
Collections.singleton(classificationType.getTypeName());
-                classificationTypeAndSubTypesQryStr = 
searchParameters.getIncludeSubClassifications() ? 
classificationType.getTypeAndAllSubTypesQryStr() : 
classificationType.getTypeQryStr();
+        //remove other types if builtin type is present
+        filterStructTypes();
+
+        //gather all classifications and its corresponding subtypes
+        Set<String> classificationTypeAndSubTypes  = new HashSet<>();
+        String classificationTypeAndSubTypesQryStr = null;
+
+        if (CollectionUtils.isNotEmpty(classificationTypes) && 
classificationTypes.iterator().next() != MATCH_ALL_NOT_CLASSIFIED ) {
+            for (AtlasClassificationType classificationType : 
classificationTypes) {
+
+                if (classificationType == MATCH_ALL_CLASSIFICATION_TYPES) {
+                    classificationTypeAndSubTypes       = 
Collections.emptySet();
+                    classificationTypeAndSubTypesQryStr = ALL_TYPE_QUERY;
+                    break;
+                } else {
+                    Set<String> allTypes = 
searchParameters.getIncludeSubClassifications() ? 
classificationType.getTypeAndAllSubTypes() : 
Collections.singleton(classificationType.getTypeName());
+                    classificationTypeAndSubTypes.addAll(allTypes);            
    }
+            }
+
+            if (CollectionUtils.isNotEmpty(classificationTypeAndSubTypes)) {
+                classificationTypeAndSubTypesQryStr = 
AtlasAttribute.escapeIndexQueryValue(classificationTypeAndSubTypes);
             }
         } else {
             classificationTypeAndSubTypes       = Collections.emptySet();
             classificationTypeAndSubTypesQryStr = "";
         }
+        this.classificationTypeAndSubTypes       = 
classificationTypeAndSubTypes;
+        this.classificationTypeAndSubTypesQryStr = 
classificationTypeAndSubTypesQryStr;
+
+        //gather all types and its corresponding subtypes
+        Set<String> typeAndSubTypes  = new HashSet<>();
+        String typeAndSubTypesQryStr = null;
+
+        if (CollectionUtils.isNotEmpty(entityTypes)) {
+            for (AtlasEntityType entityType : entityTypes) {
+
+                if (entityType.equals(MATCH_ALL_ENTITY_TYPES)) {
+                    typeAndSubTypes       = Collections.emptySet();
+                    typeAndSubTypesQryStr = ALL_TYPE_QUERY;
+                    break;
+                } else {
+                    Set<String> allTypes  = 
searchParameters.getIncludeSubTypes() ? entityType.getTypeAndAllSubTypes() : 
Collections.singleton(entityType.getTypeName());
+                    typeAndSubTypes.addAll(allTypes);
+                }
+            }
 
-        if (entityType != null) {
-            if (entityType.equals(MATCH_ALL_ENTITY_TYPES)) {
-                typeAndSubTypes       = Collections.emptySet();
-                typeAndSubTypesQryStr = ALL_TYPE_QUERY;
-            } else {
-                typeAndSubTypes       = searchParameters.getIncludeSubTypes() 
? entityType.getTypeAndAllSubTypes() : 
Collections.singleton(entityType.getTypeName());
-                typeAndSubTypesQryStr = searchParameters.getIncludeSubTypes() 
? entityType.getTypeAndAllSubTypesQryStr() : entityType.getTypeQryStr();
+            if (CollectionUtils.isNotEmpty(typeAndSubTypes)) {
+                typeAndSubTypesQryStr = 
AtlasAttribute.escapeIndexQueryValue(typeAndSubTypes);
             }
         } else {
             typeAndSubTypes       = Collections.emptySet();
             typeAndSubTypesQryStr = "";
         }
+        this.typeAndSubTypes       = typeAndSubTypes;
+        this.typeAndSubTypesQryStr = typeAndSubTypesQryStr;
 
         if (glossaryTermVertex != null) {
             addProcessor(new TermSearchProcessor(this, 
getAssignedEntities(glossaryTermVertex)));
@@ -179,37 +204,37 @@ public class SearchContext {
 
     public Set<String> getEntityAttributes() { return entityAttributes; }
 
-    public AtlasEntityType getEntityType() { return entityType; }
+    public Set<AtlasClassificationType> getClassificationTypes() { return 
classificationTypes; }
 
-    public AtlasClassificationType getClassificationType() { return 
classificationType; }
+    public Set<String> getEntityTypeNames() { return typeAndSubTypes; }
 
-    public Set<String> getEntityTypes() { return typeAndSubTypes; }
-
-    public Set<String> getClassificationTypes() { return 
classificationTypeAndSubTypes; }
+    public Set<String> getClassificationTypeNames() { return 
classificationTypeAndSubTypes; }
 
     public String getEntityTypesQryStr() { return typeAndSubTypesQryStr; }
 
     public String getClassificationTypesQryStr() { return 
classificationTypeAndSubTypesQryStr; }
 
+    public Set<AtlasEntityType> getEntityTypes() { return entityTypes; }
+
     public SearchProcessor getSearchProcessor() { return searchProcessor; }
 
-    public String getClassificationName() {return classificationName;}
+    public Set<String> getClassificationNames() {return classificationNames;}
 
     public boolean includeEntityType(String entityType) {
         return typeAndSubTypes.isEmpty() || 
typeAndSubTypes.contains(entityType);
     }
 
-    public boolean includeClassificationTypes(Collection<String> 
classificationTypes) {
+    public boolean includeClassificationTypes(Collection<String> traitNames) {
         final boolean ret;
 
-        if (classificationType == null || 
classificationTypeAndSubTypes.isEmpty()) {
+        if (CollectionUtils.isEmpty(classificationTypes) || 
classificationTypeAndSubTypes.isEmpty()) {
             ret = true;
-        } else if (classificationType == MATCH_ALL_NOT_CLASSIFIED) {
-            ret = CollectionUtils.isEmpty(classificationTypes);
-        } else if (classificationType == MATCH_ALL_CLASSIFIED || 
classificationType == MATCH_ALL_WILDCARD_CLASSIFICATION) {
-            ret = CollectionUtils.isNotEmpty(classificationTypes);
+        } else if (classificationTypes.iterator().next() == 
MATCH_ALL_NOT_CLASSIFIED) {
+            ret = CollectionUtils.isEmpty(traitNames);
+        } else if (classificationTypes.iterator().next() == 
MATCH_ALL_CLASSIFICATION_TYPES) {
+            ret = CollectionUtils.isNotEmpty(traitNames);
         } else {
-            ret = CollectionUtils.containsAny(classificationTypeAndSubTypes, 
classificationTypes);
+            ret = CollectionUtils.containsAny(classificationTypeAndSubTypes, 
traitNames);
         }
 
         return ret;
@@ -243,25 +268,18 @@ public class SearchContext {
     }
 
     boolean needClassificationProcessor() {
-        return (classificationType != null && (entityType == null || 
hasAttributeFilter(searchParameters.getTagFilters()))) || isWildCardSearch() ;
-    }
-
-    boolean isBuiltInClassificationType() {
-        return getClassificationType() == MATCH_ALL_WILDCARD_CLASSIFICATION
-            || getClassificationType() == MATCH_ALL_CLASSIFIED
-            || getClassificationType() == MATCH_ALL_NOT_CLASSIFIED;
+        return (CollectionUtils.isNotEmpty(classificationTypes) && 
(CollectionUtils.isEmpty(entityTypes) || 
hasAttributeFilter(searchParameters.getTagFilters()))) || isWildCardSearch() ;
     }
 
     boolean isWildCardSearch () {
-        String classification = getSearchParameters().getClassification();
-        if (StringUtils.isNotEmpty(classification) && getClassificationType() 
== null) {
-            return classification.contains("*");
+        if (CollectionUtils.isNotEmpty(classificationNames)) {
+            return classificationNames.stream().anyMatch(classification -> 
classification.contains(WILDCARD_CLASSIFICATIONS));
         }
         return false;
     }
 
     boolean needEntityProcessor() {
-        return entityType != null;
+        return CollectionUtils.isNotEmpty(entityTypes);
     }
 
     private void validateAttributes(final AtlasStructType structType, final 
FilterCriteria filterCriteria) throws AtlasBaseException {
@@ -285,7 +303,14 @@ public class SearchContext {
                 if (structType == null) {
                     throw new 
AtlasBaseException(AtlasErrorCode.UNKNOWN_TYPENAME, "NULL");
                 }
-                throw new AtlasBaseException(AtlasErrorCode.UNKNOWN_ATTRIBUTE, 
attributeName, structType.getTypeName());
+
+                String name = structType.getTypeName();
+                if (name.equals(MATCH_ALL_ENTITY_TYPES.getTypeName())) {
+                    name = ALL_ENTITY_TYPES;
+                } else if 
(name.equals(MATCH_ALL_CLASSIFICATION_TYPES.getTypeName())) {
+                    name = ALL_CLASSIFICATION_TYPES;
+                }
+                throw new AtlasBaseException(AtlasErrorCode.UNKNOWN_ATTRIBUTE, 
attributeName, name);
             }
         }
     }
@@ -321,11 +346,107 @@ public class SearchContext {
         return ret;
     }
 
+    private Set<AtlasClassificationType> getClassificationTypes(Set<String> 
classificationNames) {
+        if (CollectionUtils.isNotEmpty(classificationNames)) {
+            return classificationNames.stream().map(n ->
+                    
getClassificationType(n)).filter(Objects::nonNull).collect(Collectors.toSet());
+        }
+
+        return null;
+    }
+
+    private Set<String> getClassificationNames(String classification) throws 
AtlasBaseException {
+        Set<String> classificationNames = new HashSet<>();
+
+        if (StringUtils.isNotEmpty(classification)) {
+            String[] types                  = 
classification.split(TYPENAME_DELIMITER);
+            Set<String> names = new HashSet<>(Arrays.asList(types));
+
+            names.forEach(name -> {
+                AtlasClassificationType type = getClassificationType(name);
+                if (type != null || name.contains(WILDCARD_CLASSIFICATIONS)) {
+                    classificationNames.add(name);
+                }
+            });
+
+            // Validate if the classification exists
+            if (CollectionUtils.isEmpty(classificationNames) || 
classificationNames.size() != names.size()) {
+                if (CollectionUtils.isNotEmpty(classificationNames)) {
+                    names.removeAll(classificationNames);
+                }
+                throw new 
AtlasBaseException(AtlasErrorCode.UNKNOWN_CLASSIFICATION, 
String.join(TYPENAME_DELIMITER, names));
+            }
+        }
+
+        return classificationNames;
+    }
+
     private AtlasEntityType getEntityType(String entityName) {
         return StringUtils.equals(entityName, ALL_ENTITY_TYPES) ? 
MATCH_ALL_ENTITY_TYPES :
                                                                   
typeRegistry.getEntityTypeByName(entityName);
     }
 
+    private Set<AtlasEntityType> getEntityTypes(String typeName) throws 
AtlasBaseException {
+
+        Set<AtlasEntityType> entityTypes = null;
+        //split multiple typeNames by comma
+        if (StringUtils.isNotEmpty(typeName)) {
+
+            String[] types        = typeName.split(TYPENAME_DELIMITER);
+            Set<String> typeNames = new HashSet<>(Arrays.asList(types));
+            entityTypes           = typeNames.stream().map(n ->
+                                    
getEntityType(n)).filter(Objects::nonNull).collect(Collectors.toSet());
+
+            // Validate if the type name is incorrect
+            if (CollectionUtils.isEmpty(entityTypes) || entityTypes.size() != 
typeNames.size()) {
+                if (CollectionUtils.isNotEmpty(entityTypes)) {
+                    Set<String> validEntityTypes = new HashSet<>();
+                    for (AtlasEntityType entityType : entityTypes) {
+                        String name = entityType.getTypeName();
+                        if (name.equals(MATCH_ALL_ENTITY_TYPES.getTypeName())) 
{
+                            validEntityTypes.add(ALL_ENTITY_TYPES);
+                            continue;
+                        }
+                        validEntityTypes.add(entityType.getTypeName());
+                    }
+
+                    typeNames.removeAll(validEntityTypes);
+                }
+
+                throw new AtlasBaseException(AtlasErrorCode.UNKNOWN_TYPENAME, 
String.join(TYPENAME_DELIMITER, typeNames));
+            }
+
+        }
+
+        return entityTypes;
+    }
+
+    private void filterStructTypes(){
+        //if typeName contains ALL_ENTITY_TYPES, remove others as OR condition 
will not effect any other
+        if (CollectionUtils.isNotEmpty(entityTypes) && 
entityTypes.contains(MATCH_ALL_ENTITY_TYPES)) {
+            entityTypes.clear();
+            entityTypes.add(MATCH_ALL_ENTITY_TYPES);
+        }
+
+        //No Builtin Classification can be together
+        if (CollectionUtils.isNotEmpty(classificationTypes)) {
+            if (classificationTypes.contains(MATCH_ALL_NOT_CLASSIFIED)) {
+                classificationTypes.clear();
+                classificationTypes.add(MATCH_ALL_NOT_CLASSIFIED);
+
+                classificationNames.clear();
+                
classificationNames.add(MATCH_ALL_NOT_CLASSIFIED.getTypeName());
+            } else if 
(classificationTypes.contains(MATCH_ALL_WILDCARD_CLASSIFICATION) || 
classificationTypes.contains(MATCH_ALL_CLASSIFICATION_TYPES) || 
classificationTypes.contains(MATCH_ALL_CLASSIFIED)) {
+                classificationTypes.clear();
+                classificationTypes.add(MATCH_ALL_CLASSIFICATION_TYPES);
+
+                classificationNames.clear();
+                classificationNames.add(ALL_CLASSIFICATION_TYPES);
+            }
+        }
+    }
+
+
     private AtlasVertex getGlossaryTermVertex(String termName) {
         AtlasVertex ret = null;
 
diff --git 
a/repository/src/main/java/org/apache/atlas/discovery/SearchProcessor.java 
b/repository/src/main/java/org/apache/atlas/discovery/SearchProcessor.java
index ad48be1..c9a6053 100644
--- a/repository/src/main/java/org/apache/atlas/discovery/SearchProcessor.java
+++ b/repository/src/main/java/org/apache/atlas/discovery/SearchProcessor.java
@@ -51,16 +51,8 @@ import java.util.regex.Pattern;
 
 import static org.apache.atlas.SortOrder.ASCENDING;
 import static 
org.apache.atlas.discovery.SearchContext.MATCH_ALL_CLASSIFICATION_TYPES;
-import static org.apache.atlas.discovery.SearchContext.MATCH_ALL_CLASSIFIED;
 import static 
org.apache.atlas.discovery.SearchContext.MATCH_ALL_NOT_CLASSIFIED;
-import static 
org.apache.atlas.discovery.SearchContext.MATCH_ALL_WILDCARD_CLASSIFICATION;
-import static org.apache.atlas.repository.Constants.CLASSIFICATION_NAMES_KEY;
-import static 
org.apache.atlas.repository.Constants.CLASSIFICATION_NAME_DELIMITER;
-import static 
org.apache.atlas.repository.Constants.CUSTOM_ATTRIBUTES_PROPERTY_KEY;
-import static org.apache.atlas.repository.Constants.LABELS_PROPERTY_KEY;
-import static 
org.apache.atlas.repository.Constants.PROPAGATED_CLASSIFICATION_NAMES_KEY;
-import static 
org.apache.atlas.repository.Constants.PROPAGATED_TRAIT_NAMES_PROPERTY_KEY;
-import static org.apache.atlas.repository.Constants.TRAIT_NAMES_PROPERTY_KEY;
+import static org.apache.atlas.repository.Constants.*;
 import static org.apache.atlas.util.SearchPredicateUtil.*;
 
 public abstract class SearchProcessor {
@@ -153,11 +145,19 @@ public abstract class SearchProcessor {
     public abstract long getResultCount();
 
     protected boolean isEntityRootType() {
-        return context.getEntityType() == SearchContext.MATCH_ALL_ENTITY_TYPES;
+        //always size will be one if in case of _ALL_ENTITY_TYPES
+        if (CollectionUtils.isNotEmpty(context.getEntityTypes())) {
+            return context.getEntityTypes().iterator().next() == 
SearchContext.MATCH_ALL_ENTITY_TYPES;
+        }
+        return false;
     }
 
     protected boolean isClassificationRootType() {
-        return context.getClassificationType() == 
SearchContext.MATCH_ALL_CLASSIFICATION_TYPES;
+        //always size will be one if in case of _ALL_CLASSIFICATION_TYPES
+        if (CollectionUtils.isNotEmpty(context.getClassificationTypes())) {
+            return context.getClassificationTypes().iterator().next() == 
SearchContext.MATCH_ALL_CLASSIFICATION_TYPES;
+        }
+        return false;
     }
 
     protected boolean isSystemAttribute(String attrName) {
@@ -195,9 +195,14 @@ public abstract class SearchProcessor {
         }
     }
 
-    protected Predicate buildTraitPredict(AtlasClassificationType 
classificationType) {
+    protected Predicate buildTraitPredict(Set<AtlasClassificationType> 
classificationTypes) {
         Predicate traitPredicate;
-        if (classificationType == MATCH_ALL_WILDCARD_CLASSIFICATION || 
classificationType == MATCH_ALL_CLASSIFIED || classificationType == 
MATCH_ALL_CLASSIFICATION_TYPES) {
+        AtlasClassificationType classificationType = null;
+        if (CollectionUtils.isNotEmpty(classificationTypes)) {
+            classificationType = classificationTypes.iterator().next();
+        }
+
+        if (classificationType == MATCH_ALL_CLASSIFICATION_TYPES) {
             traitPredicate = 
PredicateUtils.orPredicate(SearchPredicateUtil.getNotEmptyPredicateGenerator().generatePredicate(TRAIT_NAMES_PROPERTY_KEY,
 null, List.class),
                 
SearchPredicateUtil.getNotEmptyPredicateGenerator().generatePredicate(PROPAGATED_TRAIT_NAMES_PROPERTY_KEY,
 null, List.class));
         } else if (classificationType == MATCH_ALL_NOT_CLASSIFIED) {
@@ -205,20 +210,27 @@ public abstract class SearchProcessor {
                 
SearchPredicateUtil.getIsNullOrEmptyPredicateGenerator().generatePredicate(PROPAGATED_TRAIT_NAMES_PROPERTY_KEY,
 null, List.class));
         } else if (context.isWildCardSearch()) {
             //For wildcard search __classificationNames which of String type 
is taken instead of _traitNames which is of Array type
-            //No need to escape, as classification Names only support 
letters,numbers,space and underscore
-            String regexString = getRegexString("\\|" + 
context.getClassificationName() + "\\|");
-            traitPredicate = 
PredicateUtils.orPredicate(SearchPredicateUtil.getRegexPredicateGenerator().generatePredicate(CLASSIFICATION_NAMES_KEY,
 regexString, String.class),
-                    
SearchPredicateUtil.getRegexPredicateGenerator().generatePredicate(PROPAGATED_CLASSIFICATION_NAMES_KEY,
 regexString, String.class));
+            Set<String> classificationNames = context.getClassificationNames();
+            List<Predicate> predicates = new ArrayList<>();
+
+            classificationNames.forEach(classificationName -> {
+                //No need to escape, as classification Names only support 
letters,numbers,space and underscore
+                String regexString = getRegexString("\\|" + classificationName 
+ "\\|");
+                
predicates.add(SearchPredicateUtil.getRegexPredicateGenerator().generatePredicate(CLASSIFICATION_NAMES_KEY,
 regexString, String.class));
+                
predicates.add(SearchPredicateUtil.getRegexPredicateGenerator().generatePredicate(PROPAGATED_CLASSIFICATION_NAMES_KEY,
 regexString, String.class));
+            });
+
+            traitPredicate = PredicateUtils.anyPredicate(predicates);
         } else {
-            traitPredicate = 
PredicateUtils.orPredicate(SearchPredicateUtil.getContainsAnyPredicateGenerator().generatePredicate(TRAIT_NAMES_PROPERTY_KEY,
 context.getClassificationTypes(), List.class),
-                
SearchPredicateUtil.getContainsAnyPredicateGenerator().generatePredicate(PROPAGATED_TRAIT_NAMES_PROPERTY_KEY,
 context.getClassificationTypes(), List.class));
+            traitPredicate = 
PredicateUtils.orPredicate(SearchPredicateUtil.getContainsAnyPredicateGenerator().generatePredicate(TRAIT_NAMES_PROPERTY_KEY,
 context.getClassificationTypeNames(), List.class),
+                
SearchPredicateUtil.getContainsAnyPredicateGenerator().generatePredicate(PROPAGATED_TRAIT_NAMES_PROPERTY_KEY,
 context.getClassificationTypeNames(), List.class));
         }
         return traitPredicate;
     }
 
 
-    protected void processSearchAttributes(AtlasStructType structType, 
FilterCriteria filterCriteria, Set<String> indexFiltered, Set<String> 
graphFiltered, Set<String> allAttributes) {
-        if (structType == null || filterCriteria == null) {
+    protected void processSearchAttributes(Set<? extends AtlasStructType> 
structTypes, FilterCriteria filterCriteria, Set<String> indexFiltered, 
Set<String> graphFiltered, Set<String> allAttributes) {
+        if (CollectionUtils.isEmpty(structTypes) || filterCriteria == null) {
             return;
         }
 
@@ -227,7 +239,7 @@ public abstract class SearchProcessor {
 
         if (filterCondition != null && CollectionUtils.isNotEmpty(criterion)) {
             for (SearchParameters.FilterCriteria criteria : criterion) {
-                processSearchAttributes(structType, criteria, indexFiltered, 
graphFiltered, allAttributes);
+                processSearchAttributes(structTypes, criteria, indexFiltered, 
graphFiltered, allAttributes);
             }
         } else if (StringUtils.isNotEmpty(filterCriteria.getAttributeName())) {
             String attributeName = filterCriteria.getAttributeName();
@@ -267,20 +279,23 @@ public abstract class SearchProcessor {
             }
 
             try {
-                if (isIndexSearchable(filterCriteria, structType)) {
-                    indexFiltered.add(attributeName);
-                } else {
-                    LOG.warn("not using index-search for attribute '{}'; might 
cause poor performance", structType.getVertexPropertyName(attributeName));
+                for (AtlasStructType structType : structTypes) {
+                    String qualifiedName = 
structType.getVertexPropertyName(attributeName);
+                    if (isIndexSearchable(filterCriteria, structType)) {
+                        indexFiltered.add(qualifiedName);
+                    } else {
+                        LOG.warn("not using index-search for attribute '{}'; 
might cause poor performance", structType.getVertexPropertyName(attributeName));
 
-                    graphFiltered.add(attributeName);
-                }
+                        graphFiltered.add(qualifiedName);
+                    }
 
-                if (structType instanceof AtlasEntityType && 
!isSystemAttribute(attributeName)) {
-                    // Capture the entity attributes
-                    context.getEntityAttributes().add(attributeName);
-                }
+                    if (structType instanceof AtlasEntityType && 
!isSystemAttribute(attributeName)) {
+                        // Capture the entity attributes
+                        context.getEntityAttributes().add(attributeName);
+                    }
 
-                allAttributes.add(attributeName);
+                    allAttributes.add(qualifiedName);
+                }
             } catch (AtlasBaseException e) {
                 LOG.warn(e.getMessage());
             }
@@ -298,7 +313,7 @@ public abstract class SearchProcessor {
     //      (AND (OR idx-att1=x idx-attr1=y) non-idx-attr=z)
     //      (AND (OR idx-att1=x idx-attr1=y) non-idx-attr=z (AND idx-attr2=xyz 
idx-attr2=abc))
     //
-    protected boolean canApplyIndexFilter(AtlasStructType structType, 
FilterCriteria filterCriteria, boolean insideOrCondition) {
+    protected boolean canApplyIndexFilter(Set<? extends AtlasStructType> 
structTypes, FilterCriteria filterCriteria, boolean insideOrCondition) {
         if (!context.hasAttributeFilter(filterCriteria)) {
             return true;
         }
@@ -314,7 +329,7 @@ public abstract class SearchProcessor {
 
             // If we have nested criterion let's find any nested ORs with 
non-indexed attr
             for (FilterCriteria criteria : criterion) {
-                ret = canApplyIndexFilter(structType, criteria, 
insideOrCondition);
+                ret = canApplyIndexFilter(structTypes, criteria, 
insideOrCondition);
 
                 if (!ret) {
                     break;
@@ -322,10 +337,11 @@ public abstract class SearchProcessor {
             }
         } else if (StringUtils.isNotEmpty(filterCriteria.getAttributeName())) {
             try {
-
-
-                if (insideOrCondition && !isIndexSearchable(filterCriteria, 
structType)) {
-                    ret = false;
+                for (AtlasStructType structType : structTypes) {
+                    if (insideOrCondition && 
!isIndexSearchable(filterCriteria, structType)) {
+                        ret = false;
+                        break;
+                    }
                 }
             } catch (AtlasBaseException e) {
                 LOG.warn(e.getMessage());
@@ -338,7 +354,7 @@ public abstract class SearchProcessor {
     protected void filterWhiteSpaceClassification(List<AtlasVertex> 
entityVertices) {
         if (CollectionUtils.isNotEmpty(entityVertices)) {
             final Iterator<AtlasVertex> it              = 
entityVertices.iterator();
-            final Set<String>           typeAndSubTypes = 
context.getClassificationTypes();
+            final Set<String>           typeAndSubTypes = 
context.getClassificationTypeNames();
 
             while (it.hasNext()) {
                 AtlasVertex  entityVertex        = it.next();
@@ -363,13 +379,13 @@ public abstract class SearchProcessor {
         }
     }
 
-    protected void constructFilterQuery(StringBuilder indexQuery, 
AtlasStructType type, FilterCriteria filterCriteria, Set<String> 
indexAttributes) {
+    protected void constructFilterQuery(StringBuilder indexQuery, Set<? 
extends AtlasStructType> structTypes, FilterCriteria filterCriteria, 
Set<String> indexAttributes) {
         if (filterCriteria != null) {
             if (LOG.isDebugEnabled()) {
                 LOG.debug("Processing Filters");
             }
 
-            String filterQuery = toIndexQuery(type, filterCriteria, 
indexAttributes, 0);
+            String filterQuery = toIndexQuery(structTypes, filterCriteria, 
indexAttributes, 0);
 
             if (StringUtils.isNotEmpty(filterQuery)) {
                 if (indexQuery.length() > 0) {
@@ -381,14 +397,14 @@ public abstract class SearchProcessor {
         }
     }
 
-    protected Predicate constructInMemoryPredicate(AtlasStructType type, 
FilterCriteria filterCriteria, Set<String> indexAttributes) {
+    protected Predicate constructInMemoryPredicate(Set<? extends 
AtlasStructType> structTypes, FilterCriteria filterCriteria, Set<String> 
indexAttributes) {
         Predicate ret = null;
         if (filterCriteria != null) {
             if (LOG.isDebugEnabled()) {
                 LOG.debug("Processing Filters");
             }
 
-            ret = toInMemoryPredicate(type, filterCriteria, indexAttributes);
+            ret = toInMemoryPredicate(structTypes, filterCriteria, 
indexAttributes);
         }
         return ret;
     }
@@ -473,17 +489,20 @@ public abstract class SearchProcessor {
         return ret;
     }
 
-    private String toIndexQuery(AtlasStructType type, FilterCriteria criteria, 
Set<String> indexAttributes, int level) {
-        return toIndexQuery(type, criteria, indexAttributes, new 
StringBuilder(), level);
+    private String toIndexQuery(Set<? extends AtlasStructType> structTypes, 
FilterCriteria criteria, Set<String> indexAttributes, int level) {
+        return toIndexQuery(structTypes, criteria, indexAttributes, new 
StringBuilder(), level);
     }
 
-    private String toIndexQuery(AtlasStructType type, FilterCriteria criteria, 
Set<String> indexAttributes, StringBuilder sb, int level) {
+    private String toIndexQuery(Set<? extends AtlasStructType> structTypes, 
FilterCriteria criteria, Set<String> indexAttributes, StringBuilder sb, int 
level) {
+        Set<String> filterAttributes = new HashSet<>();
+        filterAttributes.addAll(indexAttributes);
+
         Condition condition = criteria.getCondition();
         if (condition != null && 
CollectionUtils.isNotEmpty(criteria.getCriterion())) {
             StringBuilder nestedExpression = new StringBuilder();
 
             for (FilterCriteria filterCriteria : criteria.getCriterion()) {
-                String nestedQuery = toIndexQuery(type, filterCriteria, 
indexAttributes, level + 1);
+                String nestedQuery = toIndexQuery(structTypes, filterCriteria, 
filterAttributes, level + 1);
 
                 if (StringUtils.isNotEmpty(nestedQuery)) {
                     if (nestedExpression.length() > 0) {
@@ -502,19 +521,45 @@ public abstract class SearchProcessor {
             } else {
                 return EMPTY_STRING;
             }
-        } else if (indexAttributes.contains(criteria.getAttributeName())){
-            return toIndexExpression(type, criteria.getAttributeName(), 
criteria.getOperator(), criteria.getAttributeValue());
-        } else {
-            return EMPTY_STRING;
+        } else if (StringUtils.isNotEmpty(criteria.getAttributeName())) {
+            try {
+                ArrayList<String> orExpQuery = new ArrayList<>();
+                for (AtlasStructType structType : structTypes) {
+                    String name = 
structType.getVertexPropertyName(criteria.getAttributeName());
+
+                    if (filterAttributes.contains(name)) {
+                        String nestedQuery = toIndexExpression(structType, 
criteria.getAttributeName(), criteria.getOperator(), 
criteria.getAttributeValue());
+                        orExpQuery.add(nestedQuery);
+                        filterAttributes.remove(name);
+                    }
+                }
+
+                if (CollectionUtils.isNotEmpty(orExpQuery)) {
+                    if (orExpQuery.size() > 1) {
+                        String orExpStr = StringUtils.join(orExpQuery, " 
"+Condition.OR.name()+" ");
+                        return BRACE_OPEN_STR + " " + orExpStr + " " + 
BRACE_CLOSE_STR;
+                    } else {
+                        return orExpQuery.iterator().next();
+                    }
+                } else {
+                    return EMPTY_STRING;
+                }
+            } catch (AtlasBaseException e) {
+                LOG.warn(e.getMessage());
+            }
         }
+        return EMPTY_STRING;
     }
 
-    private Predicate toInMemoryPredicate(AtlasStructType type, FilterCriteria 
criteria, Set<String> indexAttributes) {
+    private Predicate toInMemoryPredicate(Set<? extends AtlasStructType> 
structTypes, FilterCriteria criteria, Set<String> indexAttributes) {
+        Set<String> filterAttributes = new HashSet<>();
+        filterAttributes.addAll(indexAttributes);
+
         if (criteria.getCondition() != null && 
CollectionUtils.isNotEmpty(criteria.getCriterion())) {
             List<Predicate> predicates = new ArrayList<>();
 
             for (FilterCriteria filterCriteria : criteria.getCriterion()) {
-                Predicate predicate = toInMemoryPredicate(type, 
filterCriteria, indexAttributes);
+                Predicate predicate = toInMemoryPredicate(structTypes, 
filterCriteria, filterAttributes);
 
                 if (predicate != null) {
                     predicates.add(predicate);
@@ -528,21 +573,40 @@ public abstract class SearchProcessor {
                     return PredicateUtils.anyPredicate(predicates);
                 }
             }
-        } else if (indexAttributes.contains(criteria.getAttributeName())) {
-            String                    attrName  = criteria.getAttributeName();
-            String                    attrValue = criteria.getAttributeValue();
-            SearchParameters.Operator operator  = criteria.getOperator();
+        } else if (StringUtils.isNotEmpty(criteria.getAttributeName())) {
+            try {
+                ArrayList<Predicate> predicates = new ArrayList<>();
+                for (AtlasStructType structType : structTypes) {
+                    String name = 
structType.getVertexPropertyName(criteria.getAttributeName());
+
+                    if (filterAttributes.contains(name)) {
+                        String attrName                    = 
criteria.getAttributeName();
+                        String attrValue                   = 
criteria.getAttributeValue();
+                        SearchParameters.Operator operator = 
criteria.getOperator();
+
+                        //process attribute value and attribute operator for 
pipeSeperated fields
+                        if (isPipeSeparatedSystemAttribute(attrName)) {
+                            FilterCriteria processedCriteria = 
processPipeSeperatedSystemAttribute(attrName, operator, attrValue);
+                            attrValue                        = 
processedCriteria.getAttributeValue();
+                            operator                         = 
processedCriteria.getOperator();
+                        }
 
-            //process attribute value and attribute operator for pipeSeperated 
fields
-            if (isPipeSeparatedSystemAttribute(attrName)) {
-                FilterCriteria processedCriteria = 
processPipeSeperatedSystemAttribute(attrName, operator, attrValue);
-                attrValue                        = 
processedCriteria.getAttributeValue();
-                operator                         = 
processedCriteria.getOperator();
-            }
+                        predicates.add(toInMemoryPredicate(structType, 
attrName, operator, attrValue));
+                        filterAttributes.remove(name);
+                    }
+                }
 
-            return toInMemoryPredicate(type, attrName, operator, attrValue);
+                if (CollectionUtils.isNotEmpty(predicates)) {
+                    if (predicates.size() > 1) {
+                        return PredicateUtils.anyPredicate(predicates);
+                    } else {
+                        return predicates.iterator().next();
+                    }
+                }
+            } catch (AtlasBaseException e) {
+                LOG.warn(e.getMessage());
+            }
         }
-
         return null;
     }
 
@@ -704,12 +768,15 @@ public abstract class SearchProcessor {
         return ret;
     }
 
-    protected AtlasGraphQuery toGraphFilterQuery(AtlasStructType type, 
FilterCriteria criteria, Set<String> graphAttributes, AtlasGraphQuery query) {
+    protected AtlasGraphQuery toGraphFilterQuery(Set<? extends 
AtlasStructType> structTypes, FilterCriteria criteria, Set<String> 
graphAttributes, AtlasGraphQuery query) {
+        Set<String> filterAttributes = new HashSet<>();
+        filterAttributes.addAll(graphAttributes);
+
         if (criteria != null) {
             if (criteria.getCondition() != null) {
                 if (criteria.getCondition() == Condition.AND) {
                     for (FilterCriteria filterCriteria : 
criteria.getCriterion()) {
-                        AtlasGraphQuery nestedQuery = toGraphFilterQuery(type, 
filterCriteria, graphAttributes, context.getGraph().query());
+                        AtlasGraphQuery nestedQuery = 
toGraphFilterQuery(structTypes, filterCriteria, filterAttributes, 
context.getGraph().query());
 
                         query.addConditionsFrom(nestedQuery);
                     }
@@ -717,7 +784,7 @@ public abstract class SearchProcessor {
                     List<AtlasGraphQuery> orConditions = new LinkedList<>();
 
                     for (FilterCriteria filterCriteria : 
criteria.getCriterion()) {
-                        AtlasGraphQuery nestedQuery = toGraphFilterQuery(type, 
filterCriteria, graphAttributes, context.getGraph().query());
+                        AtlasGraphQuery nestedQuery = 
toGraphFilterQuery(structTypes, filterCriteria, filterAttributes, 
context.getGraph().query());
 
                         
orConditions.add(context.getGraph().query().createChildQuery().addConditionsFrom(nestedQuery));
                     }
@@ -726,60 +793,80 @@ public abstract class SearchProcessor {
                         query.or(orConditions);
                     }
                 }
-            } else if (graphAttributes.contains(criteria.getAttributeName())) {
-                String                    attrName  = 
criteria.getAttributeName();
-                String                    attrValue = 
criteria.getAttributeValue();
-                SearchParameters.Operator operator  = criteria.getOperator();
-
-                //process attribute value and attribute operator for 
pipeSeperated fields
-                if (isPipeSeparatedSystemAttribute(attrName)) {
-                    FilterCriteria processedCriteria = 
processPipeSeperatedSystemAttribute(attrName, operator, attrValue);
-                    attrValue                        = 
processedCriteria.getAttributeValue();
-                    operator                         = 
processedCriteria.getOperator();
-                }
-
-                final String qualifiedName           =  
type.getAttribute(attrName).getVertexPropertyName();
+            } else if (StringUtils.isNotEmpty(criteria.getAttributeName())) {
+                try {
+                    ArrayList<AtlasGraphQuery> queries = new ArrayList<>();
+                    for (AtlasStructType structType : structTypes) {
+                        String qualifiedName = 
structType.getVertexPropertyName(criteria.getAttributeName());
+                        if (filterAttributes.contains(qualifiedName)) {
+
+                            String attrName                    = 
criteria.getAttributeName();
+                            String attrValue                   = 
criteria.getAttributeValue();
+                            SearchParameters.Operator operator = 
criteria.getOperator();
+
+                            //process attribute value and attribute operator 
for pipeSeperated fields
+                            if (isPipeSeparatedSystemAttribute(attrName)) {
+                                FilterCriteria processedCriteria = 
processPipeSeperatedSystemAttribute(attrName, operator, attrValue);
+                                attrValue = 
processedCriteria.getAttributeValue();
+                                operator = processedCriteria.getOperator();
+                            }
+
+                            AtlasGraphQuery innerQry = 
context.getGraph().query().createChildQuery();
+                            switch (operator) {
+                                case LT:
+                                    innerQry.has(qualifiedName, 
AtlasGraphQuery.ComparisionOperator.LESS_THAN, attrValue);
+                                    break;
+                                case LTE:
+                                    innerQry.has(qualifiedName, 
AtlasGraphQuery.ComparisionOperator.LESS_THAN_EQUAL, attrValue);
+                                    break;
+                                case GT:
+                                    innerQry.has(qualifiedName, 
AtlasGraphQuery.ComparisionOperator.GREATER_THAN, attrValue);
+                                    break;
+                                case GTE:
+                                    innerQry.has(qualifiedName, 
AtlasGraphQuery.ComparisionOperator.GREATER_THAN_EQUAL, attrValue);
+                                    break;
+                                case EQ:
+                                    innerQry.has(qualifiedName, 
AtlasGraphQuery.ComparisionOperator.EQUAL, attrValue);
+                                    break;
+                                case NEQ:
+                                    innerQry.has(qualifiedName, 
AtlasGraphQuery.ComparisionOperator.NOT_EQUAL, attrValue);
+                                    break;
+                                case LIKE:
+                                    innerQry.has(qualifiedName, 
AtlasGraphQuery.MatchingOperator.REGEX, attrValue);
+                                    break;
+                                case CONTAINS:
+                                    innerQry.has(qualifiedName, 
AtlasGraphQuery.MatchingOperator.REGEX, getContainsRegex(attrValue));
+                                    break;
+                                case STARTS_WITH:
+                                    innerQry.has(qualifiedName, 
AtlasGraphQuery.MatchingOperator.PREFIX, attrValue);
+                                    break;
+                                case ENDS_WITH:
+                                    innerQry.has(qualifiedName, 
AtlasGraphQuery.MatchingOperator.REGEX, getSuffixRegex(attrValue));
+                                    break;
+                                case IS_NULL:
+                                    innerQry.has(qualifiedName, 
AtlasGraphQuery.ComparisionOperator.EQUAL, null);
+                                    break;
+                                case NOT_NULL:
+                                    innerQry.has(qualifiedName, 
AtlasGraphQuery.ComparisionOperator.NOT_EQUAL, null);
+                                    break;
+                                default:
+                                    LOG.warn("{}: unsupported operator. 
Ignored", operator);
+                                    break;
+                            }
+                            
queries.add(context.getGraph().query().createChildQuery().addConditionsFrom(innerQry));
+                            filterAttributes.remove(qualifiedName);
+                        }
+                    }
 
-                switch (operator) {
-                    case LT:
-                        query.has(qualifiedName, 
AtlasGraphQuery.ComparisionOperator.LESS_THAN, attrValue);
-                        break;
-                    case LTE:
-                        query.has(qualifiedName, 
AtlasGraphQuery.ComparisionOperator.LESS_THAN_EQUAL, attrValue);
-                        break;
-                    case GT:
-                        query.has(qualifiedName, 
AtlasGraphQuery.ComparisionOperator.GREATER_THAN, attrValue);
-                        break;
-                    case GTE:
-                        query.has(qualifiedName, 
AtlasGraphQuery.ComparisionOperator.GREATER_THAN_EQUAL, attrValue);
-                        break;
-                    case EQ:
-                        query.has(qualifiedName, 
AtlasGraphQuery.ComparisionOperator.EQUAL, attrValue);
-                        break;
-                    case NEQ:
-                        query.has(qualifiedName, 
AtlasGraphQuery.ComparisionOperator.NOT_EQUAL, attrValue);
-                        break;
-                    case LIKE:
-                        query.has(qualifiedName, 
AtlasGraphQuery.MatchingOperator.REGEX, attrValue);
-                        break;
-                    case CONTAINS:
-                        query.has(qualifiedName, 
AtlasGraphQuery.MatchingOperator.REGEX, getContainsRegex(attrValue));
-                        break;
-                    case STARTS_WITH:
-                        query.has(qualifiedName, 
AtlasGraphQuery.MatchingOperator.PREFIX, attrValue);
-                        break;
-                    case ENDS_WITH:
-                        query.has(qualifiedName, 
AtlasGraphQuery.MatchingOperator.REGEX, getSuffixRegex(attrValue));
-                        break;
-                    case IS_NULL:
-                        query.has(qualifiedName, 
AtlasGraphQuery.ComparisionOperator.EQUAL, null);
-                        break;
-                    case NOT_NULL:
-                        query.has(qualifiedName, 
AtlasGraphQuery.ComparisionOperator.NOT_EQUAL, null);
-                        break;
-                    default:
-                        LOG.warn("{}: unsupported operator. Ignored", 
operator);
-                        break;
+                    if (CollectionUtils.isNotEmpty(queries)) {
+                        if (queries.size() > 1) {
+                            return 
context.getGraph().query().createChildQuery().or(queries);
+                        } else {
+                            return queries.iterator().next();
+                        }
+                    }
+                } catch (AtlasBaseException e) {
+                    LOG.warn(e.getMessage());
                 }
             }
         }
@@ -987,11 +1074,13 @@ public abstract class SearchProcessor {
     }
 
     private static String getSortByAttribute(SearchContext context) {
-        final AtlasEntityType entityType = context.getEntityType();
-        String sortBy = context.getSearchParameters().getSortBy();
-        AtlasStructType.AtlasAttribute sortByAttribute = entityType != null ? 
entityType.getAttribute(sortBy) : null;
-        if (sortByAttribute != null) {
-            return sortByAttribute.getVertexPropertyName();
+        if (CollectionUtils.isNotEmpty(context.getEntityTypes())) {
+            final AtlasEntityType entityType = 
context.getEntityTypes().iterator().next();
+            String sortBy = context.getSearchParameters().getSortBy();
+            AtlasStructType.AtlasAttribute sortByAttribute = 
entityType.getAttribute(sortBy);
+            if (sortByAttribute != null) {
+                return sortByAttribute.getVertexPropertyName();
+            }
         }
         return null;
     }
diff --git 
a/repository/src/test/java/org/apache/atlas/discovery/EntitySearchProcessorTest.java
 
b/repository/src/test/java/org/apache/atlas/discovery/EntitySearchProcessorTest.java
index 43f11d1..b7ce978 100644
--- 
a/repository/src/test/java/org/apache/atlas/discovery/EntitySearchProcessorTest.java
+++ 
b/repository/src/test/java/org/apache/atlas/discovery/EntitySearchProcessorTest.java
@@ -130,7 +130,7 @@ public class EntitySearchProcessorTest extends 
BasicTestSetup {
         new EntitySearchProcessor(context);
     }
 
-    @Test
+    @Test(priority = -1)
     public void searchWithNEQ_stringAttr() throws AtlasBaseException {
         String expectedEntityName = "hive_Table_Null_tableType";
         createDummyEntity(expectedEntityName,HIVE_TABLE_TYPE);
@@ -197,4 +197,116 @@ public class EntitySearchProcessorTest extends 
BasicTestSetup {
 
         assertTrue(nameList.contains("hive_Table_Null_tableType"));
     }
+
+    @Test
+    public void ALLEntityType() throws AtlasBaseException {
+        SearchParameters params = new SearchParameters();
+        params.setTypeName(SearchParameters.ALL_ENTITY_TYPES);
+        params.setLimit(20);
+
+        SearchContext context = new SearchContext(params, typeRegistry, graph, 
Collections.<String>emptySet());
+
+        EntitySearchProcessor processor = new EntitySearchProcessor(context);
+        assertEquals(processor.execute().size(), 20);
+    }
+
+    @Test
+    public void ALLEntityTypeWithTag() throws AtlasBaseException {
+        SearchParameters params = new SearchParameters();
+        params.setTypeName(SearchParameters.ALL_ENTITY_TYPES);
+        params.setClassification(FACT_CLASSIFICATION);
+        params.setLimit(20);
+
+        SearchContext context = new SearchContext(params, typeRegistry, graph, 
Collections.<String>emptySet());
+
+        EntitySearchProcessor processor = new EntitySearchProcessor(context);
+        assertEquals(processor.execute().size(), 5);
+    }
+
+    @Test
+    public void entityType() throws AtlasBaseException {
+        SearchParameters params = new SearchParameters();
+        params.setTypeName(DATABASE_TYPE);
+        params.setLimit(20);
+
+        SearchContext context = new SearchContext(params, typeRegistry, graph, 
Collections.<String>emptySet());
+
+        EntitySearchProcessor processor = new EntitySearchProcessor(context);
+        assertEquals(processor.execute().size(), 3);
+    }
+
+    @Test
+    public void entityTypes() throws AtlasBaseException {
+        SearchParameters params = new SearchParameters();
+        params.setTypeName(DATABASE_TYPE+","+HIVE_TABLE_TYPE);
+        params.setLimit(20);
+
+        SearchContext context = new SearchContext(params, typeRegistry, graph, 
Collections.<String>emptySet());
+
+        EntitySearchProcessor processor = new EntitySearchProcessor(context);
+        assertEquals(processor.execute().size(), 14);
+    }
+
+    @Test(expectedExceptions = AtlasBaseException.class, 
expectedExceptionsMessageRegExp = "Not_Exists: Unknown/invalid typename")
+    public void entityTypesNotAllowed() throws AtlasBaseException {
+        SearchParameters params = new SearchParameters();
+        params.setTypeName(DATABASE_TYPE+",Not_Exists");
+        params.setLimit(20);
+
+        SearchContext context = new SearchContext(params, typeRegistry, graph, 
Collections.<String>emptySet());
+    }
+
+    @Test(expectedExceptions = AtlasBaseException.class, 
expectedExceptionsMessageRegExp = "Attribute tableType not found for type 
"+DATABASE_TYPE)
+    public void entityFiltersNotAllowed() throws AtlasBaseException {
+        SearchParameters params = new SearchParameters();
+        params.setTypeName(DATABASE_TYPE+","+HIVE_TABLE_TYPE);
+        SearchParameters.FilterCriteria filterCriteria = 
getSingleFilterCondition("tableType", SearchParameters.Operator.CONTAINS, 
"ETL");
+        params.setEntityFilters(filterCriteria);
+        params.setLimit(20);
+
+        SearchContext context = new SearchContext(params, typeRegistry, graph, 
Collections.<String>emptySet());
+    }
+
+    @Test
+    public void entityTypesAndTag() throws AtlasBaseException {
+        SearchParameters params = new SearchParameters();
+        params.setTypeName(DATABASE_TYPE+","+HIVE_TABLE_TYPE);
+        params.setClassification(FACT_CLASSIFICATION);
+        params.setLimit(20);
+
+        SearchContext context = new SearchContext(params, typeRegistry, graph, 
Collections.<String>emptySet());
+
+        EntitySearchProcessor processor = new EntitySearchProcessor(context);
+        assertEquals(processor.execute().size(), 3);
+    }
+
+    @Test
+    public void searchWithEntityTypesAndEntityFilters() throws 
AtlasBaseException {
+        SearchParameters params = new SearchParameters();
+        params.setTypeName(DATABASE_TYPE+","+HIVE_TABLE_TYPE);
+        SearchParameters.FilterCriteria filterCriteria = 
getSingleFilterCondition("owner", SearchParameters.Operator.CONTAINS, "ETL");
+        params.setEntityFilters(filterCriteria);
+        params.setLimit(20);
+
+        SearchContext context = new SearchContext(params, typeRegistry, graph, 
Collections.<String>emptySet());
+
+        EntitySearchProcessor processor = new EntitySearchProcessor(context);
+        assertEquals(processor.execute().size(), 4);
+    }
+
+    @Test
+    public void searchWithEntityTypesAndEntityFiltersAndTag() throws 
AtlasBaseException {
+        SearchParameters params = new SearchParameters();
+        params.setTypeName(DATABASE_TYPE+","+HIVE_TABLE_TYPE);
+        SearchParameters.FilterCriteria filterCriteria = 
getSingleFilterCondition("owner", SearchParameters.Operator.CONTAINS, "ETL");
+        params.setEntityFilters(filterCriteria);
+        params.setClassification(LOGDATA_CLASSIFICATION);
+        params.setLimit(20);
+
+        SearchContext context = new SearchContext(params, typeRegistry, graph, 
Collections.<String>emptySet());
+
+        EntitySearchProcessor processor = new EntitySearchProcessor(context);
+        assertEquals(processor.execute().size(), 2);
+    }
+
 }

Reply via email to