Commit c31f1440 by Bolke de Bruin Committed by Madhan Neethiraj

ATLAS-3399: added support for order-by in basic-search

parent 1c781deb
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
package org.apache.atlas.repository.graphdb; package org.apache.atlas.repository.graphdb;
import org.apache.tinkerpop.gremlin.process.traversal.Order;
import java.util.Iterator; import java.util.Iterator;
/** /**
...@@ -36,6 +38,14 @@ public interface AtlasIndexQuery<V, E> { ...@@ -36,6 +38,14 @@ public interface AtlasIndexQuery<V, E> {
Iterator<Result<V, E>> vertices(); Iterator<Result<V, E>> vertices();
/** /**
* Gets the sorted query results
* @param offset starting offset
* @param limit max number of results
* @return
*/
Iterator<Result<V, E>> vertices(int offset, int limit, String sortBy, Order sortOrder);
/**
* Gets the query results * Gets the query results
* @param offset starting offset * @param offset starting offset
* @param limit max number of results * @param limit max number of results
......
...@@ -25,6 +25,7 @@ import org.apache.atlas.repository.graphdb.AtlasVertex; ...@@ -25,6 +25,7 @@ import org.apache.atlas.repository.graphdb.AtlasVertex;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.collect.Iterators; import com.google.common.collect.Iterators;
import org.apache.tinkerpop.gremlin.process.traversal.Order;
import org.janusgraph.core.JanusGraphIndexQuery; import org.janusgraph.core.JanusGraphIndexQuery;
import org.janusgraph.core.JanusGraphVertex; import org.janusgraph.core.JanusGraphVertex;
...@@ -78,6 +79,29 @@ public class AtlasJanusIndexQuery implements AtlasIndexQuery<AtlasJanusVertex, A ...@@ -78,6 +79,29 @@ public class AtlasJanusIndexQuery implements AtlasIndexQuery<AtlasJanusVertex, A
} }
@Override @Override
public Iterator<Result<AtlasJanusVertex, AtlasJanusEdge>> vertices(int offset, int limit, String sortBy, Order sortOrder) {
Preconditions.checkArgument(offset >=0, "Index offset should be greater than or equals to 0");
Preconditions.checkArgument(limit >=0, "Index limit should be greater than or equals to 0");
Iterator<JanusGraphIndexQuery.Result<JanusGraphVertex>> results = query
.orderBy(sortBy, sortOrder)
.offset(offset)
.limit(limit)
.vertices().iterator();
Function<JanusGraphIndexQuery.Result<JanusGraphVertex>, Result<AtlasJanusVertex, AtlasJanusEdge>> function =
new Function<JanusGraphIndexQuery.Result<JanusGraphVertex>, Result<AtlasJanusVertex, AtlasJanusEdge>>() {
@Override
public Result<AtlasJanusVertex, AtlasJanusEdge> apply(JanusGraphIndexQuery.Result<JanusGraphVertex> source) {
return new ResultImpl(source);
}
};
return Iterators.transform(results, function);
}
@Override
public Long vertexTotals() { public Long vertexTotals() {
return query.vertexTotals(); return query.vertexTotals();
} }
......
...@@ -609,12 +609,7 @@ public class Solr6Index implements IndexProvider { ...@@ -609,12 +609,7 @@ public class Solr6Index implements IndexProvider {
final String queryFilter = buildQueryFilter(query.getCondition(), information.get(collection)); final String queryFilter = buildQueryFilter(query.getCondition(), information.get(collection));
solrQuery.addFilterQuery(queryFilter); solrQuery.addFilterQuery(queryFilter);
if (!query.getOrder().isEmpty()) { if (!query.getOrder().isEmpty()) {
final List<IndexQuery.OrderEntry> orders = query.getOrder(); addOrderToQuery(solrQuery, query.getOrder());
for (final IndexQuery.OrderEntry order1 : orders) {
final String item = order1.getKey();
final SolrQuery.ORDER order = order1.getOrder() == Order.ASC ? SolrQuery.ORDER.asc : SolrQuery.ORDER.desc;
solrQuery.addSort(new SolrQuery.SortClause(item, order));
}
} }
solrQuery.setStart(0); solrQuery.setStart(0);
if (query.hasLimit()) { if (query.hasLimit()) {
...@@ -626,6 +621,14 @@ public class Solr6Index implements IndexProvider { ...@@ -626,6 +621,14 @@ public class Solr6Index implements IndexProvider {
doc -> doc.getFieldValue(keyIdField).toString()); doc -> doc.getFieldValue(keyIdField).toString());
} }
private void addOrderToQuery(SolrQuery solrQuery, List<IndexQuery.OrderEntry> orders) {
for (final IndexQuery.OrderEntry order1 : orders) {
final String item = order1.getKey();
final SolrQuery.ORDER order = order1.getOrder() == Order.ASC ? SolrQuery.ORDER.asc : SolrQuery.ORDER.desc;
solrQuery.addSort(new SolrQuery.SortClause(item, order));
}
}
private <E> Stream<E> executeQuery(Integer limit, int offset, String collection, SolrQuery solrQuery, private <E> Stream<E> executeQuery(Integer limit, int offset, String collection, SolrQuery solrQuery,
Function<SolrDocument, E> function) throws PermanentBackendException { Function<SolrDocument, E> function) throws PermanentBackendException {
try { try {
...@@ -654,6 +657,9 @@ public class Solr6Index implements IndexProvider { ...@@ -654,6 +657,9 @@ public class Solr6Index implements IndexProvider {
} else { } else {
solrQuery.setRows(batchSize); solrQuery.setRows(batchSize);
} }
if (!query.getOrders().isEmpty()) {
addOrderToQuery(solrQuery, query.getOrders());
}
for(final Parameter parameter: query.getParameters()) { for(final Parameter parameter: query.getParameters()) {
if (parameter.value() instanceof String[]) { if (parameter.value() instanceof String[]) {
......
...@@ -23,6 +23,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; ...@@ -23,6 +23,7 @@ import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonValue; import com.fasterxml.jackson.annotation.JsonValue;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.apache.atlas.SortOrder;
import java.io.Serializable; import java.io.Serializable;
import java.util.HashMap; import java.util.HashMap;
...@@ -44,6 +45,7 @@ public class SearchParameters implements Serializable { ...@@ -44,6 +45,7 @@ public class SearchParameters implements Serializable {
private String typeName; private String typeName;
private String classification; private String classification;
private String termName; private String termName;
private String sortBy;
private boolean excludeDeletedEntities; private boolean excludeDeletedEntities;
private boolean includeClassificationAttributes; private boolean includeClassificationAttributes;
private boolean includeSubTypes = true; private boolean includeSubTypes = true;
...@@ -54,6 +56,7 @@ public class SearchParameters implements Serializable { ...@@ -54,6 +56,7 @@ public class SearchParameters implements Serializable {
private FilterCriteria entityFilters; private FilterCriteria entityFilters;
private FilterCriteria tagFilters; private FilterCriteria tagFilters;
private Set<String> attributes; private Set<String> attributes;
private SortOrder sortOrder;
public static final String WILDCARD_CLASSIFICATIONS = "*"; public static final String WILDCARD_CLASSIFICATIONS = "*";
public static final String ALL_CLASSIFICATIONS = "_CLASSIFIED"; public static final String ALL_CLASSIFICATIONS = "_CLASSIFIED";
...@@ -258,6 +261,30 @@ public class SearchParameters implements Serializable { ...@@ -258,6 +261,30 @@ public class SearchParameters implements Serializable {
this.attributes = attributes; this.attributes = attributes;
} }
/**
* @return Attribute on which to sort the results
*/
public String getSortBy() { return sortBy; }
/**
* Sort the results based on sortBy attribute
* @param sortBy Attribute on which to sort the results
*/
public void setSortBy(String sortBy) { this.sortBy = sortBy; }
/**
* @return Sorting order of the results
*/
public SortOrder getSortOrder() {
return sortOrder;
}
/**
* Sorting order to sort the results
* @param sortOrder ASCENDING vs DESCENDING
*/
public void setSortOrder(SortOrder sortOrder) { this.sortOrder = sortOrder; }
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
...@@ -273,13 +300,15 @@ public class SearchParameters implements Serializable { ...@@ -273,13 +300,15 @@ public class SearchParameters implements Serializable {
Objects.equals(termName, that.termName) && Objects.equals(termName, that.termName) &&
Objects.equals(entityFilters, that.entityFilters) && Objects.equals(entityFilters, that.entityFilters) &&
Objects.equals(tagFilters, that.tagFilters) && Objects.equals(tagFilters, that.tagFilters) &&
Objects.equals(attributes, that.attributes); Objects.equals(attributes, that.attributes) &&
Objects.equals(sortBy, that.sortBy) &&
Objects.equals(sortOrder, that.sortOrder);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(query, typeName, classification, termName, excludeDeletedEntities, includeClassificationAttributes, return Objects.hash(query, typeName, classification, termName, excludeDeletedEntities, includeClassificationAttributes,
limit, offset, entityFilters, tagFilters, attributes); limit, offset, entityFilters, tagFilters, attributes, sortBy, sortOrder);
} }
public StringBuilder toString(StringBuilder sb) { public StringBuilder toString(StringBuilder sb) {
...@@ -299,6 +328,8 @@ public class SearchParameters implements Serializable { ...@@ -299,6 +328,8 @@ public class SearchParameters implements Serializable {
sb.append(", entityFilters=").append(entityFilters); sb.append(", entityFilters=").append(entityFilters);
sb.append(", tagFilters=").append(tagFilters); sb.append(", tagFilters=").append(tagFilters);
sb.append(", attributes=").append(attributes); sb.append(", attributes=").append(attributes);
sb.append(", sortBy=").append(sortBy).append('\'');
sb.append(", sortOrder=").append(sortOrder).append('\'');
sb.append('}'); sb.append('}');
return sb; return sb;
...@@ -461,5 +492,6 @@ public class SearchParameters implements Serializable { ...@@ -461,5 +492,6 @@ public class SearchParameters implements Serializable {
public String toString() { public String toString() {
return getSymbol(); return getSymbol();
} }
} }
} }
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
*/ */
package org.apache.atlas.discovery; package org.apache.atlas.discovery;
import org.apache.atlas.SortOrder;
import org.apache.atlas.exception.AtlasBaseException; import org.apache.atlas.exception.AtlasBaseException;
import org.apache.atlas.model.discovery.SearchParameters.FilterCriteria; import org.apache.atlas.model.discovery.SearchParameters.FilterCriteria;
import org.apache.atlas.model.instance.AtlasEntity; import org.apache.atlas.model.instance.AtlasEntity;
...@@ -58,6 +59,8 @@ import static org.apache.atlas.repository.Constants.PROPAGATED_TRAIT_NAMES_PROPE ...@@ -58,6 +59,8 @@ import static org.apache.atlas.repository.Constants.PROPAGATED_TRAIT_NAMES_PROPE
import static org.apache.atlas.repository.Constants.TRAIT_NAMES_PROPERTY_KEY; import static org.apache.atlas.repository.Constants.TRAIT_NAMES_PROPERTY_KEY;
import static org.apache.atlas.repository.graphdb.AtlasGraphQuery.ComparisionOperator.EQUAL; 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.ComparisionOperator.NOT_EQUAL;
import static org.apache.atlas.repository.graphdb.AtlasGraphQuery.SortOrder.ASC;
import static org.apache.atlas.repository.graphdb.AtlasGraphQuery.SortOrder.DESC;
public class ClassificationSearchProcessor extends SearchProcessor { public class ClassificationSearchProcessor extends SearchProcessor {
...@@ -72,7 +75,6 @@ public class ClassificationSearchProcessor extends SearchProcessor { ...@@ -72,7 +75,6 @@ public class ClassificationSearchProcessor extends SearchProcessor {
private final String gremlinTagFilterQuery; private final String gremlinTagFilterQuery;
private final Map<String, Object> gremlinQueryBindings; private final Map<String, Object> gremlinQueryBindings;
public ClassificationSearchProcessor(SearchContext context) { public ClassificationSearchProcessor(SearchContext context) {
super(context); super(context);
...@@ -83,6 +85,8 @@ public class ClassificationSearchProcessor extends SearchProcessor { ...@@ -83,6 +85,8 @@ public class ClassificationSearchProcessor extends SearchProcessor {
final Set<String> allAttributes = new HashSet<>(); final Set<String> allAttributes = new HashSet<>();
final Set<String> typeAndSubTypes = context.getClassificationTypes(); final Set<String> typeAndSubTypes = context.getClassificationTypes();
final String typeAndSubTypesQryStr = context.getClassificationTypesQryStr(); final String typeAndSubTypesQryStr = context.getClassificationTypesQryStr();
final String sortBy = context.getSearchParameters().getSortBy();
final SortOrder sortOrder = context.getSearchParameters().getSortOrder();
processSearchAttributes(classificationType, filterCriteria, indexAttributes, graphAttributes, allAttributes); processSearchAttributes(classificationType, filterCriteria, indexAttributes, graphAttributes, allAttributes);
...@@ -187,6 +191,11 @@ public class ClassificationSearchProcessor extends SearchProcessor { ...@@ -187,6 +191,11 @@ public class ClassificationSearchProcessor extends SearchProcessor {
entityPredicateTraitNames = PredicateUtils.andPredicate(entityPredicateTraitNames, activePredicate); entityPredicateTraitNames = PredicateUtils.andPredicate(entityPredicateTraitNames, activePredicate);
} }
if (sortBy != null && !sortBy.isEmpty()) {
AtlasGraphQuery.SortOrder qrySortOrder = sortOrder == SortOrder.ASCENDING ? ASC : DESC;
entityGraphQueryTraitNames.orderBy(sortBy, qrySortOrder);
}
gremlinTagFilterQuery = null; gremlinTagFilterQuery = null;
gremlinQueryBindings = null; gremlinQueryBindings = null;
} }
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
*/ */
package org.apache.atlas.discovery; package org.apache.atlas.discovery;
import org.apache.atlas.SortOrder;
import org.apache.atlas.model.discovery.SearchParameters.FilterCriteria; import org.apache.atlas.model.discovery.SearchParameters.FilterCriteria;
import org.apache.atlas.repository.Constants; import org.apache.atlas.repository.Constants;
import org.apache.atlas.repository.graphdb.AtlasGraphQuery; import org.apache.atlas.repository.graphdb.AtlasGraphQuery;
...@@ -24,11 +25,14 @@ import org.apache.atlas.repository.graphdb.AtlasIndexQuery; ...@@ -24,11 +25,14 @@ import org.apache.atlas.repository.graphdb.AtlasIndexQuery;
import org.apache.atlas.repository.graphdb.AtlasVertex; import org.apache.atlas.repository.graphdb.AtlasVertex;
import org.apache.atlas.type.AtlasClassificationType; import org.apache.atlas.type.AtlasClassificationType;
import org.apache.atlas.type.AtlasEntityType; import org.apache.atlas.type.AtlasEntityType;
import org.apache.atlas.type.AtlasStructType;
import org.apache.atlas.util.SearchPredicateUtil; import org.apache.atlas.util.SearchPredicateUtil;
import org.apache.atlas.utils.AtlasPerfTracer; import org.apache.atlas.utils.AtlasPerfTracer;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate; import org.apache.commons.collections.Predicate;
import org.apache.commons.collections.PredicateUtils; 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.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
...@@ -39,6 +43,7 @@ import java.util.LinkedList; ...@@ -39,6 +43,7 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import static org.apache.atlas.SortOrder.ASCENDING;
import static org.apache.atlas.discovery.SearchContext.MATCH_ALL_CLASSIFIED; 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_NOT_CLASSIFIED;
import static org.apache.atlas.discovery.SearchContext.MATCH_ALL_WILDCARD_CLASSIFICATION; import static org.apache.atlas.discovery.SearchContext.MATCH_ALL_WILDCARD_CLASSIFICATION;
...@@ -46,6 +51,8 @@ import static org.apache.atlas.repository.Constants.PROPAGATED_TRAIT_NAMES_PROPE ...@@ -46,6 +51,8 @@ import static org.apache.atlas.repository.Constants.PROPAGATED_TRAIT_NAMES_PROPE
import static org.apache.atlas.repository.Constants.TRAIT_NAMES_PROPERTY_KEY; import static org.apache.atlas.repository.Constants.TRAIT_NAMES_PROPERTY_KEY;
import static org.apache.atlas.repository.graphdb.AtlasGraphQuery.ComparisionOperator.EQUAL; 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.ComparisionOperator.NOT_EQUAL;
import static org.apache.atlas.repository.graphdb.AtlasGraphQuery.SortOrder.ASC;
import static org.apache.atlas.repository.graphdb.AtlasGraphQuery.SortOrder.DESC;
public class EntitySearchProcessor extends SearchProcessor { public class EntitySearchProcessor extends SearchProcessor {
private static final Logger LOG = LoggerFactory.getLogger(EntitySearchProcessor.class); private static final Logger LOG = LoggerFactory.getLogger(EntitySearchProcessor.class);
...@@ -66,6 +73,8 @@ public class EntitySearchProcessor extends SearchProcessor { ...@@ -66,6 +73,8 @@ public class EntitySearchProcessor extends SearchProcessor {
final Set<String> allAttributes = new HashSet<>(); final Set<String> allAttributes = new HashSet<>();
final Set<String> typeAndSubTypes = context.getEntityTypes(); final Set<String> typeAndSubTypes = context.getEntityTypes();
final String typeAndSubTypesQryStr = context.getEntityTypesQryStr(); final String typeAndSubTypesQryStr = context.getEntityTypesQryStr();
final String sortBy = context.getSearchParameters().getSortBy();
final SortOrder sortOrder = context.getSearchParameters().getSortOrder();
final AtlasClassificationType classificationType = context.getClassificationType(); final AtlasClassificationType classificationType = context.getClassificationType();
final Set<String> classificationTypeAndSubTypes = context.getClassificationTypes(); final Set<String> classificationTypeAndSubTypes = context.getClassificationTypes();
...@@ -190,12 +199,18 @@ public class EntitySearchProcessor extends SearchProcessor { ...@@ -190,12 +199,18 @@ public class EntitySearchProcessor extends SearchProcessor {
graphQueryPredicate = activePredicate; graphQueryPredicate = activePredicate;
} }
} }
if (sortBy != null && !sortBy.isEmpty()) {
AtlasGraphQuery.SortOrder qrySortOrder = sortOrder == SortOrder.ASCENDING ? ASC : DESC;
graphQuery.orderBy(sortBy, qrySortOrder);
}
} else { } else {
graphQuery = null; graphQuery = null;
graphQueryPredicate = null; graphQueryPredicate = null;
} }
// Prepare the graph query and in-memory filter for the filtering phase // Prepare the graph query and in-memory filter for the filtering phase
filterGraphQueryPredicate = typeNamePredicate; filterGraphQueryPredicate = typeNamePredicate;
...@@ -213,6 +228,7 @@ public class EntitySearchProcessor extends SearchProcessor { ...@@ -213,6 +228,7 @@ public class EntitySearchProcessor extends SearchProcessor {
if (context.getSearchParameters().getExcludeDeletedEntities()) { if (context.getSearchParameters().getExcludeDeletedEntities()) {
filterGraphQueryPredicate = PredicateUtils.andPredicate(filterGraphQueryPredicate, activePredicate); filterGraphQueryPredicate = PredicateUtils.andPredicate(filterGraphQueryPredicate, activePredicate);
} }
} }
@Override @Override
...@@ -241,6 +257,19 @@ public class EntitySearchProcessor extends SearchProcessor { ...@@ -241,6 +257,19 @@ public class EntitySearchProcessor extends SearchProcessor {
final List<AtlasVertex> entityVertices = new ArrayList<>(); final List<AtlasVertex> entityVertices = new ArrayList<>();
SortOrder sortOrder = context.getSearchParameters().getSortOrder();
String sortBy = context.getSearchParameters().getSortBy();
final AtlasEntityType entityType = context.getEntityType();
AtlasStructType.AtlasAttribute sortByAttribute = entityType.getAttribute(sortBy);
if (sortByAttribute == null) {
sortBy = null;
} else {
sortBy = sortByAttribute.getVertexPropertyName();
}
if (sortOrder == null) { sortOrder = ASCENDING; }
for (; ret.size() < limit; qryOffset += limit) { for (; ret.size() < limit; qryOffset += limit) {
entityVertices.clear(); entityVertices.clear();
...@@ -253,7 +282,14 @@ public class EntitySearchProcessor extends SearchProcessor { ...@@ -253,7 +282,14 @@ public class EntitySearchProcessor extends SearchProcessor {
final boolean isLastResultPage; final boolean isLastResultPage;
if (indexQuery != null) { if (indexQuery != null) {
Iterator<AtlasIndexQuery.Result> idxQueryResult = indexQuery.vertices(qryOffset, limit); Iterator<AtlasIndexQuery.Result> idxQueryResult;
if (StringUtils.isEmpty(sortBy)) {
idxQueryResult = indexQuery.vertices(qryOffset, limit);
} else {
Order qrySortOrder = sortOrder == SortOrder.ASCENDING ? Order.asc : Order.desc;
idxQueryResult = indexQuery.vertices(qryOffset, limit, sortBy, qrySortOrder);
}
getVerticesFromIndexQueryResult(idxQueryResult, entityVertices); getVerticesFromIndexQueryResult(idxQueryResult, entityVertices);
......
...@@ -106,6 +106,9 @@ public class SearchContext { ...@@ -106,6 +106,9 @@ public class SearchContext {
// Invalid attributes will raise an exception with 400 error code // Invalid attributes will raise an exception with 400 error code
validateAttributes(entityType, searchParameters.getEntityFilters()); validateAttributes(entityType, searchParameters.getEntityFilters());
// Invalid attribute will raise an exception with 400 error code
validateAttributes(entityType, searchParameters.getSortBy());
// Invalid attributes will raise an exception with 400 error code // Invalid attributes will raise an exception with 400 error code
validateAttributes(classificationType, searchParameters.getTagFilters()); validateAttributes(classificationType, searchParameters.getTagFilters());
...@@ -253,13 +256,18 @@ public class SearchContext { ...@@ -253,13 +256,18 @@ public class SearchContext {
} }
} else { } else {
String attributeName = filterCriteria.getAttributeName(); String attributeName = filterCriteria.getAttributeName();
validateAttributes(structType, attributeName);
}
}
}
private void validateAttributes(final AtlasStructType structType, final String... attributeNames) throws AtlasBaseException {
for (String attributeName : attributeNames) {
if (StringUtils.isNotEmpty(attributeName) && structType.getAttributeType(attributeName) == null) { if (StringUtils.isNotEmpty(attributeName) && structType.getAttributeType(attributeName) == null) {
throw new AtlasBaseException(AtlasErrorCode.UNKNOWN_ATTRIBUTE, attributeName, structType.getTypeName()); throw new AtlasBaseException(AtlasErrorCode.UNKNOWN_ATTRIBUTE, attributeName, structType.getTypeName());
} }
} }
} }
}
private boolean hasAttributeFilter(FilterCriteria filterCriteria) { private boolean hasAttributeFilter(FilterCriteria filterCriteria) {
return filterCriteria != null && return filterCriteria != null &&
......
...@@ -188,11 +188,14 @@ public class DiscoveryREST { ...@@ -188,11 +188,14 @@ public class DiscoveryREST {
public AtlasSearchResult searchUsingBasic(@QueryParam("query") String query, public AtlasSearchResult searchUsingBasic(@QueryParam("query") String query,
@QueryParam("typeName") String typeName, @QueryParam("typeName") String typeName,
@QueryParam("classification") String classification, @QueryParam("classification") String classification,
@QueryParam("sortBy") String sortByAttribute,
@QueryParam("sortOrder") SortOrder sortOrder,
@QueryParam("excludeDeletedEntities") boolean excludeDeletedEntities, @QueryParam("excludeDeletedEntities") boolean excludeDeletedEntities,
@QueryParam("limit") int limit, @QueryParam("limit") int limit,
@QueryParam("offset") int offset) throws AtlasBaseException { @QueryParam("offset") int offset) throws AtlasBaseException {
Servlets.validateQueryParamLength("typeName", typeName); Servlets.validateQueryParamLength("typeName", typeName);
Servlets.validateQueryParamLength("classification", classification); Servlets.validateQueryParamLength("classification", classification);
Servlets.validateQueryParamLength("sortBy", sortByAttribute);
if (StringUtils.isNotEmpty(query) && query.length() > maxFullTextQueryLength) { if (StringUtils.isNotEmpty(query) && query.length() > maxFullTextQueryLength) {
throw new AtlasBaseException(AtlasErrorCode.INVALID_QUERY_LENGTH, Constants.MAX_FULLTEXT_QUERY_STR_LENGTH); throw new AtlasBaseException(AtlasErrorCode.INVALID_QUERY_LENGTH, Constants.MAX_FULLTEXT_QUERY_STR_LENGTH);
} }
...@@ -212,6 +215,8 @@ public class DiscoveryREST { ...@@ -212,6 +215,8 @@ public class DiscoveryREST {
searchParameters.setExcludeDeletedEntities(excludeDeletedEntities); searchParameters.setExcludeDeletedEntities(excludeDeletedEntities);
searchParameters.setLimit(limit); searchParameters.setLimit(limit);
searchParameters.setOffset(offset); searchParameters.setOffset(offset);
searchParameters.setSortBy(sortByAttribute);
searchParameters.setSortOrder(sortOrder);
return discoveryService.searchWithParameters(searchParameters); return discoveryService.searchWithParameters(searchParameters);
} finally { } finally {
...@@ -690,6 +695,7 @@ public class DiscoveryREST { ...@@ -690,6 +695,7 @@ public class DiscoveryREST {
if (parameters != null) { if (parameters != null) {
Servlets.validateQueryParamLength("typeName", parameters.getTypeName()); Servlets.validateQueryParamLength("typeName", parameters.getTypeName());
Servlets.validateQueryParamLength("classification", parameters.getClassification()); Servlets.validateQueryParamLength("classification", parameters.getClassification());
Servlets.validateQueryParamLength("sortBy", parameters.getSortBy());
if (StringUtils.isNotEmpty(parameters.getQuery()) && parameters.getQuery().length() > maxFullTextQueryLength) { if (StringUtils.isNotEmpty(parameters.getQuery()) && parameters.getQuery().length() > maxFullTextQueryLength) {
throw new AtlasBaseException(AtlasErrorCode.INVALID_QUERY_LENGTH, Constants.MAX_FULLTEXT_QUERY_STR_LENGTH); throw new AtlasBaseException(AtlasErrorCode.INVALID_QUERY_LENGTH, Constants.MAX_FULLTEXT_QUERY_STR_LENGTH);
} }
......
...@@ -129,6 +129,12 @@ public class BasicSearchIT extends BaseResourceIT { ...@@ -129,6 +129,12 @@ public class BasicSearchIT extends BaseResourceIT {
assertNotNull(searchResult.getEntities()); assertNotNull(searchResult.getEntities());
assertEquals(searchResult.getEntities().size(), testExpectation.expectedCount); assertEquals(searchResult.getEntities().size(), testExpectation.expectedCount);
} }
if (testExpectation.searchParameters.getSortBy() != null && !testExpectation.searchParameters.getSortBy().isEmpty()) {
assertNotNull(searchResult.getEntities());
assertEquals(searchResult.getEntities().get(0).getAttribute("name"),
"testtable_3");
}
} }
} catch (IOException | AtlasServiceException e) { } catch (IOException | AtlasServiceException e) {
fail(e.getMessage()); fail(e.getMessage());
......
...@@ -21,6 +21,29 @@ ...@@ -21,6 +21,29 @@
"expectedCount": 3 "expectedCount": 3
}, },
{ {
"testDescription": "Asset.name contains testtable order by name descending",
"searchParameters": {
"typeName": "hive_table",
"excludeDeletedEntities": true,
"classification": "",
"query": "",
"limit": 25,
"offset": 0,
"sortBy": "name",
"sortOrder": "DESCENDING",
"entityFilters": {
"attributeName": "name",
"operator": "contains",
"attributeValue": "testtable"
},
"tagFilters": null,
"attributes": [
""
]
},
"expectedCount": 3
},
{
"testDescription": "hive_column.name contains 30", "testDescription": "hive_column.name contains 30",
"searchParameters": { "searchParameters": {
"typeName": "hive_column", "typeName": "hive_column",
......
...@@ -12,5 +12,22 @@ ...@@ -12,5 +12,22 @@
"classification":"fooTag" "classification":"fooTag"
}, },
"expectedCount": 1 "expectedCount": 1
},
{
"testDescription": "Search for exact Tag name order by",
"searchParameters": {
"entityFilters":null,
"tagFilters":null,
"attributes":null,
"query":null,
"excludeDeletedEntities":true,
"limit":25,
"typeName":null,
"sortBy": "name",
"sortOrder": "DESCENDING",
"classification":"fooTag"
},
"expectedCount": 1
} }
] ]
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment