add Not logical operator on WhereParser.
diff --git a/s2core/src/main/scala/org/apache/s2graph/core/parsers/WhereParser.scala b/s2core/src/main/scala/org/apache/s2graph/core/parsers/WhereParser.scala
index 75e9657..d6e176b 100644
--- a/s2core/src/main/scala/org/apache/s2graph/core/parsers/WhereParser.scala
+++ b/s2core/src/main/scala/org/apache/s2graph/core/parsers/WhereParser.scala
@@ -198,10 +198,14 @@
 
   def paren: Parser[Clause] = "(" ~> clause <~ ")"
 
-  def clause: Parser[Clause] = (predicate | paren) * (and ^^^ { (a: Clause, b: Clause) => And(a, b) } | or ^^^ { (a: Clause, b: Clause) => Or(a, b) })
+  def clause: Parser[Clause] = (_not | predicate | paren) * (and ^^^ { (a: Clause, b: Clause) => And(a, b) } | or ^^^ { (a: Clause, b: Clause) => Or(a, b) })
 
   def identWithDot: Parser[String] = repsep(ident, ".") ^^ { case values => values.mkString(".") }
 
+  val _not = "not|NOT".r ~ (predicate | paren) ^^ {
+    case op ~ p => Not(p)
+  }
+
   val _eq = identWithDot ~ ("!=" | "=") ~ stringLiteral ^^ {
     case f ~ op ~ s => if (op == "=") Eq(f, s) else Not(Eq(f, s))
   }
@@ -219,14 +223,10 @@
     case f ~ minV ~ maxV => Between(f, minV, maxV)
   }
 
-  val _in = identWithDot ~ (notIn | in) ~ ("(" ~> repsep(stringLiteral, ",") <~ ")") ^^ {
+  val _in = identWithDot ~ (in) ~ ("(" ~> repsep(stringLiteral, ",") <~ ")") ^^ {
     case f ~ op ~ values =>
-      val inClause =
-        if (f.startsWith("_parent")) IN(f, values.toSet)
-        else InWithoutParent(f, values.toSet)
-
-      if (op.toLowerCase == "in") inClause
-      else Not(inClause)
+      if (f.startsWith("_parent")) IN(f, values.toSet)
+      else InWithoutParent(f, values.toSet)
   }
 
   val _contains = identWithDot ~ contains ~ stringLiteral ^^ {
diff --git a/s2core/src/test/scala/org/apache/s2graph/core/parsers/WhereParserTest.scala b/s2core/src/test/scala/org/apache/s2graph/core/parsers/WhereParserTest.scala
index 342d9c6..0ff4db1 100644
--- a/s2core/src/test/scala/org/apache/s2graph/core/parsers/WhereParserTest.scala
+++ b/s2core/src/test/scala/org/apache/s2graph/core/parsers/WhereParserTest.scala
@@ -46,6 +46,7 @@
     }
 
     val whereOpt = WhereParser().parse(sql)
+
     if (whereOpt.isFailure) {
       debug(whereOpt)
       whereOpt.get // touch exception
@@ -138,6 +139,7 @@
       f("time > 2")(true)
       f("time <= 3")(true)
       f("time < 2")(false)
+      f("NOT time >= 3")(false)
 
       f("(time in (1, 2, 3) and is_blocked = true) or is_hidden = false")(false)
       f("(time in (1, 2, 3) or is_blocked = true) or is_hidden = false")(true)
@@ -169,6 +171,8 @@
       f(s"_from = ${tgtVertex.innerId.value} and _to = 102934")(false)
       f(s"_from = -1")(false)
       f(s"_from in (-1, -0.1)")(false)
+      f(s"NOT (_from = -1)")(true)
+      f(s"NOT _from contains 'a'")(true)
     }
   }