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

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

commit 7312a26528dddb56a5e0c67106b306637978b5a1
Author: sheetalshah1007 <[email protected]>
AuthorDate: Fri Mar 13 10:24:50 2026 +0530

    ATLAS-5194: Add pagination while fetching relationships of an entity (#510)
    
    (cherry picked from commit a807e6d6d18fd356d687bc3bd4501e15c6312544)
---
 .../main/java/org/apache/atlas/AtlasErrorCode.java |   1 +
 .../atlas/discovery/AtlasDiscoveryService.java     |  28 +++-
 .../atlas/discovery/EntityDiscoveryService.java    |  85 ++++++-----
 .../atlas/discovery/AtlasDiscoveryServiceTest.java | 161 ++++++++++++++++++++-
 .../discovery/EntityDiscoveryServiceTest.java      |   2 +-
 .../org/apache/atlas/web/rest/DiscoveryREST.java   |  22 ++-
 .../apache/atlas/web/rest/DiscoveryRESTTest.java   |   8 +-
 7 files changed, 250 insertions(+), 57 deletions(-)

diff --git a/intg/src/main/java/org/apache/atlas/AtlasErrorCode.java 
b/intg/src/main/java/org/apache/atlas/AtlasErrorCode.java
index ff856e497..2c7fc45e5 100644
--- a/intg/src/main/java/org/apache/atlas/AtlasErrorCode.java
+++ b/intg/src/main/java/org/apache/atlas/AtlasErrorCode.java
@@ -182,6 +182,7 @@ public enum AtlasErrorCode {
     INVALID_OPERATOR(400, "ATLAS-400-00-103", "Invalid operator specified for 
attribute: {0}"),
     BLANK_NAME_ATTRIBUTE(400, "ATLAS-400-00-104", "Name Attribute can't be 
empty!"),
     BLANK_VALUE_ATTRIBUTE(400, "ATLAS-400-00-105", "Value Attribute can't be 
empty!"),
+    INVALID_RELATIONSHIP_LABEL(400, "ATLAS-400-00-106", "Invalid relationship 
label '{0}'. The referenced entity type '{1}' could not be resolved from the 
type registry."),
 
     UNAUTHORIZED_ACCESS(403, "ATLAS-403-00-001", "{0} is not authorized to 
perform {1}"),
 
diff --git 
a/repository/src/main/java/org/apache/atlas/discovery/AtlasDiscoveryService.java
 
b/repository/src/main/java/org/apache/atlas/discovery/AtlasDiscoveryService.java
index 9e0f1973d..9beec5888 100644
--- 
a/repository/src/main/java/org/apache/atlas/discovery/AtlasDiscoveryService.java
+++ 
b/repository/src/main/java/org/apache/atlas/discovery/AtlasDiscoveryService.java
@@ -103,13 +103,27 @@ public interface AtlasDiscoveryService {
     AtlasSearchResult 
searchRelationsWithParameters(RelationshipSearchParameters searchParameters) 
throws AtlasBaseException;
 
     /**
-     * @param guid unique ID of the entity.
-     * @param relation relation name.
-     * @param getApproximateCount
-     * @param searchParameters
-     * @return AtlasSearchResult
-     */
-    AtlasSearchResult searchRelatedEntities(String guid, String relation, 
boolean getApproximateCount, SearchParameters searchParameters) throws 
AtlasBaseException;
+     * Search for entities related to a given entity through a specified 
relationship.
+     *
+     * @param guid unique ID of the entity
+     * @param relation relationship name or attribute name
+     * @param getApproximateCount whether to calculate and return the 
approximate count of related entities;
+     *                            when true and excludeDeletedEntities is 
enabled, counts only active entities
+     * @param searchParameters search parameters including:
+     *                         - sortBy: attribute name to sort by (overrides 
default sorting)
+     *                         - sortOrder: ASCENDING or DESCENDING
+     *                         - limit: maximum number of results to return
+     *                         - offset: starting position for pagination
+     *                         - excludeDeletedEntities: filter out deleted 
entities
+     *                         - attributes: specific attributes to include in 
results
+     *                         - includeClassificationAttributes: include 
classifications in results
+     * @param disableDefaultSorting when false (default), applies default 
"name" sorting if sortBy is not specified;
+     *                              when true, disables default sorting for 
better performance with large result sets
+     *                              (recommended for pagination with high 
offsets on unsorted queries)
+     * @return AtlasSearchResult containing related entities with accurate 
approximateCount (excludes deleted entities when requested)
+     * @throws AtlasBaseException if guid is invalid, relationship doesn't 
exist, or query parameters are invalid
+     */
+    AtlasSearchResult searchRelatedEntities(String guid, String relation, 
boolean getApproximateCount, SearchParameters searchParameters, boolean 
disableDefaultSorting) throws AtlasBaseException;
 
     /**
      * @param savedSearch Search to be saved
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 a85425cd8..25b52b24d 100644
--- 
a/repository/src/main/java/org/apache/atlas/discovery/EntityDiscoveryService.java
+++ 
b/repository/src/main/java/org/apache/atlas/discovery/EntityDiscoveryService.java
@@ -76,10 +76,8 @@ import org.apache.atlas.type.AtlasType;
 import org.apache.atlas.type.AtlasTypeRegistry;
 import org.apache.atlas.util.AtlasGremlinQueryProvider;
 import org.apache.atlas.util.AtlasGremlinQueryProvider.AtlasGremlinQuery;
-import org.apache.atlas.util.SearchPredicateUtil;
 import org.apache.atlas.util.SearchTracker;
 import org.apache.commons.collections.CollectionUtils;
-import org.apache.commons.collections.Predicate;
 import org.apache.commons.collections4.IteratorUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.tinkerpop.gremlin.process.traversal.Order;
@@ -504,7 +502,7 @@ public class EntityDiscoveryService implements 
AtlasDiscoveryService {
 
     @Override
     @GraphTransaction
-    public AtlasSearchResult searchRelatedEntities(String guid, String 
relation, boolean getApproximateCount, SearchParameters searchParameters) 
throws AtlasBaseException {
+    public AtlasSearchResult searchRelatedEntities(String guid, String 
relation, boolean getApproximateCount, SearchParameters searchParameters, 
boolean disableDefaultSorting) throws AtlasBaseException {
         AtlasSearchResult ret = new 
AtlasSearchResult(AtlasQueryType.RELATIONSHIP);
 
         if (StringUtils.isEmpty(guid) || StringUtils.isEmpty(relation)) {
@@ -544,6 +542,10 @@ public class EntityDiscoveryService implements 
AtlasDiscoveryService {
             if (StringUtils.isNotEmpty(endEntityTypeName)) {
                 endEntityType = 
typeRegistry.getEntityTypeByName(endEntityTypeName);
             }
+
+            if (endEntityType == null) {
+                throw new 
AtlasBaseException(AtlasErrorCode.INVALID_RELATIONSHIP_LABEL, relation, 
endEntityTypeName);
+            }
         }
 
         //validate sortBy attribute
@@ -551,24 +553,29 @@ public class EntityDiscoveryService implements 
AtlasDiscoveryService {
         SortOrder sortOrder           = searchParameters.getSortOrder();
         int       offset              = searchParameters.getOffset();
         int       limit               = searchParameters.getLimit();
-        String    sortByAttributeName = DEFAULT_SORT_ATTRIBUTE_NAME;
+        String    sortByAttributeName = null;
 
-        if (StringUtils.isNotEmpty(sortBy)) {
-            sortByAttributeName = sortBy;
-        }
+        if (disableDefaultSorting && StringUtils.isEmpty(sortBy)) {
+            sortOrder = null;
+        } else {
+            if (StringUtils.isNotEmpty(sortBy)) {
+                sortByAttributeName = sortBy;
+            } else if (!disableDefaultSorting) {
+                sortByAttributeName = DEFAULT_SORT_ATTRIBUTE_NAME;
+            }
 
-        if (endEntityType != null) {
             AtlasAttribute sortByAttribute = 
endEntityType.getAttribute(sortByAttributeName);
 
             if (sortByAttribute == null) {
-                sortByAttributeName = null;
-                sortOrder           = null;
-
                 if (StringUtils.isNotEmpty(sortBy)) {
-                    LOG.info("Invalid sortBy Attribute {} for entityType {}, 
Ignoring Sorting", sortBy, endEntityType.getTypeName());
+                    LOG.info("Invalid sortBy '{}' for type {}, using unsorted 
query",
+                            sortBy, endEntityType.getTypeName());
                 } else {
-                    LOG.info("Invalid Default sortBy Attribute {} for 
entityType {}, Ignoring Sorting", DEFAULT_SORT_ATTRIBUTE_NAME, 
endEntityType.getTypeName());
+                    LOG.info("Default sortBy '{}' not found for type {}, using 
unsorted query",
+                            DEFAULT_SORT_ATTRIBUTE_NAME, 
endEntityType.getTypeName());
                 }
+                sortByAttributeName = null;
+                sortOrder           = null;
             } else {
                 sortByAttributeName = sortByAttribute.getVertexPropertyName();
 
@@ -576,12 +583,11 @@ public class EntityDiscoveryService implements 
AtlasDiscoveryService {
                     sortOrder = ASCENDING;
                 }
             }
-        } else {
-            sortOrder = null;
-
-            LOG.info("Invalid sortBy Attribute {}, Ignoring Sorting", sortBy);
         }
 
+        LOG.debug("searchRelatedEntities: guid={}, relation={}, sortBy={}, 
order={}, offset={}, limit={}, excludeDeleted={}",
+                guid, relation, sortByAttributeName, sortOrder, offset, limit, 
searchParameters.getExcludeDeletedEntities());
+
         //get relationship(end vertices) vertices
         GraphTraversal gt = 
graph.V(entityVertex.getId()).bothE(relation).otherV();
 
@@ -589,7 +595,7 @@ public class EntityDiscoveryService implements 
AtlasDiscoveryService {
             gt.has(Constants.STATE_PROPERTY_KEY, 
AtlasEntity.Status.ACTIVE.name());
         }
 
-        if (sortOrder != null) {
+        if (sortOrder != null && StringUtils.isNotEmpty(sortByAttributeName)) {
             if (sortOrder == ASCENDING) {
                 gt.order().by(sortByAttributeName, Order.asc);
             } else {
@@ -607,37 +613,39 @@ public class EntityDiscoveryService implements 
AtlasDiscoveryService {
             if (v != null && 
v.property(Constants.GUID_PROPERTY_KEY).isPresent()) {
                 String            endVertexGuid = 
v.property(Constants.GUID_PROPERTY_KEY).value().toString();
                 AtlasVertex       vertex        = 
entityRetriever.getEntityVertex(endVertexGuid);
-                AtlasEntityHeader entity        = 
entityRetriever.toAtlasEntityHeader(vertex, searchParameters.getAttributes());
 
-                if (searchParameters.getIncludeClassificationAttributes()) {
-                    
entity.setClassifications(entityRetriever.getAllClassifications(vertex));
-                }
+                if (vertex != null) {
+                    AtlasEntityHeader entity = 
entityRetriever.toAtlasEntityHeader(vertex, searchParameters.getAttributes());
 
-                resultList.add(entity);
+                    if (searchParameters.getIncludeClassificationAttributes()) 
{
+                        
entity.setClassifications(entityRetriever.getAllClassifications(vertex));
+                    }
+
+                    resultList.add(entity);
+                }
             }
         }
 
         ret.setEntities(resultList);
 
-        if (ret.getEntities() == null) {
-            ret.setEntities(new ArrayList<>());
-        }
-
-        //set approximate count
-        //state of the edge and endVertex will be same
+        // Set approximate count
         if (getApproximateCount) {
             Iterator<AtlasEdge> edges = 
GraphHelper.getAdjacentEdgesByLabel(entityVertex, AtlasEdgeDirection.BOTH, 
relation);
 
             if (searchParameters.getExcludeDeletedEntities()) {
-                List<AtlasEdge> edgeList = new ArrayList<>();
-
-                edges.forEachRemaining(edgeList::add);
+                // Count edges where end vertex is ACTIVE (edges remain ACTIVE 
when only one end is deleted)
+                int activeCount = 0;
 
-                Predicate activePredicate = 
SearchPredicateUtil.getEQPredicateGenerator().generatePredicate(Constants.STATE_PROPERTY_KEY,
 AtlasEntity.Status.ACTIVE.name(), String.class);
+                while (edges.hasNext()) {
+                    AtlasEdge   edge      = edges.next();
+                    AtlasVertex endVertex = getOtherVertex(edge, entityVertex);
 
-                CollectionUtils.filter(edgeList, activePredicate);
+                    if (endVertex != null && GraphHelper.getStatus(endVertex) 
== ACTIVE) {
+                        activeCount++;
+                    }
+                }
 
-                ret.setApproximateCount(edgeList.size());
+                ret.setApproximateCount(activeCount);
             } else {
                 ret.setApproximateCount(IteratorUtils.size(edges));
             }
@@ -648,6 +656,13 @@ public class EntityDiscoveryService implements 
AtlasDiscoveryService {
         return ret;
     }
 
+    private AtlasVertex getOtherVertex(AtlasEdge edge, AtlasVertex vertex) {
+        AtlasVertex outVertex = edge.getOutVertex();
+        AtlasVertex inVertex  = edge.getInVertex();
+
+        return StringUtils.equals(outVertex.getIdForDisplay(), 
vertex.getIdForDisplay()) ? inVertex : outVertex;
+    }
+
     @Override
     public AtlasUserSavedSearch addSavedSearch(String currentUser, 
AtlasUserSavedSearch savedSearch) throws AtlasBaseException {
         try {
diff --git 
a/repository/src/test/java/org/apache/atlas/discovery/AtlasDiscoveryServiceTest.java
 
b/repository/src/test/java/org/apache/atlas/discovery/AtlasDiscoveryServiceTest.java
index fc6432bbe..9a324fa22 100644
--- 
a/repository/src/test/java/org/apache/atlas/discovery/AtlasDiscoveryServiceTest.java
+++ 
b/repository/src/test/java/org/apache/atlas/discovery/AtlasDiscoveryServiceTest.java
@@ -51,6 +51,7 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import static 
org.apache.atlas.model.discovery.SearchParameters.ALL_CLASSIFICATION_TYPES;
 import static 
org.apache.atlas.model.discovery.SearchParameters.ALL_ENTITY_TYPES;
@@ -698,7 +699,7 @@ public class AtlasDiscoveryServiceTest extends 
BasicTestSetup {
 
         params.setLimit(10);
 
-        AtlasSearchResult       relResult = 
discoveryService.searchRelatedEntities(guid, "__hive_table.columns", false, 
params);
+        AtlasSearchResult       relResult = 
discoveryService.searchRelatedEntities(guid, "__hive_table.columns", false, 
params, false);
         List<AtlasEntityHeader> list      = relResult.getEntities();
 
         assertTrue(CollectionUtils.isNotEmpty(list));
@@ -715,7 +716,7 @@ public class AtlasDiscoveryServiceTest extends 
BasicTestSetup {
         params.setLimit(10);
         params.setSortOrder(SortOrder.DESCENDING);
 
-        AtlasSearchResult       relResult = 
discoveryService.searchRelatedEntities(guid, "columns", false, params);
+        AtlasSearchResult       relResult = 
discoveryService.searchRelatedEntities(guid, "columns", false, params, false);
         List<AtlasEntityHeader> list      = relResult.getEntities();
 
         assertTrue(CollectionUtils.isNotEmpty(list));
@@ -724,6 +725,162 @@ public class AtlasDiscoveryServiceTest extends 
BasicTestSetup {
         assertTrue(list.get(0).getDisplayText().equalsIgnoreCase("time_id"));
     }
 
+    @Test
+    public void testSearchRelatedEntitiesWithDisableDefaultSorting() throws 
AtlasBaseException {
+        String           guid   = gethiveTableSalesFactGuid();
+        SearchParameters params = new SearchParameters();
+
+        params.setLimit(10);
+
+        // Test 1: With disableDefaultSorting=true (no sorting applied)
+        AtlasSearchResult unsortedResult = 
discoveryService.searchRelatedEntities(
+                guid, "__hive_table.columns", false, params, true);
+        List<AtlasEntityHeader> unsortedList = unsortedResult.getEntities();
+
+        assertTrue(CollectionUtils.isNotEmpty(unsortedList));
+        assertEquals(unsortedList.size(), 6);
+
+        // Test 2: With disableDefaultSorting=false (default name sorting 
applied)
+        AtlasSearchResult sortedResult = 
discoveryService.searchRelatedEntities(
+                guid, "__hive_table.columns", false, params, false);
+        List<AtlasEntityHeader> sortedList = sortedResult.getEntities();
+
+        assertTrue(CollectionUtils.isNotEmpty(sortedList));
+        assertEquals(sortedList.size(), 6);
+
+        // Both should return same number of entities (order may differ)
+        assertEquals(unsortedList.size(), sortedList.size());
+
+        // Verify all entities are present in both results
+        Set<String> unsortedGuids = unsortedList.stream()
+                .map(AtlasEntityHeader::getGuid)
+                .collect(java.util.stream.Collectors.toSet());
+        Set<String> sortedGuids = sortedList.stream()
+                .map(AtlasEntityHeader::getGuid)
+                .collect(java.util.stream.Collectors.toSet());
+
+        assertEquals(unsortedGuids, sortedGuids, "Both methods should return 
same entities");
+    }
+
+    @Test
+    public void testSearchRelatedEntitiesWithOffset() throws 
AtlasBaseException {
+        String           guid   = gethiveTableSalesFactGuid();
+        SearchParameters params = new SearchParameters();
+
+        // Fetch first page (entities 0-2)
+        params.setOffset(0);
+        params.setLimit(2);
+        AtlasSearchResult page1 = discoveryService.searchRelatedEntities(
+                guid, "__hive_table.columns", false, params, true);
+        List<AtlasEntityHeader> page1List = page1.getEntities();
+
+        assertTrue(CollectionUtils.isNotEmpty(page1List));
+        assertEquals(page1List.size(), 2);
+
+        // Fetch second page (entities 2-4)
+        params.setOffset(2);
+        params.setLimit(2);
+        AtlasSearchResult page2 = discoveryService.searchRelatedEntities(
+                guid, "__hive_table.columns", false, params, true);
+        List<AtlasEntityHeader> page2List = page2.getEntities();
+
+        assertTrue(CollectionUtils.isNotEmpty(page2List));
+        assertEquals(page2List.size(), 2);
+
+        // Fetch third page (entities 4-6)
+        params.setOffset(4);
+        params.setLimit(2);
+        AtlasSearchResult page3 = discoveryService.searchRelatedEntities(
+                guid, "__hive_table.columns", false, params, true);
+        List<AtlasEntityHeader> page3List = page3.getEntities();
+
+        assertTrue(CollectionUtils.isNotEmpty(page3List));
+        assertEquals(page3List.size(), 2);
+
+        // Verify pages are different
+        
assertTrue(!page1List.get(0).getGuid().equals(page2List.get(0).getGuid()),
+                "Page 1 and Page 2 should have different first entities");
+        
assertTrue(!page2List.get(0).getGuid().equals(page3List.get(0).getGuid()),
+                "Page 2 and Page 3 should have different first entities");
+
+        // Verify offset beyond available entities returns empty
+        params.setOffset(100);
+        params.setLimit(10);
+        AtlasSearchResult emptyPage = discoveryService.searchRelatedEntities(
+                guid, "__hive_table.columns", false, params, true);
+
+        assertTrue(CollectionUtils.isEmpty(emptyPage.getEntities()) || 
emptyPage.getEntities().size() == 0);
+    }
+
+    @Test
+    public void testSearchRelatedEntitiesWithDeletedEntities() throws 
AtlasBaseException {
+        String           guid   = gethiveTableSalesFactGuid();
+        SearchParameters params = new SearchParameters();
+
+        params.setLimit(20);
+        params.setExcludeDeletedEntities(true);
+
+        // Test with disableDefaultSorting=true and excludeDeletedEntities=true
+        AtlasSearchResult result = discoveryService.searchRelatedEntities(
+                guid, "__hive_table.columns", false, params, true);
+
+        assertNotNull(result);
+        List<AtlasEntityHeader> entities = result.getEntities();
+        assertTrue(CollectionUtils.isNotEmpty(entities));
+
+        // Verify all returned entities are ACTIVE
+        for (AtlasEntityHeader entity : entities) {
+            assertTrue(!AtlasEntity.Status.DELETED.equals(entity.getStatus()),
+                    "Should not return DELETED entities when 
excludeDeletedEntities=true");
+        }
+
+        // Test with excludeDeletedEntities=false to get all entities
+        params.setExcludeDeletedEntities(false);
+        AtlasSearchResult resultWithDeleted = 
discoveryService.searchRelatedEntities(
+                guid, "__hive_table.columns", false, params, true);
+
+        assertNotNull(resultWithDeleted);
+        // Result should have same or more entities when not excluding deleted
+        assertTrue(resultWithDeleted.getEntities().size() >= 
result.getEntities().size());
+    }
+
+    @Test
+    public void testApproximateCountExcludesDeleted() throws 
AtlasBaseException {
+        String           guid   = gethiveTableSalesFactGuid();
+        SearchParameters params = new SearchParameters();
+
+        params.setLimit(10);
+        params.setExcludeDeletedEntities(true);
+
+        // Test with disableDefaultSorting=true and getApproximateCount=true
+        AtlasSearchResult result = discoveryService.searchRelatedEntities(
+                guid, "__hive_table.columns", true, params, true);
+
+        assertNotNull(result);
+        assertTrue(result.getApproximateCount() > 0, "Approximate count should 
be greater than 0");
+
+        // The count should reflect only ACTIVE entities
+        long approximateCount = result.getApproximateCount();
+        long actualCount = result.getEntities().size();
+
+        // Approximate count should be close to actual entity count
+        // (may differ if there are more entities beyond limit)
+        assertTrue(approximateCount >= actualCount,
+                "Approximate count should be >= actual returned entities");
+
+        // Test without excluding deleted entities
+        params.setExcludeDeletedEntities(false);
+        AtlasSearchResult resultWithDeleted = 
discoveryService.searchRelatedEntities(
+                guid, "__hive_table.columns", true, params, true);
+
+        assertNotNull(resultWithDeleted);
+        long countWithDeleted = resultWithDeleted.getApproximateCount();
+
+        // Count including deleted should be >= count excluding deleted
+        assertTrue(countWithDeleted >= approximateCount,
+                "Count with deleted entities should be >= count without 
deleted");
+    }
+
     //test excludeHeaderAttributes
     @Test
     public void excludeHeaderAttributesStringAttr() throws AtlasBaseException {
diff --git 
a/repository/src/test/java/org/apache/atlas/discovery/EntityDiscoveryServiceTest.java
 
b/repository/src/test/java/org/apache/atlas/discovery/EntityDiscoveryServiceTest.java
index 6e8c5c403..7f3b31f8f 100644
--- 
a/repository/src/test/java/org/apache/atlas/discovery/EntityDiscoveryServiceTest.java
+++ 
b/repository/src/test/java/org/apache/atlas/discovery/EntityDiscoveryServiceTest.java
@@ -314,7 +314,7 @@ public class EntityDiscoveryServiceTest {
     public void testSearchRelatedEntities() throws AtlasBaseException {
         SearchParameters params = new SearchParameters();
         try {
-            AtlasSearchResult result = 
entityDiscoveryService.searchRelatedEntities("testGuid", "testRelation", false, 
params);
+            AtlasSearchResult result = 
entityDiscoveryService.searchRelatedEntities("testGuid", "testRelation", false, 
params, false);
         } catch (Exception e) {
             assertTrue(true);
         }
diff --git a/webapp/src/main/java/org/apache/atlas/web/rest/DiscoveryREST.java 
b/webapp/src/main/java/org/apache/atlas/web/rest/DiscoveryREST.java
index f18600944..6f404a656 100644
--- a/webapp/src/main/java/org/apache/atlas/web/rest/DiscoveryREST.java
+++ b/webapp/src/main/java/org/apache/atlas/web/rest/DiscoveryREST.java
@@ -55,6 +55,7 @@ import javax.inject.Singleton;
 import javax.servlet.http.HttpServletRequest;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
+import javax.ws.rs.DefaultValue;
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
 import javax.ws.rs.PUT;
@@ -514,17 +515,21 @@ public class DiscoveryREST {
     /**
      * Relationship search to search for related entities satisfying the 
search parameters
      *
-     * @param guid Attribute name
-     * @param relation relationName
-     * @param attributes set of attributes in search result.
-     * @param sortByAttribute sort the result using this attribute name, 
default value is 'name'
-     * @param sortOrder sorting order
+     * @param guid entity GUID
+     * @param relation relationship name or attribute name
+     * @param attributes set of attributes to include in search result
+     * @param sortByAttribute attribute name to sort results by (if not 
specified and disableDefaultSorting=false, defaults to 'name')
+     * @param sortOrder sorting order (ASCENDING or DESCENDING)
+     * @param excludeDeletedEntities exclude deleted entities from results
+     * @param includeClassificationAttributes include classification 
attributes in result entities
+     * @param getApproximateCount calculate and return approximate count of 
total relationships
+     * @param disableDefaultSorting if true, disables default sorting by 
'name' when sortByAttribute is not specified; allows unsorted results for 
better performance
      * @param limit limit the result set to only include the specified number 
of entries
      * @param offset start offset of the result set (useful for pagination)
      * @return Atlas search result
      * @throws AtlasBaseException
      * @HTTP 200 On successful search
-     * @HTTP 400 guid is not a valid entity type or attributeName is not a 
valid relationship attribute
+     * @HTTP 400 guid is not a valid entity type or relationship name is not a 
valid relationship attribute
      */
     @GET
     @Path("relationship")
@@ -537,6 +542,7 @@ public class DiscoveryREST {
             @QueryParam("excludeDeletedEntities") boolean 
excludeDeletedEntities,
             @QueryParam("includeClassificationAttributes") boolean 
includeClassificationAttributes,
             @QueryParam("getApproximateCount") boolean getApproximateCount,
+            @DefaultValue("false") @QueryParam("disableDefaultSorting") 
boolean disableDefaultSorting,
             @QueryParam("limit") int limit,
             @QueryParam("offset") int offset) throws AtlasBaseException {
         Servlets.validateQueryParamLength("guid", guid);
@@ -547,7 +553,7 @@ public class DiscoveryREST {
 
         try {
             if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
-                perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, 
"DiscoveryREST.relatedEntitiesSearch(" + guid + ", " + relation + ", " + 
sortByAttribute + ", " + sortOrder + ", " + excludeDeletedEntities + ", " + 
getApproximateCount + ", " + limit + ", " + offset + ")");
+                perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, 
"DiscoveryREST.searchRelatedEntities(" + guid + ", " + relation + ", " + 
sortByAttribute + ", " + sortOrder + ", " + excludeDeletedEntities + ", " + 
getApproximateCount + ", " + disableDefaultSorting + ", " + limit + ", " + 
offset + ")");
             }
 
             SearchParameters parameters = new SearchParameters();
@@ -560,7 +566,7 @@ public class DiscoveryREST {
             parameters.setOffset(offset);
             
parameters.setIncludeClassificationAttributes(includeClassificationAttributes);
 
-            return discoveryService.searchRelatedEntities(guid, relation, 
getApproximateCount, parameters);
+            return discoveryService.searchRelatedEntities(guid, relation, 
getApproximateCount, parameters, disableDefaultSorting);
         } finally {
             AtlasPerfTracer.log(perf);
         }
diff --git 
a/webapp/src/test/java/org/apache/atlas/web/rest/DiscoveryRESTTest.java 
b/webapp/src/test/java/org/apache/atlas/web/rest/DiscoveryRESTTest.java
index f43c9fe89..b4bd5abcf 100644
--- a/webapp/src/test/java/org/apache/atlas/web/rest/DiscoveryRESTTest.java
+++ b/webapp/src/test/java/org/apache/atlas/web/rest/DiscoveryRESTTest.java
@@ -504,15 +504,15 @@ public class DiscoveryRESTTest {
         AtlasSearchResult expectedResult = getAtlasSearchResult();
 
         when(mockDiscoveryService.searchRelatedEntities(eq(guid), 
eq(relation), eq(getApproximateCount),
-                any(SearchParameters.class))).thenReturn(expectedResult);
+                any(SearchParameters.class), 
eq(false))).thenReturn(expectedResult);
 
         AtlasSearchResult actualResult = 
discoveryREST.searchRelatedEntities(guid, relation, attributes, sortByAttribute,
-                sortOrder, excludeDeletedEntities, 
includeClassificationAttributes, getApproximateCount, limit, offset);
+                sortOrder, excludeDeletedEntities, 
includeClassificationAttributes, getApproximateCount, false, limit, offset);
 
         assertNotNull(actualResult);
         assertEquals(actualResult, expectedResult);
         verify(mockDiscoveryService, times(1)).searchRelatedEntities(eq(guid), 
eq(relation), eq(getApproximateCount),
-                any(SearchParameters.class));
+                any(SearchParameters.class), eq(false));
     }
 
     @Test
@@ -531,7 +531,7 @@ public class DiscoveryRESTTest {
 
         AtlasBaseException exception = expectThrows(AtlasBaseException.class,
                 () -> discoveryREST.searchRelatedEntities(guid, relation, 
attributes, sortByAttribute, sortOrder,
-                        excludeDeletedEntities, 
includeClassificationAttributes, getApproximateCount, limit, offset));
+                        excludeDeletedEntities, 
includeClassificationAttributes, getApproximateCount, false, limit, offset));
 
         TestUtility.assertInvalidParamLength(exception, "guid");
     }

Reply via email to