Commit 9853d9d1 by Harish Butani

support output for select expressions and non-class types; add helper for GremlinQueryResult toJson

parent 8f5a2a29
......@@ -21,7 +21,7 @@ package org.apache.hadoop.metadata.query
import com.thinkaurelius.titan.core.TitanVertex
import com.tinkerpop.blueprints.Direction
import org.apache.hadoop.metadata.types.DataTypes._
import org.apache.hadoop.metadata.{ITypedInstance, ITypedReferenceableInstance}
import org.apache.hadoop.metadata.{IStruct, ITypedInstance, IReferenceableInstance, ITypedReferenceableInstance}
import org.apache.hadoop.metadata.query.Expressions.{ExpressionException, ComparisonExpression}
import org.apache.hadoop.metadata.query.TypeUtils.FieldInfo
import org.apache.hadoop.metadata.storage.Id
......@@ -80,14 +80,7 @@ trait GraphPersistenceStrategies {
*/
def getIdFromVertex(dataTypeNm : String, v : TitanVertex) : Id
/**
* construct a [[ITypedReferenceableInstance]] from its vertex
*
* @param dataType
* @param v
* @return
*/
def constructClassInstance(dataType : ClassType, v : TitanVertex) : ITypedReferenceableInstance
def constructInstance[U](dataType : IDataType[U], v : AnyRef) : U
def gremlinCompOp(op : ComparisonExpression) = op.symbol match {
case "=" => "T.eq"
......@@ -120,6 +113,35 @@ object GraphPersistenceStrategy1 extends GraphPersistenceStrategies {
}
}
def constructInstance[U](dataType : IDataType[U], v : AnyRef) : U = {
dataType.getTypeCategory match {
case DataTypes.TypeCategory.PRIMITIVE => dataType.convert(v, Multiplicity.OPTIONAL)
case DataTypes.TypeCategory.STRUCT => {
val sType = dataType.asInstanceOf[StructType]
val sInstance = sType.createInstance()
loadStructInstance(sType, sInstance, v.asInstanceOf[TitanVertex])
dataType.convert(sInstance, Multiplicity.OPTIONAL)
}
case DataTypes.TypeCategory.TRAIT => {
val tType = dataType.asInstanceOf[TraitType]
val tInstance = tType.createInstance()
/*
* this is not right, we should load the Instance associated with this trait.
* for now just loading the trait struct.
*/
loadStructInstance(tType, tInstance, v.asInstanceOf[TitanVertex])
dataType.convert(tInstance, Multiplicity.OPTIONAL)
}
case DataTypes.TypeCategory.CLASS => {
val cType = dataType.asInstanceOf[ClassType]
val cInstance = constructClassInstance(dataType.asInstanceOf[ClassType], v.asInstanceOf[TitanVertex])
dataType.convert(cInstance, Multiplicity.OPTIONAL)
}
case DataTypes.TypeCategory.ENUM => dataType.convert(v, Multiplicity.OPTIONAL)
case x => throw new UnsupportedOperationException(s"load for ${dataType} not supported")
}
}
def loadStructInstance(dataType : IConstructableType[_,_ <: ITypedInstance],
typInstance : ITypedInstance, v : TitanVertex) : Unit = {
import scala.collection.JavaConversions._
......
......@@ -20,14 +20,20 @@ package org.apache.hadoop.metadata.query
import javax.script.{Bindings, ScriptEngine, ScriptEngineManager}
import com.thinkaurelius.titan.core.{TitanVertex, TitanGraph}
import org.apache.hadoop.metadata.ITypedInstance
import org.apache.hadoop.metadata.types.{ClassType, IConstructableType}
import com.thinkaurelius.titan.core.TitanGraph
import com.tinkerpop.pipes.util.structures.Row
import org.apache.hadoop.metadata.json._
import org.apache.hadoop.metadata.types._
import org.json4s._
import org.json4s.native.Serialization._
import scala.language.existentials
case class GremlinQueryResult(qry : GremlinQuery,
resultDataType : IConstructableType[_, _ <: ITypedInstance],
rows : List[ITypedInstance])
case class GremlinQueryResult(query : String,
resultDataType : IDataType[_],
rows : List[_]) {
def toJson = JsonHelper.toJson(this)
}
class GremlinEvaluator(qry : GremlinQuery, persistenceStrategy : GraphPersistenceStrategies, g: TitanGraph) {
......@@ -41,15 +47,52 @@ class GremlinEvaluator(qry : GremlinQuery, persistenceStrategy : GraphPersistenc
val rType = qry.expr.dataType
val rawRes = engine.eval(qry.queryStr, bindings)
if ( rType.isInstanceOf[ClassType]) {
val dType = rType.asInstanceOf[ClassType]
val rows = rawRes.asInstanceOf[java.util.List[TitanVertex]].map { v =>
persistenceStrategy.constructClassInstance(dType, v)
if ( !qry.hasSelectList ) {
val rows = rawRes.asInstanceOf[java.util.List[AnyRef]].map { v =>
persistenceStrategy.constructInstance(rType, v)
}
GremlinQueryResult(qry, dType, rows.toList)
GremlinQueryResult(qry.expr.toString, rType, rows.toList)
} else {
null
val sType = rType.asInstanceOf[StructType]
val rows = rawRes.asInstanceOf[java.util.List[Row[java.util.List[_]]]].map { r =>
val sInstance = sType.createInstance()
val selExpr = qry.expr.asInstanceOf[Expressions.SelectExpression]
selExpr.selectListWithAlias.foreach { aE =>
val cName = aE.alias
val (src, idx) = qry.resultMaping(cName)
val v = r.getColumn(src).get(idx)
sInstance.set(cName, aE.dataType.convert(v, Multiplicity.OPTIONAL))
}
sInstance
}
GremlinQueryResult(qry.expr.toString, sType, rows.toList)
}
}
}
object JsonHelper {
class GremlinQueryResultSerializer()
extends Serializer[GremlinQueryResult] {
def deserialize(implicit format: Formats) = {
throw new UnsupportedOperationException("Deserialization of GremlinQueryResult not supported")
}
def serialize(implicit f: Formats) = {
case GremlinQueryResult(query, rT, rows) =>
JObject(JField("query", JString(query)),
JField("dataType", TypesSerialization.toJsonValue(rT)(f)),
JField("rows", Extraction.decompose(rows)(f))
)
}
}
implicit val formats = org.json4s.native.Serialization.formats(NoTypeHints) + new TypedStructSerializer +
new TypedReferenceableInstanceSerializer + new BigDecimalSerializer + new BigIntegerSerializer +
new GremlinQueryResultSerializer
def toJson(r : GremlinQueryResult ) : String = {
writePretty(r)
}
}
\ No newline at end of file
......@@ -25,8 +25,9 @@ import scala.collection.mutable
import scala.collection.mutable.ArrayBuffer
case class GremlinQuery(expr: Expression, queryStr: String) {
case class GremlinQuery(expr: Expression, queryStr: String, resultMaping : Map[String, (String, Int)]) {
def hasSelectList = resultMaping != null
}
trait SelectExpressionHandling {
......@@ -93,6 +94,24 @@ trait SelectExpressionHandling {
m
}
/**
* For each Output Column in the SelectExpression compute the ArrayList(Src) this maps to and the position within
* this list.
* @param sel
* @return
*/
def buildResultMapping(sel : SelectExpression) : Map[String, (String, Int)] = {
val srcToExprs = groupSelectExpressionsBySrc(sel)
val m = new mutable.HashMap[String, (String, Int)]
sel.selectListWithAlias.foreach { se =>
val src = getSelectExpressionSrc(se.child)(0)
val srcExprs = srcToExprs(src)
var idx = srcExprs.indexOf(se.child)
m(se.alias) = (src, idx)
}
m.toMap
}
}
class GremlinTranslationException(expr: Expression, reason: String) extends
......@@ -195,8 +214,11 @@ class GremlinTranslator(expr: Expression,
e1.traverseUp(validateSelectExprHaveOneSrc)
e1 match {
case e1: SelectExpression => GremlinQuery(e1, s"g.V.${genQuery(e1, false)}.toList()")
case e1 => GremlinQuery(e1, s"g.V.${genQuery(e1, false)}.toList()")
case e1: SelectExpression => {
val rMap = buildResultMapping(e1)
GremlinQuery(e1, s"g.V.${genQuery(e1, false)}.toList()", rMap)
}
case e1 => GremlinQuery(e1, s"g.V.${genQuery(e1, false)}.toList()", null)
}
}
......
......@@ -18,8 +18,8 @@
package org.apache.hadoop.metadata.query
import Expressions._
import com.thinkaurelius.titan.core.TitanGraph
import org.apache.hadoop.metadata.query.Expressions._
object QueryProcessor {
......
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