You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@atlas.apache.org by ma...@apache.org on 2018/02/14 23:57:36 UTC

atlas git commit: ATLAS-2447: DSL improvement in handling of select clause

Repository: atlas
Updated Branches:
  refs/heads/master 3ec37cae8 -> a2ccdf12c


ATLAS-2447: DSL improvement in handling of select clause

Signed-off-by: Madhan Neethiraj <ma...@apache.org>


Project: http://git-wip-us.apache.org/repos/asf/atlas/repo
Commit: http://git-wip-us.apache.org/repos/asf/atlas/commit/a2ccdf12
Tree: http://git-wip-us.apache.org/repos/asf/atlas/tree/a2ccdf12
Diff: http://git-wip-us.apache.org/repos/asf/atlas/diff/a2ccdf12

Branch: refs/heads/master
Commit: a2ccdf12c2b901744aa8b54fe08654d72490b23c
Parents: 3ec37ca
Author: Ashutosh Mestry <am...@hortonworks.com>
Authored: Wed Feb 14 15:45:15 2018 -0800
Committer: Madhan Neethiraj <ma...@apache.org>
Committed: Wed Feb 14 15:45:15 2018 -0800

----------------------------------------------------------------------
 .../org/apache/atlas/query/GremlinClause.java   |   4 +-
 .../atlas/query/GremlinQueryComposer.java       |  13 +-
 .../org/apache/atlas/query/DSLQueriesTest.java  |  14 ++-
 .../atlas/query/GremlinQueryComposerTest.java   | 126 +++++++++----------
 .../web/errors/AtlasBaseExceptionMapper.java    |   5 +
 5 files changed, 93 insertions(+), 69 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/atlas/blob/a2ccdf12/repository/src/main/java/org/apache/atlas/query/GremlinClause.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/query/GremlinClause.java b/repository/src/main/java/org/apache/atlas/query/GremlinClause.java
