remove inefficiency logic
diff --git a/s2graphql/src/main/scala/org/apache/s2graph/graphql/GraphQLServer.scala b/s2graphql/src/main/scala/org/apache/s2graph/graphql/GraphQLServer.scala
index 5f1c225..a4a61ff 100644
--- a/s2graphql/src/main/scala/org/apache/s2graph/graphql/GraphQLServer.scala
+++ b/s2graphql/src/main/scala/org/apache/s2graph/graphql/GraphQLServer.scala
@@ -45,7 +45,7 @@
 import scala.util.control.NonFatal
 import scala.util.{Failure, Success, Try}
 
-object GraphQLServer {
+class GraphQLServer() {
   val className = Schema.getClass.getName
   val logger = LoggerFactory.getLogger(this.getClass)
 
@@ -58,6 +58,7 @@
   val config = ConfigFactory.load()
   val s2graph = new S2Graph(config)
   val schemaCacheTTL = Try(config.getInt("schemaCacheTTL")).getOrElse(-1)
+  val withAdmin = Try(config.getBoolean("schemaCacheTTL")).getOrElse(false)
   val s2Repository = new GraphRepository(s2graph)
   val schemaConfig = ConfigFactory.parseMap(Map(
     SafeUpdateCache.MaxSizeKey -> 1, SafeUpdateCache.TtlKey -> schemaCacheTTL
@@ -77,15 +78,24 @@
     ret
   }
 
+  logger.info(s"schemaCacheTTL: ${schemaCacheTTL}")
+
+  val schemaCacheKey = className + "s2Schema"
+
+  schemaCache.put(schemaCacheKey, createNewSchema(withAdmin))
+
   /**
     * In development mode(schemaCacheTTL = -1),
     * a new schema is created for each request.
     */
-  logger.info(s"schemaCacheTTL: ${schemaCacheTTL}")
 
-  private def createNewSchema(): Schema[GraphRepository, Any] = {
-    val newSchema = new SchemaDef(s2Repository).S2GraphSchema
-    logger.info(s"Schema updated: ${System.currentTimeMillis()}")
+  private def createNewSchema(withAdmin: Boolean): Schema[GraphRepository, Any] = {
+    logger.info(s"Schema update start")
+
+    val ts = System.currentTimeMillis()
+    val newSchema = new SchemaDef(s2Repository, withAdmin).S2GraphSchema
+
+    logger.info(s"Schema updated: ${(System.currentTimeMillis() - ts) / 1000} sec")
 
     newSchema
   }
@@ -115,8 +125,7 @@
   def executeGraphQLQuery(query: Document, op: Option[String], vars: JsObject)(implicit e: ExecutionContext) = {
     import GraphRepository._
 
-    val cacheKey = className + "s2Schema"
-    val s2schema = schemaCache.withCache(cacheKey, broadcast = false, onEvict = onEvictSchema)(createNewSchema())
+    val s2schema = schemaCache.withCache(schemaCacheKey, broadcast = false, onEvict = onEvictSchema)(createNewSchema(withAdmin))
     val resolver: DeferredResolver[GraphRepository] = DeferredResolver.fetchers(vertexFetcher, edgeFetcher)
 
     val includeGrpaph = vars.fields.get("includeGraph").contains(spray.json.JsBoolean(true))
diff --git a/s2graphql/src/main/scala/org/apache/s2graph/graphql/HttpServer.scala b/s2graphql/src/main/scala/org/apache/s2graph/graphql/HttpServer.scala
index 65ff348..8b89c73 100644
--- a/s2graphql/src/main/scala/org/apache/s2graph/graphql/HttpServer.scala
+++ b/s2graphql/src/main/scala/org/apache/s2graph/graphql/HttpServer.scala
@@ -54,12 +54,14 @@
 
   import spray.json.DefaultJsonProtocol._
 
+  val graphQLServer = new GraphQLServer()
+
   val route: Route =
     get {
       getFromResource("assets/graphiql.html")
     } ~ (post & path("updateEdgeFetcher")) {
       entity(as[JsValue]) { body =>
-        GraphQLServer.updateEdgeFetcher(body) match {
+        graphQLServer.updateEdgeFetcher(body) match {
           case Success(_) => complete(StatusCodes.OK -> JsString("Update fetcher finished"))
           case Failure(e) =>
             logger.error("Error on execute", e)
@@ -70,11 +72,11 @@
       parameters('operationName.?, 'variables.?) { (operationNameParam, variablesParam) =>
         entity(as[Document]) { document ⇒
           variablesParam.map(parseJson) match {
-            case None ⇒ complete(GraphQLServer.executeGraphQLQuery(document, operationNameParam, JsObject()))
-            case Some(Right(js)) ⇒ complete(GraphQLServer.executeGraphQLQuery(document, operationNameParam, js.asJsObject))
+            case None ⇒ complete(graphQLServer.executeGraphQLQuery(document, operationNameParam, JsObject()))
+            case Some(Right(js)) ⇒ complete(graphQLServer.executeGraphQLQuery(document, operationNameParam, js.asJsObject))
             case Some(Left(e)) ⇒
               logger.error("Error on execute", e)
-              complete(StatusCodes.BadRequest -> GraphQLServer.formatError(e))
+              complete(StatusCodes.BadRequest -> graphQLServer.formatError(e))
           }
         } ~ entity(as[JsValue]) { body ⇒
           val fields = body.asJsObject.fields
@@ -84,13 +86,13 @@
           val variables = fields.get("variables").filterNot(_ == JsNull)
 
           query.map(QueryParser.parse(_)) match {
-            case None ⇒ complete(StatusCodes.BadRequest -> GraphQLServer.formatError("No query to execute"))
+            case None ⇒ complete(StatusCodes.BadRequest -> graphQLServer.formatError("No query to execute"))
             case Some(Failure(error)) ⇒
               logger.error("Error on execute", error)
-              complete(StatusCodes.BadRequest -> GraphQLServer.formatError(error))
+              complete(StatusCodes.BadRequest -> graphQLServer.formatError(error))
             case Some(Success(document)) => variables match {
-              case Some(js) ⇒ complete(GraphQLServer.executeGraphQLQuery(document, operationName, js.asJsObject))
-              case None ⇒ complete(GraphQLServer.executeGraphQLQuery(document, operationName, JsObject()))
+              case Some(js) ⇒ complete(graphQLServer.executeGraphQLQuery(document, operationName, js.asJsObject))
+              case None ⇒ complete(graphQLServer.executeGraphQLQuery(document, operationName, JsObject()))
             }
           }
         }
@@ -101,7 +103,9 @@
 
   logger.info(s"Starting GraphQL server... $port")
 
-  Http().bindAndHandle(route, "0.0.0.0", port)
+  Http().bindAndHandle(route, "0.0.0.0", port).foreach { binding =>
+    logger.info(s"GraphQL server ready for connect")
+  }
 
   def shutdown(): Unit = {
     logger.info("Terminating...")
diff --git a/s2graphql/src/main/scala/org/apache/s2graph/graphql/repository/GraphRepository.scala b/s2graphql/src/main/scala/org/apache/s2graph/graphql/repository/GraphRepository.scala
index b5e65dc..bd98504 100644
--- a/s2graphql/src/main/scala/org/apache/s2graph/graphql/repository/GraphRepository.scala
+++ b/s2graphql/src/main/scala/org/apache/s2graph/graphql/repository/GraphRepository.scala
@@ -273,14 +273,29 @@
 
   def deleteLabel(args: Args): Try[Label] = {
     val labelName = args.arg[String]("name")
-
     val deleteLabelTry = Management.deleteLabel(labelName)
+
     withLogTryResponse("deleteLabel", deleteLabelTry)
   }
 
-  def services(): List[Service] = Service.findAll()
+  def services(): List[Service] = {
+    Service.findAll()
+  }
 
-  def serviceColumns(): List[ServiceColumn] = ServiceColumn.findAll()
+  def serviceColumns(): List[ServiceColumn] = {
+    val allServices = services().toSet
 
-  def labels() = Label.findAll()
+    ServiceColumn
+      .findAll()
+      .filter(sc => allServices(sc.service))
+  }
+
+  def labels() = {
+    val allServiceColumns = serviceColumns().toSet
+
+    Label
+      .findAll()
+      .filter(l => allServiceColumns(l.srcColumn) || allServiceColumns(l.tgtColumn))
+  }
+
 }
diff --git a/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/ManagementType.scala b/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/ManagementType.scala
index 1275ca7..7b57059 100644
--- a/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/ManagementType.scala
+++ b/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/ManagementType.scala
@@ -67,7 +67,11 @@
   import org.apache.s2graph.graphql.bind.Unmarshaller._
   import org.apache.s2graph.graphql.types.StaticTypes._
 
-  lazy val serviceColumnOnServiceWithPropInputObjectFields = repo.services().map { service =>
+  val services = repo.services()
+  val serviceColumns = repo.serviceColumns()
+  val labels = repo.labels()
+
+  lazy val serviceColumnOnServiceWithPropInputObjectFields = services.map { service =>
     InputField(service.serviceName.toValidName, OptionInputType(InputObjectType(
       s"Input_${service.serviceName.toValidName}_ServiceColumn_Props",
       description = "desc here",
@@ -78,7 +82,7 @@
     )))
   }
 
-  lazy val serviceColumnOnServiceInputObjectFields = repo.services().map { service =>
+  lazy val serviceColumnOnServiceInputObjectFields = services.map { service =>
     InputField(service.serviceName.toValidName, OptionInputType(InputObjectType(
       s"Input_${service.serviceName.toValidName}_ServiceColumn",
       description = "desc here",
@@ -91,15 +95,17 @@
   def makeServiceColumnEnumTypeOnService(service: Service): EnumType[String] = {
     val columns = service.serviceColumns(false).toList
     EnumType(
-      s"Enum_${service.serviceName}_ServiceColumn",
+      s"Enum_${service.serviceName.toValidName}_ServiceColumn",
       description = Option("desc here"),
-      values = dummyEnum +: columns.map { column =>
-        EnumValue(column.columnName.toValidName, value = column.columnName.toValidName)
-      }
+      values =
+        if (columns.isEmpty) dummyEnum :: Nil
+        else columns.map { column =>
+          EnumValue(column.columnName.toValidName, value = column.columnName)
+        }
     )
   }
 
-  lazy val labelPropsInputFields = repo.labels().map { label =>
+  lazy val labelPropsInputFields = labels.map { label =>
     InputField(label.label.toValidName, OptionInputType(InputObjectType(
       s"Input_${label.label.toValidName}_props",
       description = "desc here",
@@ -134,28 +140,34 @@
   lazy val ServiceListType = EnumType(
     s"Enum_Service",
     description = Option("desc here"),
-    values =
-      dummyEnum +: repo.services().map { service =>
+    values = {
+      if (services.isEmpty) dummyEnum :: Nil
+      else services.map { service =>
         EnumValue(service.serviceName.toValidName, value = service.serviceName)
       }
+    }
   )
 
   lazy val ServiceColumnListType = EnumType(
     s"Enum_ServiceColumn",
     description = Option("desc here"),
-    values =
-      dummyEnum +: repo.serviceColumns().map { serviceColumn =>
+    values = {
+      if (serviceColumns.isEmpty) dummyEnum :: Nil
+      else serviceColumns.map { serviceColumn =>
         EnumValue(serviceColumn.columnName.toValidName, value = serviceColumn.columnName)
       }
+    }
   )
 
   lazy val EnumLabelsType = EnumType(
     s"Enum_Label",
     description = Option("desc here"),
-    values =
-      dummyEnum +: repo.labels().map { label =>
+    values = {
+      if (labels.isEmpty) dummyEnum :: Nil
+      else labels.map { label =>
         EnumValue(label.label.toValidName, value = label.label)
       }
+    }
   )
 
   lazy val ServiceMutationResponseType = makeMutationResponseType[Service](
@@ -200,19 +212,25 @@
   val AddPropServiceType = InputObjectType[ServiceColumnParam](
     "Input_Service_ServiceColumn_Props",
     description = "desc",
-    fields = DummyInputField +: serviceColumnOnServiceWithPropInputObjectFields
+    fields =
+      if (serviceColumnOnServiceWithPropInputObjectFields.isEmpty) DummyInputField :: Nil
+      else serviceColumnOnServiceWithPropInputObjectFields
   )
 
   val ServiceColumnSelectType = InputObjectType[ServiceColumnParam](
     "Input_Service_ServiceColumn",
     description = "desc",
-    fields = DummyInputField +: serviceColumnOnServiceInputObjectFields
+    fields =
+      if (serviceColumnOnServiceInputObjectFields.isEmpty) DummyInputField :: Nil
+      else serviceColumnOnServiceInputObjectFields
   )
 
   val InputServiceType = InputObjectType[ServiceColumnParam](
     "Input_Service",
     description = "desc",
-    fields = DummyInputField +: serviceColumnOnServiceInputObjectFields
+    fields =
+      if (serviceColumnOnServiceInputObjectFields.isEmpty) DummyInputField :: Nil
+      else serviceColumnOnServiceInputObjectFields
   )
 
   lazy val servicesField: Field[GraphRepository, Any] = Field(
diff --git a/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/S2Type.scala b/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/S2Type.scala
index a18fc4e..e41e838 100644
--- a/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/S2Type.scala
+++ b/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/S2Type.scala
@@ -27,6 +27,7 @@
 import sangria.schema._
 import org.apache.s2graph.graphql.types.StaticTypes._
 
+import scala.collection.mutable
 import scala.language.existentials
 
 object S2Type {
@@ -102,36 +103,116 @@
     labelFields.asInstanceOf[Seq[InputField[Any]]] ++ propFields.asInstanceOf[Seq[InputField[Any]]]
   }
 
-  def makeServiceColumnFields(column: ServiceColumn, allLabels: Seq[Label]): List[Field[GraphRepository, Any]] = {
-    val reservedFields = List("id" -> column.columnType, "timestamp" -> "long")
+  def makeServiceColumnFields(column: ServiceColumn,
+                              relatedLabels: Seq[Label])
+                             (typeCache: mutable.Map[String, ObjectType[GraphRepository, Any]]): List[Field[GraphRepository, Any]] = {
+
+    val reservedFields = Vector("id" -> column.columnType, "timestamp" -> "long")
     val columnMetasKv = column.metasWithoutCache.filter(ColumnMeta.isValid).map { columnMeta => columnMeta.name -> columnMeta.dataType }
 
-    val (sameLabel, diffLabel) = allLabels.toList.partition(l => l.srcColumn == l.tgtColumn)
+    val (sameLabel, diffLabel) = relatedLabels.toList.partition(l => l.srcColumn == l.tgtColumn)
 
-    val outLabels = diffLabel.filter(l => column == l.srcColumn).distinct.toList
-    val inLabels = diffLabel.filter(l => column == l.tgtColumn).distinct.toList
+    val outLabels = diffLabel.filter(l => column == l.srcColumn).distinct
+    val inLabels = diffLabel.filter(l => column == l.tgtColumn).distinct
     val inOutLabels = sameLabel.filter(l => l.srcColumn == column && l.tgtColumn == column)
 
-    lazy val columnFields = (reservedFields ++ columnMetasKv).map { case (k, v) => makeGraphElementField(k.toValidName, v) }
+    val columnFields = (reservedFields ++ columnMetasKv).map { case (k, v) => makeGraphElementField(k.toValidName, v) }
 
-    lazy val outLabelFields: List[Field[GraphRepository, Any]] = outLabels.map(l => makeLabelField("out", l, allLabels))
-    lazy val inLabelFields: List[Field[GraphRepository, Any]] = inLabels.map(l => makeLabelField("in", l, allLabels))
-    lazy val inOutLabelFields: List[Field[GraphRepository, Any]] = inOutLabels.map(l => makeLabelField("both", l, allLabels))
-    lazy val propsType = wrapField(s"ServiceColumn_${column.service.serviceName}_${column.columnName}_props", "props", columnFields)
+    val outLabelFields: List[Field[GraphRepository, Any]] = outLabels.map(l => toLabelFieldOnColumn("out", l, relatedLabels)(typeCache))
+    val inLabelFields: List[Field[GraphRepository, Any]] = inLabels.map(l => toLabelFieldOnColumn("in", l, relatedLabels)(typeCache))
+    val inOutLabelFields: List[Field[GraphRepository, Any]] = inOutLabels.map(l => toLabelFieldOnColumn("both", l, relatedLabels)(typeCache))
+    val propsType = wrapField(s"ServiceColumn_${column.service.serviceName.toValidName}_${column.columnName.toValidName}_props", "props", columnFields)
 
-    lazy val labelFieldNameSet = (outLabels ++ inLabels ++ inOutLabels).map(_.label).toSet
+    val labelFieldNameSet = (outLabels ++ inLabels ++ inOutLabels).map(_.label.toValidName).toSet
 
-    propsType :: inLabelFields ++ outLabelFields ++ inOutLabelFields ++ columnFields.filterNot(cf => labelFieldNameSet(cf.name))
+    propsType :: inLabelFields ++ outLabelFields ++ inOutLabelFields ++ columnFields.filterNot(cf => labelFieldNameSet(cf.name.toValidName))
   }
 
-  def makeServiceField(service: Service, allLabels: List[Label])(implicit repo: GraphRepository): List[Field[GraphRepository, Any]] = {
-    val columnsOnService = service.serviceColumns(false).toList.map { column =>
-      lazy val serviceColumnFields = makeServiceColumnFields(column, allLabels)
-      lazy val ColumnType = ObjectType(
-        s"ServiceColumn_${service.serviceName}_${column.columnName}",
+  def toLabelFieldOnColumn(dir: String, label: Label, relatedLabels: Seq[Label])
+                          (typeCache: mutable.Map[String, ObjectType[GraphRepository, Any]]): Field[GraphRepository, Any] = {
+
+    val LabelType = makeLabelType(dir, label, relatedLabels)(typeCache)
+
+    val dirArgs = dir match {
+      case "in" => Argument("direction", OptionInputType(InDirectionType), "desc here", defaultValue = "in") :: Nil
+      case "out" => Argument("direction", OptionInputType(OutDirectionType), "desc here", defaultValue = "out") :: Nil
+      case "both" => Argument("direction", OptionInputType(BothDirectionType), "desc here", defaultValue = "out") :: Nil
+    }
+
+    val indexEnumType = EnumType(
+      s"Label_Index_${label.label.toValidName}",
+      description = Option("desc here"),
+      values =
+        if (label.indices.isEmpty) EnumValue("_", value = "_") :: Nil
+        else label.indices.map(idx => EnumValue(idx.name.toValidName, value = idx.name))
+    )
+
+    val paramArgs = List(
+      Argument("offset", OptionInputType(IntType), "desc here", defaultValue = 0),
+      Argument("limit", OptionInputType(IntType), "desc here", defaultValue = 100),
+      Argument("index", OptionInputType(indexEnumType), "desc here"),
+      Argument("filter", OptionInputType(StringType), "desc here")
+    )
+
+    val edgeTypeField: Field[GraphRepository, Any] = Field(
+      s"${label.label.toValidName}",
+      ListType(LabelType),
+      arguments = dirArgs ++ paramArgs,
+      description = Some("fetch edges"),
+      resolve = { c =>
+        implicit val ec = c.ctx.ec
+
+        val edgeQueryParam = graphql.types.FieldResolver.label(label, c)
+        val empty = Seq.empty[S2EdgeLike]
+
+        DeferredValue(
+          GraphRepository.edgeFetcher.deferOpt(edgeQueryParam)
+        ).map(m => m.fold(empty)(m => m._2))
+      }
+    )
+
+    edgeTypeField
+  }
+
+
+  def makeColumnType(column: ServiceColumn, relatedLabels: Seq[Label])
+                    (typeCache: mutable.Map[String, ObjectType[GraphRepository, Any]]): ObjectType[GraphRepository, Any] = {
+
+    val objectName = s"ServiceColumn_${column.service.serviceName.toValidName}_${column.columnName.toValidName}"
+
+    typeCache.getOrElseUpdate(objectName, {
+      lazy val serviceColumnFields = makeServiceColumnFields(column, relatedLabels)(typeCache)
+
+      val ColumnType = ObjectType(
+        objectName,
         () => fields[GraphRepository, Any](serviceColumnFields: _*)
       )
 
+      ColumnType
+    })
+  }
+
+  def makeServiceType(service: Service,
+                      relatedColumns: Seq[ServiceColumn],
+                      relatedLabels: Seq[Label])
+                     (typeCache: mutable.Map[String, ObjectType[GraphRepository, Any]]): ObjectType[GraphRepository, Any] = {
+
+    val _serviceFields = makeServiceFields(service, relatedColumns, relatedLabels)(typeCache)
+    val serviceFields = if (_serviceFields.isEmpty) DummyObjectTypeField :: _serviceFields else _serviceFields
+
+    ObjectType(
+      s"Service_${service.serviceName.toValidName}",
+      fields[GraphRepository, Any](serviceFields: _*)
+    )
+  }
+
+  def makeServiceFields(service: Service, columns: Seq[ServiceColumn], relatedLabels: Seq[Label])
+                       (typeCache: mutable.Map[String, ObjectType[GraphRepository, Any]]): List[Field[GraphRepository, Any]] = {
+
+    val columnsOnService = columns.map { column =>
+
+      val ColumnType = makeColumnType(column, relatedLabels)(typeCache)
+
       Field(column.columnName.toValidName,
         ListType(ColumnType),
         arguments = List(
@@ -152,76 +233,52 @@
       ): Field[GraphRepository, Any]
     }
 
-    columnsOnService
+    columnsOnService.toList
   }
 
-  def makeLabelField(dir: String, label: Label, allLabels: Seq[Label]): Field[GraphRepository, Any] = {
+  def makeLabelType(dir: String, label: Label, relatedLabels: Seq[Label])
+                   (typeCache: mutable.Map[String, ObjectType[GraphRepository, Any]]): ObjectType[GraphRepository, Any] = {
+
+    val objectName = s"Label_${label.label.toValidName}_${dir}"
+
+    typeCache.getOrElseUpdate(objectName, {
+      lazy val labelFields = makeLabelFields(dir, label, relatedLabels)(typeCache)
+
+      val LabelType = ObjectType(
+        objectName,
+        () => fields[GraphRepository, Any](labelFields: _*)
+      )
+
+      LabelType
+    })
+  }
+
+  def makeLabelFields(dir: String, label: Label, relatedLabels: Seq[Label])
+                     (typeCache: mutable.Map[String, ObjectType[GraphRepository, Any]]): List[Field[GraphRepository, Any]] = {
+
     val labelReserved = List("direction" -> "string", "timestamp" -> "long")
-    val labelProps = label.labelMetas.map { lm => lm.name -> lm.dataType }
+
+    val labelProps = label.labelMetas
+      .filterNot(l => labelReserved.exists(kv => kv._1 == l.name))
+      .map { lm => lm.name -> lm.dataType }
 
     val column = if (dir == "out") label.tgtColumn else label.srcColumn
 
-    lazy val labelFields: List[Field[GraphRepository, Any]] =
+    val labelFields: List[Field[GraphRepository, Any]] =
       (labelReserved ++ labelProps).map { case (k, v) => makeGraphElementField(k.toValidName, v) }
 
-    lazy val labelPropField = wrapField(s"Label_${label.label.toValidName}_props", "props", labelFields)
+    val labelPropField = wrapField(s"Label_${label.label.toValidName}_props", "props", labelFields)
+    val labelColumnType = makeColumnType(column, relatedLabels)(typeCache)
 
-    lazy val labelColumnType = ObjectType(s"Label_${label.label.toValidName}_${column.columnName.toValidName}",
-      () => makeServiceColumnFields(column, allLabels)
-    )
-
-    lazy val serviceColumnField: Field[GraphRepository, Any] = Field(column.columnName, labelColumnType, resolve = c => {
-      implicit val ec = c.ctx.ec
-      val vertexQueryParam = FieldResolver.serviceColumnOnLabel(c)
-
-      DeferredValue(GraphRepository.vertexFetcher.defer(vertexQueryParam)).map(m => m._2.head)
-    })
-
-    lazy val EdgeType = ObjectType(
-      s"Label_${label.label.toValidName}_${column.columnName.toValidName}_${dir}",
-      () => fields[GraphRepository, Any](
-        List(serviceColumnField, labelPropField) ++ labelFields.filterNot(_.name == column.columnName): _*)
-    )
-
-    val dirArgs = dir match {
-      case "in" => Argument("direction", OptionInputType(InDirectionType), "desc here", defaultValue = "in") :: Nil
-      case "out" => Argument("direction", OptionInputType(OutDirectionType), "desc here", defaultValue = "out") :: Nil
-      case "both" => Argument("direction", OptionInputType(BothDirectionType), "desc here", defaultValue = "out") :: Nil
-    }
-
-    val idxNames = label.indices.map { idx =>
-      EnumValue(idx.name.toValidName, value = idx.name.toValidName)
-    }
-
-    val indexEnumType = EnumType(
-      s"Label_Index_${label.label.toValidName}",
-      description = Option("desc here"),
-      values = idxNames
-    )
-
-    val paramArgs = List(
-      Argument("offset", OptionInputType(IntType), "desc here", defaultValue = 0),
-      Argument("limit", OptionInputType(IntType), "desc here", defaultValue = 100),
-      Argument("index", OptionInputType(indexEnumType), "desc here"),
-      Argument("filter", OptionInputType(StringType), "desc here")
-    )
-
-    lazy val edgeTypeField: Field[GraphRepository, Any] = Field(
-      s"${label.label.toValidName}",
-      ListType(EdgeType),
-      arguments = dirArgs ++ paramArgs,
-      description = Some("fetch edges"),
-      resolve = { c =>
+    val serviceColumnField: Field[GraphRepository, Any] =
+      Field(column.columnName.toValidName, labelColumnType, resolve = c => {
         implicit val ec = c.ctx.ec
+        val vertexQueryParam = FieldResolver.serviceColumnOnLabel(c)
 
-        val edgeQueryParam = graphql.types.FieldResolver.label(label, c)
-        val empty = Seq.empty[S2EdgeLike]
+        DeferredValue(GraphRepository.vertexFetcher.defer(vertexQueryParam)).map(m => m._2.head)
+      })
 
-        DeferredValue(GraphRepository.edgeFetcher.deferOpt(edgeQueryParam)).map(m => m.fold(empty)(_._2))
-      }
-    )
-
-    edgeTypeField
+    List(serviceColumnField, labelPropField) ++ labelFields.filterNot(_.name.toValidName == column.columnName.toValidName)
   }
 }
 
@@ -229,26 +286,35 @@
 
   import S2Type._
   import org.apache.s2graph.graphql.bind.Unmarshaller._
-
-  implicit val graphRepository = repo
+  import scala.collection._
 
   /**
     * fields
     */
-  lazy val serviceFields: List[Field[GraphRepository, Any]] = repo.services().map { service =>
-    lazy val serviceFields = DummyObjectTypeField :: makeServiceField(service, repo.labels())
+  val serviceFields: List[Field[GraphRepository, Any]] = {
+    val allColumns = repo.serviceColumns()
+    val allLabels = repo.labels()
 
-    lazy val ServiceType = ObjectType(
-      s"Service_${service.serviceName.toValidName}",
-      fields[GraphRepository, Any](serviceFields: _*)
-    )
+    val typeCache = mutable.Map.empty[String, ObjectType[GraphRepository, Any]]
 
-    Field(
-      service.serviceName.toValidName,
-      ServiceType,
-      description = Some(s"serviceName: ${service.serviceName}"),
-      resolve = _ => service
-    ): Field[GraphRepository, Any]
+    repo.services().flatMap { service =>
+      val relatedColumns = allColumns.filter(_.service == service).toSet
+      val relatedLabels = allLabels.filter(l => relatedColumns(l.srcColumn) || relatedColumns(l.tgtColumn))
+
+      if (relatedColumns.isEmpty) Nil
+      else {
+        val ServiceType = makeServiceType(service, relatedColumns.toVector, relatedLabels.distinct)(typeCache)
+
+        val f = Field(
+          service.serviceName.toValidName,
+          ServiceType,
+          description = Some(s"serviceName: ${service.serviceName}"),
+          resolve = _ => service
+        ): Field[GraphRepository, Any]
+
+        List(f)
+      }
+    }
   }
 
   /**
@@ -287,7 +353,7 @@
     * Provide s2graph query / mutate API
     * - Fields is created(or changed) for metadata is changed.
     */
-  lazy val queryFields = serviceFields
+  val queryFields = serviceFields
 
   lazy val mutationFields: List[Field[GraphRepository, Any]] = List(
     Field("addVertex",
diff --git a/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/SchemaDef.scala b/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/SchemaDef.scala
index 7451023..d094ee0 100644
--- a/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/SchemaDef.scala
+++ b/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/SchemaDef.scala
@@ -26,7 +26,7 @@
   *
   * When a Label or Service is created, the GraphQL schema is created dynamically.
   */
-class SchemaDef(g: GraphRepository) {
+class SchemaDef(g: GraphRepository, withAdmin: Boolean = false) {
 
   import sangria.schema._
 
@@ -39,17 +39,24 @@
     fields(s2Type.queryFields ++ queryManagementFields: _*)
   )
 
-  val mutateManagementFields = List(wrapField("MutationManagement", "Management", s2ManagementType.mutationFields))
-  val S2MutationType = ObjectType[GraphRepository, Any](
-    "Mutation",
-    fields(s2Type.mutationFields ++ mutateManagementFields: _*)
-  )
+  lazy val mutateManagementFields = List(wrapField("MutationManagement", "Management", s2ManagementType.mutationFields))
+
+  val S2MutationType =
+    if (!withAdmin) None
+    else {
+      val mutationTpe = ObjectType[GraphRepository, Any](
+        "Mutation",
+        fields(s2Type.mutationFields ++ mutateManagementFields: _*)
+      )
+
+      Option(mutationTpe)
+    }
 
   val directives = S2Directive.Transform :: BuiltinDirectives
 
   private val s2Schema = Schema(
     S2QueryType,
-    Option(S2MutationType),
+    S2MutationType,
     directives = directives
   )