index c770f77..3841103 100644
--- a/repository/src/main/java/org/apache/atlas/query/GremlinClause.java
+++ b/repository/src/main/java/org/apache/atlas/query/GremlinClause.java
@@ -36,11 +36,11 @@ enum GremlinClause {
     AND("and(%s)"),
     NESTED_START("__"),
     NESTED_HAS_OPERATOR("has('%s', %s(%s))"),
-    LIMIT("limit(local, %s).limit(%s)"),
+    LIMIT("limit(%s)"),
     ORDER_BY("order().by('%s')"),
     ORDER_BY_DESC("order().by('%s', decr)"),
     OUT("out('%s')"),
-    RANGE("range(local, %s, %s + %s).range(%s, %s + %s)"),
+    RANGE("range(%s, %s + %s)"),
     SELECT("select('%s')"),
     TO_LIST("toList()"),
     TEXT_CONTAINS("has('%s', org.janusgraph.core.attribute.Text.textRegex(%s))"),

http://git-wip-us.apache.org/repos/asf/atlas/blob/a2ccdf12/repository/src/main/java/org/apache/atlas/query/GremlinQueryComposer.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/query/GremlinQueryComposer.java b/repository/src/main/java/org/apache/atlas/query/GremlinQueryComposer.java
index 92029f5..9a66636 100644
--- a/repository/src/main/java/org/apache/atlas/query/GremlinQueryComposer.java
+++ b/repository/src/main/java/org/apache/atlas/query/GremlinQueryComposer.java
@@ -167,9 +167,7 @@ public class GremlinQueryComposer {
 
         if (lhsI.isDate()) {
             rhs = parseDate(rhs);
-        }
-
-        if (lhsI.isNumeric()) {
+        } else if (lhsI.isNumeric()) {
             rhs = parseNumber(rhs);
         }
 
@@ -492,6 +490,15 @@ public class GremlinQueryComposer {
         if (isNestedQuery)
             return;
 
+        // Need de-duping at the end so that correct results are fetched
+        if (queryClauses.size() > 2) {
+            // QueryClauses should've something more that just g.V() (hence 2)
+            add(GremlinClause.DEDUP);
+            // Range and limit must be present after the de-duping construct
+            moveToLast(GremlinClause.RANGE);
+            moveToLast(GremlinClause.LIMIT);
+        }
+
         if (!queryMetadata.hasLimitOffset()) {
             addDefaultLimit();
         }

http://git-wip-us.apache.org/repos/asf/atlas/blob/a2ccdf12/repository/src/test/java/org/apache/atlas/query/DSLQueriesTest.java
----------------------------------------------------------------------
diff --git a/repository/src/test/java/org/apache/atlas/query/DSLQueriesTest.java b/repository/src/test/java/org/apache/atlas/query/DSLQueriesTest.java
index 82b7381..fedb8a7 100644
--- a/repository/src/test/java/org/apache/atlas/query/DSLQueriesTest.java
+++ b/repository/src/test/java/org/apache/atlas/query/DSLQueriesTest.java
@@ -44,6 +44,7 @@ import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotNull;
 import static org.testng.Assert.assertNull;
 import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
 
 @Guice(modules = TestModules.TestOnlyModule.class)
 public class DSLQueriesTest extends BasicTestSetup {
@@ -176,7 +177,8 @@ public class DSLQueriesTest extends BasicTestSetup {
                 {"Person where (age < 50)", 3},
                 {"Person where (age <= 35)", 2},
                 {"Person where (age =  35)", 0},
-                {"Person where (age != 35)", 4}
+                {"Person where (age != 35)", 4},
+                {"Person where (approximationOfPi > -3.4028235e+38)", 4},
         };
     }
 
@@ -606,9 +608,19 @@ public class DSLQueriesTest extends BasicTestSetup {
                 {"hive_table select owner, columns"}, // Can't select a mix of immediate attribute and referred entity
                 {"hive_table select owner, db.name"}, // Same as above
                 {"hive_order"}, // From src should be an Entity or Classification
+                {"Person where (age > -3.4028235e+38)"} // comparing float with BigDecimal
         };
     }
 
+    @Test
+    public void testQuery() {
+        try {
+            discoveryService.searchUsingDslQuery("hive_table select db", DEFAULT_LIMIT, 0);
+        } catch (AtlasBaseException e) {
+            fail("Should've been a success");
+        }
+    }
+
     @Test(dataProvider = "errorQueriesProvider", expectedExceptions = { AtlasBaseException.class })
     public void errorQueries(String query) throws AtlasBaseException {
         LOG.debug(query);

http://git-wip-us.apache.org/repos/asf/atlas/blob/a2ccdf12/repository/src/test/java/org/apache/atlas/query/GremlinQueryComposerTest.java
----------------------------------------------------------------------
diff --git a/repository/src/test/java/org/apache/atlas/query/GremlinQueryComposerTest.java b/repository/src/test/java/org/apache/atlas/query/GremlinQueryComposerTest.java
index 85addc2..9c8aac5 100644
--- a/repository/src/test/java/org/apache/atlas/query/GremlinQueryComposerTest.java
+++ b/repository/src/test/java/org/apache/atlas/query/GremlinQueryComposerTest.java
@@ -36,13 +36,13 @@ import static org.testng.Assert.fail;
 public class GremlinQueryComposerTest {
     @Test
     public void classification() {
-        String expected = "g.V().has('__traitNames', within('PII')).limit(local, 25).limit(25).toList()";
+        String expected = "g.V().has('__traitNames', within('PII')).dedup().limit(25).toList()";
         verify("PII", expected);
     }
 
     @Test()
     public void dimension() {
-        String expected = "g.V().has('__typeName', 'Table').has('__traitNames', within('Dimension')).limit(local, 25).limit(25).toList()";
+        String expected = "g.V().has('__typeName', 'Table').has('__traitNames', within('Dimension')).dedup().limit(25).toList()";
         verify("Table isa Dimension", expected);
         verify("Table is Dimension", expected);
         verify("Table where Table is Dimension", expected);
@@ -50,59 +50,59 @@ public class GremlinQueryComposerTest {
 
     @Test
     public void fromDB() {
-        String expected10 = "g.V().has('__typeName', 'DB').limit(local, 10).limit(10).toList()";
-        verify("from DB", "g.V().has('__typeName', 'DB').limit(local, 25).limit(25).toList()");
+        String expected10 = "g.V().has('__typeName', 'DB').dedup().limit(10).toList()";
+        verify("from DB", "g.V().has('__typeName', 'DB').dedup().limit(25).toList()");
         verify("from DB limit 10", expected10);
         verify("DB limit 10", expected10);
     }
 
     @Test
     public void DBHasName() {
-        String expected = "g.V().has('__typeName', 'DB').has('DB.name').limit(local, 25).limit(25).toList()";
+        String expected = "g.V().has('__typeName', 'DB').has('DB.name').dedup().limit(25).toList()";
         verify("DB has name", expected);
         verify("DB where DB has name", expected);
     }
 
     @Test
     public void DBasD() {
-        verify("DB as d", "g.V().has('__typeName', 'DB').as('d').limit(local, 25).limit(25).toList()");
+        verify("DB as d", "g.V().has('__typeName', 'DB').as('d').dedup().limit(25).toList()");
     }
 
     @Test
     public void DBasDSelect() {
         String expected = "def f(r){ t=[['d.name','d.owner']];  r.each({t.add([it.value('DB.name'),it.value('DB.owner')])}); t.unique(); }; " +
                                   "f(g.V().has('__typeName', 'DB').as('d').has('DB.name').has('DB.owner')";
-        verify("DB as d select d.name, d.owner", expected + ".limit(local, 25).limit(25).toList())");
-        verify("DB as d select d.name, d.owner limit 10", expected + ".limit(local, 10).limit(10).toList())");
-        verify("DB as d select d","def f(r){ r }; f(g.V().has('__typeName', 'DB').as('d').limit(local, 25).limit(25).toList())");
+        verify("DB as d select d.name, d.owner", expected + ".dedup().limit(25).toList())");
+        verify("DB as d select d.name, d.owner limit 10", expected + ".dedup().limit(10).toList())");
+        verify("DB as d select d","def f(r){ r }; f(g.V().has('__typeName', 'DB').as('d').dedup().limit(25).toList())");
     }
 
     @Test
     public void tableSelectColumns() {
-        String exMain = "g.V().has('__typeName', 'Table').out('__Table.columns').limit(local, 10).limit(10).toList()";
+        String exMain = "g.V().has('__typeName', 'Table').out('__Table.columns').dedup().limit(10).toList()";
         String exSel = "def f(r){ r }";
         String exSel1 = "def f(r){ t=[['db.name']];  r.each({t.add([it.value('DB.name')])}); t.unique(); }";
         verify("Table select columns limit 10", getExpected(exSel, exMain));
 
-        String exMain2 = "g.V().has('__typeName', 'Table').out('__Table.db').limit(local, 25).limit(25).toList()";
+        String exMain2 = "g.V().has('__typeName', 'Table').out('__Table.db').dedup().limit(25).toList()";
         verify("Table select db", getExpected(exSel, exMain2));
 
-        String exMain3 = "g.V().has('__typeName', 'Table').out('__Table.db').limit(local, 25).limit(25).toList()";
+        String exMain3 = "g.V().has('__typeName', 'Table').out('__Table.db').dedup().limit(25).toList()";
         verify("Table select db.name", getExpected(exSel1, exMain3));
 
     }
 
     @Test
     public void valueArray() {
-        verify("DB where owner = ['hdfs', 'anon']", "g.V().has('__typeName', 'DB').has('DB.owner', within('hdfs','anon')).limit(local, 25).limit(25).toList()");
-        verify("DB owner = ['hdfs', 'anon']", "g.V().has('__typeName', 'DB').has('DB.owner', within('hdfs','anon')).limit(local, 25).limit(25).toList()");
-        verify("hive_db as d owner = ['hdfs', 'anon']", "g.V().has('__typeName', 'hive_db').as('d').has('hive_db.owner', within('hdfs','anon')).limit(local, 25).limit(25).toList()");
+        verify("DB where owner = ['hdfs', 'anon']", "g.V().has('__typeName', 'DB').has('DB.owner', within('hdfs','anon')).dedup().limit(25).toList()");
+        verify("DB owner = ['hdfs', 'anon']", "g.V().has('__typeName', 'DB').has('DB.owner', within('hdfs','anon')).dedup().limit(25).toList()");
+        verify("hive_db as d owner = ['hdfs', 'anon']", "g.V().has('__typeName', 'hive_db').as('d').has('hive_db.owner', within('hdfs','anon')).dedup().limit(25).toList()");
     }
     @Test
     public void groupByMin() {
         verify("from DB groupby (owner) select min(name) orderby name limit 2",
                 "def f(l){ t=[['min(name)']]; l.get(0).each({k,r -> L:{ def min=r.min({it.value('DB.name')}).value('DB.name'); t.add([min]); } }); t; }; " +
-                        "f(g.V().has('__typeName', 'DB').group().by('DB.owner').toList())");
+                        "f(g.V().has('__typeName', 'DB').group().by('DB.owner').dedup().toList())");
     }
 
     @Test
@@ -111,28 +111,28 @@ public class GremlinQueryComposerTest {
                 "def f(l){ h=[['name','owner','clusterName']]; t=[]; " +
                         "l.get(0).each({k,r -> L:{  r.each({t.add([it.value('Table.name'),it.value('Table.owner'),it.value('Table.clusterName')])}) } }); " +
                         "h.plus(t.unique().sort{a,b -> a[0] <=> b[0]}); }; " +
-                        "f(g.V().has('__typeName', 'Table').has('Table.name').has('Table.owner').has('Table.clusterName').group().by('Table.owner').limit(local, 25).limit(25).toList())");
+                        "f(g.V().has('__typeName', 'Table').has('Table.name').has('Table.owner').has('Table.clusterName').group().by('Table.owner').dedup().limit(25).toList())");
     }
 
     @Test
     public void DBAsDSelectLimit() {
-        verify("from DB limit 5", "g.V().has('__typeName', 'DB').limit(local, 5).limit(5).toList()");
-        verify("from DB limit 5 offset 2", "g.V().has('__typeName', 'DB').range(local, 2, 2 + 5).range(2, 2 + 5).toList()");
+        verify("from DB limit 5", "g.V().has('__typeName', 'DB').dedup().limit(5).toList()");
+        verify("from DB limit 5 offset 2", "g.V().has('__typeName', 'DB').dedup().range(2, 2 + 5).toList()");
     }
 
     @Test
     public void DBOrderBy() {
-        String expected = "g.V().has('__typeName', 'DB').order().by('DB.name').limit(local, 25).limit(25).toList()";
+        String expected = "g.V().has('__typeName', 'DB').order().by('DB.name').dedup().limit(25).toList()";
         verify("DB orderby name", expected);
         verify("from DB orderby name", expected);
-        verify("from DB as d orderby d.owner limit 3", "g.V().has('__typeName', 'DB').as('d').order().by('DB.owner').limit(local, 3).limit(3).toList()");
-        verify("DB as d orderby d.owner limit 3", "g.V().has('__typeName', 'DB').as('d').order().by('DB.owner').limit(local, 3).limit(3).toList()");
+        verify("from DB as d orderby d.owner limit 3", "g.V().has('__typeName', 'DB').as('d').order().by('DB.owner').dedup().limit(3).toList()");
+        verify("DB as d orderby d.owner limit 3", "g.V().has('__typeName', 'DB').as('d').order().by('DB.owner').dedup().limit(3).toList()");
 
         String exSel = "def f(r){ t=[['d.name','d.owner']];  r.each({t.add([it.value('DB.name'),it.value('DB.owner')])}); t.unique(); }";
-        String exMain = "g.V().has('__typeName', 'DB').as('d').has('DB.name').has('DB.owner').order().by('DB.owner').limit(local, 25).limit(25).toList()";
+        String exMain = "g.V().has('__typeName', 'DB').as('d').has('DB.name').has('DB.owner').order().by('DB.owner').dedup().limit(25).toList()";
         verify("DB as d select d.name, d.owner orderby (d.owner) limit 25", getExpected(exSel, exMain));
 
-        String exMain2 = "g.V().has('__typeName', 'Table').and(__.has('Table.name', eq(\"sales_fact\")),__.has('Table.createTime', gt('1418265300000'))).order().by('Table.createTime').limit(local, 25).limit(25).toList()";
+        String exMain2 = "g.V().has('__typeName', 'Table').and(__.has('Table.name', eq(\"sales_fact\")),__.has('Table.createTime', gt('1418265300000'))).order().by('Table.createTime').dedup().limit(25).toList()";
         String exSel2 = "def f(r){ t=[['_col_0','_col_1']];  r.each({t.add([it.value('Table.name'),it.value('Table.createTime')])}); t.unique(); }";
         verify("Table where (name = \"sales_fact\" and createTime > \"2014-12-11T02:35:0.0Z\" ) select name as _col_0, createTime as _col_1 orderby _col_1",
                 getExpected(exSel2, exMain2));
@@ -140,51 +140,51 @@ public class GremlinQueryComposerTest {
 
     @Test
     public void fromDBOrderByNameDesc() {
-        verify("from DB orderby name DESC", "g.V().has('__typeName', 'DB').order().by('DB.name', decr).limit(local, 25).limit(25).toList()");
+        verify("from DB orderby name DESC", "g.V().has('__typeName', 'DB').order().by('DB.name', decr).dedup().limit(25).toList()");
     }
 
     @Test
     public void fromDBSelect() {
         String expected = "def f(r){ t=[['DB.name','DB.owner']];  r.each({t.add([it.value('DB.name'),it.value('DB.owner')])}); t.unique(); }; " +
-                                  "f(g.V().has('__typeName', 'DB').has('DB.name').has('DB.owner').limit(local, 25).limit(25).toList())";
+                                  "f(g.V().has('__typeName', 'DB').has('DB.name').has('DB.owner').dedup().limit(25).toList())";
         verify("from DB select DB.name, DB.owner", expected);
     }
 
     @Test
     public void fromDBGroupBy() {
-        verify("from DB groupby (DB.owner)", "g.V().has('__typeName', 'DB').group().by('DB.owner').limit(local, 25).limit(25).toList()");
+        verify("from DB groupby (DB.owner)", "g.V().has('__typeName', 'DB').group().by('DB.owner').dedup().limit(25).toList()");
     }
 
     @Test
     public void whereClauseTextContains() {
-        String exMain = "g.V().has('__typeName', 'DB').has('DB.name', eq(\"Reporting\")).has('DB.owner').limit(local, 25).limit(25).toList()";
+        String exMain = "g.V().has('__typeName', 'DB').has('DB.name', eq(\"Reporting\")).has('DB.owner').dedup().limit(25).toList()";
         String exSel = "def f(r){ t=[['name','owner']];  r.each({t.add([it.value('DB.name'),it.value('DB.owner')])}); t.unique(); }";
         verify("from DB where name = \"Reporting\" select name, owner", getExpected(exSel, exMain));
         verify("from DB where (name = \"Reporting\") select name, owner", getExpected(exSel, exMain));
         verify("Table where Asset.name like \"Tab*\"",
-                "g.V().has('__typeName', 'Table').has('Table.name', org.janusgraph.core.attribute.Text.textRegex(\"Tab.*\")).limit(local, 25).limit(25).toList()");
+                "g.V().has('__typeName', 'Table').has('Table.name', org.janusgraph.core.attribute.Text.textRegex(\"Tab.*\")).dedup().limit(25).toList()");
         verify("from Table where (db.name = \"Reporting\")",
-                "g.V().has('__typeName', 'Table').out('__Table.db').has('DB.name', eq(\"Reporting\")).dedup().in('__Table.db').limit(local, 25).limit(25).toList()");
+                "g.V().has('__typeName', 'Table').out('__Table.db').has('DB.name', eq(\"Reporting\")).dedup().in('__Table.db').dedup().limit(25).toList()");
     }
 
     @Test
     public void whereClauseWithAsTextContains() {
         String exSel = "def f(r){ t=[['t.name','t.owner']];  r.each({t.add([it.value('Table.name'),it.value('Table.owner')])}); t.unique(); }";
-        String exMain = "g.V().has('__typeName', 'Table').as('t').has('Table.name', eq(\"testtable_1\")).has('Table.owner').limit(local, 25).limit(25).toList()";
+        String exMain = "g.V().has('__typeName', 'Table').as('t').has('Table.name', eq(\"testtable_1\")).has('Table.owner').dedup().limit(25).toList()";
         verify("Table as t where t.name = \"testtable_1\" select t.name, t.owner", getExpected(exSel, exMain));
     }
 
     @Test
     public void whereClauseWithDateCompare() {
         String exSel = "def f(r){ t=[['t.name','t.owner']];  r.each({t.add([it.value('Table.name'),it.value('Table.owner')])}); t.unique(); }";
-        String exMain = "g.V().has('__typeName', 'Table').as('t').has('Table.createTime', eq('%s')).has('Table.name').has('Table.owner').limit(local, 25).limit(25).toList()";
+        String exMain = "g.V().has('__typeName', 'Table').as('t').has('Table.createTime', eq('%s')).has('Table.name').has('Table.owner').dedup().limit(25).toList()";
         verify("Table as t where t.createTime = \"2017-12-12T02:35:58.440Z\" select t.name, t.owner", getExpected(exSel, String.format(exMain, "1513046158440")));
         verify("Table as t where t.createTime = \"2017-12-12\" select t.name, t.owner", getExpected(exSel, String.format(exMain, "1513036800000")));
     }
 
     @Test
     public void subType() {
-        String exMain = "g.V().has('__typeName', within('Asset','Table')).has('Asset.name').has('Asset.owner').limit(local, 25).limit(25).toList()";
+        String exMain = "g.V().has('__typeName', within('Asset','Table')).has('Asset.name').has('Asset.owner').dedup().limit(25).toList()";
         String exSel = "def f(r){ t=[['name','owner']];  r.each({t.add([it.value('Asset.name'),it.value('Asset.owner')])}); t.unique(); }";
 
         verify("Asset select name, owner", getExpected(exSel, exMain));
@@ -193,24 +193,24 @@ public class GremlinQueryComposerTest {
     @Test
     public void countMinMax() {
         verify("from DB groupby (owner) select count()",
-                "def f(l){ t=[['count()']]; l.get(0).each({k,r -> L:{ def count=r.size(); t.add([count]); } }); t; }; f(g.V().has('__typeName', 'DB').group().by('DB.owner').toList())");
+                "def f(l){ t=[['count()']]; l.get(0).each({k,r -> L:{ def count=r.size(); t.add([count]); } }); t; }; f(g.V().has('__typeName', 'DB').group().by('DB.owner').dedup().toList())");
         verify("from DB groupby (owner) select max(name)",
-                "def f(l){ t=[['max(name)']]; l.get(0).each({k,r -> L:{ def max=r.max({it.value('DB.name')}).value('DB.name'); t.add([max]); } }); t; }; f(g.V().has('__typeName', 'DB').group().by('DB.owner').toList())");
+                "def f(l){ t=[['max(name)']]; l.get(0).each({k,r -> L:{ def max=r.max({it.value('DB.name')}).value('DB.name'); t.add([max]); } }); t; }; f(g.V().has('__typeName', 'DB').group().by('DB.owner').dedup().toList())");
         verify("from DB groupby (owner) select min(name)",
-                "def f(l){ t=[['min(name)']]; l.get(0).each({k,r -> L:{ def min=r.min({it.value('DB.name')}).value('DB.name'); t.add([min]); } }); t; }; f(g.V().has('__typeName', 'DB').group().by('DB.owner').toList())");
+                "def f(l){ t=[['min(name)']]; l.get(0).each({k,r -> L:{ def min=r.min({it.value('DB.name')}).value('DB.name'); t.add([min]); } }); t; }; f(g.V().has('__typeName', 'DB').group().by('DB.owner').dedup().toList())");
         verify("from Table select sum(createTime)",
-                "def f(r){ t=[['sum(createTime)']]; def sum=r.sum({it.value('Table.createTime')}); t.add([sum]); t;}; f(g.V().has('__typeName', 'Table').toList())");
+                "def f(r){ t=[['sum(createTime)']]; def sum=r.sum({it.value('Table.createTime')}); t.add([sum]); t;}; f(g.V().has('__typeName', 'Table').dedup().toList())");
     }
 
     @Test
     public void traitWithSpace() {
-        verify("`Log Data`", "g.V().has('__typeName', 'Log Data').limit(local, 25).limit(25).toList()");
+        verify("`Log Data`", "g.V().has('__typeName', 'Log Data').dedup().limit(25).toList()");
     }
 
     @Test
     public void whereClauseWithBooleanCondition() {
         String queryFormat = "Table as t where name ='Reporting' or t.isFile = %s";
-        String expectedFormat = "g.V().has('__typeName', 'Table').as('t').or(__.has('Table.name', eq('Reporting')),__.has('Table.isFile', eq(%s))).limit(local, 25).limit(25).toList()";
+        String expectedFormat = "g.V().has('__typeName', 'Table').as('t').or(__.has('Table.name', eq('Reporting')),__.has('Table.isFile', eq(%s))).dedup().limit(25).toList()";
         verify(String.format(queryFormat, "true"), String.format(expectedFormat, "true"));
         verify(String.format(queryFormat, "false"), String.format(expectedFormat, "false"));
         verify(String.format(queryFormat, "True"), String.format(expectedFormat, "True"));
@@ -221,23 +221,23 @@ public class GremlinQueryComposerTest {
     private Object[][] nestedQueriesSource() {
         return new Object[][]{
                 {"Table where name=\"sales_fact\" or name=\"testtable_1\"",
-                        "g.V().has('__typeName', 'Table').or(__.has('Table.name', eq(\"sales_fact\")),__.has('Table.name', eq(\"testtable_1\"))).limit(local, 25).limit(25).toList()"},
+                        "g.V().has('__typeName', 'Table').or(__.has('Table.name', eq(\"sales_fact\")),__.has('Table.name', eq(\"testtable_1\"))).dedup().limit(25).toList()"},
                 {"Table where name=\"sales_fact\" and name=\"testtable_1\"",
-                        "g.V().has('__typeName', 'Table').and(__.has('Table.name', eq(\"sales_fact\")),__.has('Table.name', eq(\"testtable_1\"))).limit(local, 25).limit(25).toList()"},
+                        "g.V().has('__typeName', 'Table').and(__.has('Table.name', eq(\"sales_fact\")),__.has('Table.name', eq(\"testtable_1\"))).dedup().limit(25).toList()"},
                 {"Table where name=\"sales_fact\" or name=\"testtable_1\" or name=\"testtable_2\"",
                         "g.V().has('__typeName', 'Table')" +
                                 ".or(" +
                                 "__.has('Table.name', eq(\"sales_fact\"))," +
                                 "__.has('Table.name', eq(\"testtable_1\"))," +
                                 "__.has('Table.name', eq(\"testtable_2\"))" +
-                                ").limit(local, 25).limit(25).toList()"},
+                                ").dedup().limit(25).toList()"},
                 {"Table where name=\"sales_fact\" and name=\"testtable_1\" and name=\"testtable_2\"",
                         "g.V().has('__typeName', 'Table')" +
                                 ".and(" +
                                 "__.has('Table.name', eq(\"sales_fact\"))," +
                                 "__.has('Table.name', eq(\"testtable_1\"))," +
                                 "__.has('Table.name', eq(\"testtable_2\"))" +
-                                ").limit(local, 25).limit(25).toList()"},
+                                ").dedup().limit(25).toList()"},
                 {"Table where (name=\"sales_fact\" or name=\"testtable_1\") and name=\"testtable_2\"",
                         "g.V().has('__typeName', 'Table')" +
                                 ".and(" +
@@ -246,7 +246,7 @@ public class GremlinQueryComposerTest {
                                 "__.has('Table.name', eq(\"testtable_1\"))" +
                                 ")," +
                                 "__.has('Table.name', eq(\"testtable_2\")))" +
-                                ".limit(local, 25).limit(25).toList()"},
+                                ".dedup().limit(25).toList()"},
                 {"Table where name=\"sales_fact\" or (name=\"testtable_1\" and name=\"testtable_2\")",
                         "g.V().has('__typeName', 'Table')" +
                                 ".or(" +
@@ -255,7 +255,7 @@ public class GremlinQueryComposerTest {
                                 "__.has('Table.name', eq(\"testtable_1\"))," +
                                 "__.has('Table.name', eq(\"testtable_2\")))" +
                                 ")" +
-                                ".limit(local, 25).limit(25).toList()"},
+                                ".dedup().limit(25).toList()"},
                 {"Table where name=\"sales_fact\" or name=\"testtable_1\" and name=\"testtable_2\"",
                         "g.V().has('__typeName', 'Table')" +
                                 ".and(" +
@@ -264,7 +264,7 @@ public class GremlinQueryComposerTest {
                                 "__.has('Table.name', eq(\"testtable_1\"))" +
                                 ")," +
                                 "__.has('Table.name', eq(\"testtable_2\")))" +
-                                ".limit(local, 25).limit(25).toList()"},
+                                ".dedup().limit(25).toList()"},
                 {"Table where (name=\"sales_fact\" and owner=\"Joe\") OR (name=\"sales_fact_daily_mv\" and owner=\"Joe BI\")",
                         "g.V().has('__typeName', 'Table')" +
                                 ".or(" +
@@ -276,13 +276,13 @@ public class GremlinQueryComposerTest {
                                 "__.has('Table.name', eq(\"sales_fact_daily_mv\"))," +
                                 "__.has('Table.owner', eq(\"Joe BI\"))" +
                                 "))" +
-                                ".limit(local, 25).limit(25).toList()"},
+                                ".dedup().limit(25).toList()"},
                 {"Table where owner=\"hdfs\" or ((name=\"testtable_1\" or name=\"testtable_2\") and createTime < \"2017-12-12T02:35:58.440Z\")",
-                        "g.V().has('__typeName', 'Table').or(__.has('Table.owner', eq(\"hdfs\")),__.and(__.or(__.has('Table.name', eq(\"testtable_1\")),__.has('Table.name', eq(\"testtable_2\"))),__.has('Table.createTime', lt('1513046158440')))).limit(local, 25).limit(25).toList()"},
+                        "g.V().has('__typeName', 'Table').or(__.has('Table.owner', eq(\"hdfs\")),__.and(__.or(__.has('Table.name', eq(\"testtable_1\")),__.has('Table.name', eq(\"testtable_2\"))),__.has('Table.createTime', lt('1513046158440')))).dedup().limit(25).toList()"},
                 {"hive_db where hive_db.name='Reporting' and hive_db.createTime < '2017-12-12T02:35:58.440Z'",
-                        "g.V().has('__typeName', 'hive_db').and(__.has('hive_db.name', eq('Reporting')),__.has('hive_db.createTime', lt('1513046158440'))).limit(local, 25).limit(25).toList()"},
+                        "g.V().has('__typeName', 'hive_db').and(__.has('hive_db.name', eq('Reporting')),__.has('hive_db.createTime', lt('1513046158440'))).dedup().limit(25).toList()"},
                 {"Table where db.name='Sales' and db.clusterName='cl1'",
-                        "g.V().has('__typeName', 'Table').and(__.out('__Table.db').has('DB.name', eq('Sales')).dedup().in('__Table.db'),__.out('__Table.db').has('DB.clusterName', eq('cl1')).dedup().in('__Table.db')).limit(local, 25).limit(25).toList()"},
+                        "g.V().has('__typeName', 'Table').and(__.out('__Table.db').has('DB.name', eq('Sales')).dedup().in('__Table.db'),__.out('__Table.db').has('DB.clusterName', eq('cl1')).dedup().in('__Table.db')).dedup().limit(25).toList()"},
         };
     }
 
@@ -295,35 +295,35 @@ public class GremlinQueryComposerTest {
     @Test
     public void keywordsInWhereClause() {
         verify("Table as t where t has name and t isa Dimension",
-                "g.V().has('__typeName', 'Table').as('t').and(__.has('Table.name'),__.has('__traitNames', within('Dimension'))).limit(local, 25).limit(25).toList()");
+                "g.V().has('__typeName', 'Table').as('t').and(__.has('Table.name'),__.has('__traitNames', within('Dimension'))).dedup().limit(25).toList()");
         verify("Table as t where t has name and t.name = 'sales_fact'",
-                "g.V().has('__typeName', 'Table').as('t').and(__.has('Table.name'),__.has('Table.name', eq('sales_fact'))).limit(local, 25).limit(25).toList()");
+                "g.V().has('__typeName', 'Table').as('t').and(__.has('Table.name'),__.has('Table.name', eq('sales_fact'))).dedup().limit(25).toList()");
         verify("Table as t where t is Dimension and t.name = 'sales_fact'",
-                "g.V().has('__typeName', 'Table').as('t').and(__.has('__traitNames', within('Dimension')),__.has('Table.name', eq('sales_fact'))).limit(local, 25).limit(25).toList()");
-        verify("Table isa 'Dimension' and name = 'sales_fact'", "g.V().has('__typeName', 'Table').and(__.has('__traitNames', within('Dimension')),__.has('Table.name', eq('sales_fact'))).limit(local, 25).limit(25).toList()");
-        verify("Table has name and name = 'sales_fact'", "g.V().has('__typeName', 'Table').and(__.has('Table.name'),__.has('Table.name', eq('sales_fact'))).limit(local, 25).limit(25).toList()");
-        verify("Table is 'Dimension' and Table has owner and name = 'sales_fact'", "g.V().has('__typeName', 'Table').and(__.has('__traitNames', within('Dimension')),__.has('Table.owner'),__.has('Table.name', eq('sales_fact'))).limit(local, 25).limit(25).toList()");
-        verify("Table has name and Table has owner and name = 'sales_fact'", "g.V().has('__typeName', 'Table').and(__.has('Table.name'),__.has('Table.owner'),__.has('Table.name', eq('sales_fact'))).limit(local, 25).limit(25).toList()");
+                "g.V().has('__typeName', 'Table').as('t').and(__.has('__traitNames', within('Dimension')),__.has('Table.name', eq('sales_fact'))).dedup().limit(25).toList()");
+        verify("Table isa 'Dimension' and name = 'sales_fact'", "g.V().has('__typeName', 'Table').and(__.has('__traitNames', within('Dimension')),__.has('Table.name', eq('sales_fact'))).dedup().limit(25).toList()");
+        verify("Table has name and name = 'sales_fact'", "g.V().has('__typeName', 'Table').and(__.has('Table.name'),__.has('Table.name', eq('sales_fact'))).dedup().limit(25).toList()");
+        verify("Table is 'Dimension' and Table has owner and name = 'sales_fact'", "g.V().has('__typeName', 'Table').and(__.has('__traitNames', within('Dimension')),__.has('Table.owner'),__.has('Table.name', eq('sales_fact'))).dedup().limit(25).toList()");
+        verify("Table has name and Table has owner and name = 'sales_fact'", "g.V().has('__typeName', 'Table').and(__.has('Table.name'),__.has('Table.owner'),__.has('Table.name', eq('sales_fact'))).dedup().limit(25).toList()");
     }
 
 
     @Test
     public void numericAttributes() {
-        verify("Table where partitionSize = 2048", "g.V().has('__typeName', 'Table').has('Table.partitionSize', eq(2048)).limit(local, 25).limit(25).toList()");
-        verify("Table where partitionSize = 2048 or partitionSize = 10", "g.V().has('__typeName', 'Table').or(__.has('Table.partitionSize', eq(2048)),__.has('Table.partitionSize', eq(10))).limit(local, 25).limit(25).toList()");
+        verify("Table where partitionSize = 2048", "g.V().has('__typeName', 'Table').has('Table.partitionSize', eq(2048)).dedup().limit(25).toList()");
+        verify("Table where partitionSize = 2048 or partitionSize = 10", "g.V().has('__typeName', 'Table').or(__.has('Table.partitionSize', eq(2048)),__.has('Table.partitionSize', eq(10))).dedup().limit(25).toList()");
     }
 
     @Test
     public void systemAttributes() {
-        verify("Table has __state", "g.V().has('__typeName', 'Table').has('__state').limit(local, 25).limit(25).toList()");
-        verify("Table select __guid", "def f(r){ t=[['__guid']];  r.each({t.add([it.value('__guid')])}); t.unique(); }; f(g.V().has('__typeName', 'Table').has('__guid').limit(local, 25).limit(25).toList())");
-        verify("Table as t where t.__state = 'ACTIVE'", "g.V().has('__typeName', 'Table').as('t').has('__state', eq('ACTIVE')).limit(local, 25).limit(25).toList()");
+        verify("Table has __state", "g.V().has('__typeName', 'Table').has('__state').dedup().limit(25).toList()");
+        verify("Table select __guid", "def f(r){ t=[['__guid']];  r.each({t.add([it.value('__guid')])}); t.unique(); }; f(g.V().has('__typeName', 'Table').has('__guid').dedup().limit(25).toList())");
+        verify("Table as t where t.__state = 'ACTIVE'", "g.V().has('__typeName', 'Table').as('t').has('__state', eq('ACTIVE')).dedup().limit(25).toList()");
     }
 
     @Test
     public void whereComplexAndSelect() {
         String exSel = "def f(r){ t=[['name']];  r.each({t.add([it.value('Table.name')])}); t.unique(); }";
-        String exMain = "g.V().has('__typeName', 'Table').and(__.out('__Table.db').has('DB.name', eq(\"Reporting\")).dedup().in('__Table.db'),__.has('Table.name', eq(\"sales_fact\"))).limit(local, 25).limit(25).toList()";
+        String exMain = "g.V().has('__typeName', 'Table').and(__.out('__Table.db').has('DB.name', eq(\"Reporting\")).dedup().in('__Table.db'),__.has('Table.name', eq(\"sales_fact\"))).dedup().limit(25).toList()";
         verify("Table where db.name = \"Reporting\" and name =\"sales_fact\" select name", getExpected(exSel, exMain));
         verify("Table where db.name = \"Reporting\" and name =\"sales_fact\"", exMain);
     }

http://git-wip-us.apache.org/repos/asf/atlas/blob/a2ccdf12/webapp/src/main/java/org/apache/atlas/web/errors/AtlasBaseExceptionMapper.java
----------------------------------------------------------------------
diff --git a/webapp/src/main/java/org/apache/atlas/web/errors/AtlasBaseExceptionMapper.java b/webapp/src/main/java/org/apache/atlas/web/errors/AtlasBaseExceptionMapper.java
index f4b8d67..fde6d8a 100755
--- a/webapp/src/main/java/org/apache/atlas/web/errors/AtlasBaseExceptionMapper.java
+++ b/webapp/src/main/java/org/apache/atlas/web/errors/AtlasBaseExceptionMapper.java
@@ -53,6 +53,11 @@ public class AtlasBaseExceptionMapper implements ExceptionMapper<AtlasBaseExcept
         AtlasErrorCode errorCode = baseException.getAtlasErrorCode();
         errorJsonMap.put("errorCode", errorCode.getErrorCode());
         errorJsonMap.put("errorMessage", baseException.getMessage());
+
+        if (baseException.getCause() != null) {
+            errorJsonMap.put("errorCause", baseException.getCause().getMessage());
+        }
+
         Response.ResponseBuilder responseBuilder = Response.status(errorCode.getHttpCode());
 
         // No body for 204 (and maybe 304)