You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@s2graph.apache.org by st...@apache.org on 2017/07/31 01:05:27 UTC
[13/25] incubator-s2graph git commit: add basic test for
IndexProvider.
add basic test for IndexProvider.
Project: http://git-wip-us.apache.org/repos/asf/incubator-s2graph/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-s2graph/commit/b639996b
Tree: http://git-wip-us.apache.org/repos/asf/incubator-s2graph/tree/b639996b
Diff: http://git-wip-us.apache.org/repos/asf/incubator-s2graph/diff/b639996b
Branch: refs/heads/master
Commit: b639996bf196034fd6bcecc622fd5b12ed61b60a
Parents: 33ed1d8
Author: DO YUNG YOON <st...@apache.org>
Authored: Thu Jul 27 20:06:18 2017 +0900
Committer: DO YUNG YOON <st...@apache.org>
Committed: Thu Jul 27 20:06:18 2017 +0900
----------------------------------------------------------------------
dev_support/graph_mysql/schema.sql | 14 +
.../core/io/tinkerpop/optimize/S2GraphStep.java | 6 +-
.../org/apache/s2graph/core/mysqls/schema.sql | 35 +--
.../org/apache/s2graph/core/Management.scala | 9 +
.../scala/org/apache/s2graph/core/S2Graph.scala | 20 +-
.../org/apache/s2graph/core/S2Vertex.scala | 42 ---
.../s2graph/core/index/IndexProvider.scala | 266 ++++++++++++++-----
.../s2graph/core/mysqls/GlobalIndex.scala | 62 +++++
.../apache/s2graph/core/mysqls/LabelIndex.scala | 55 +++-
.../core/Integrate/LabelIndexOptionTest.scala | 144 ----------
.../LabelLabelIndexMutateOptionTest.scala | 144 ++++++++++
.../s2graph/core/index/IndexProviderTest.scala | 73 ++++-
.../s2graph/core/models/GlobalIndexTest.scala | 59 ++++
.../core/tinkerpop/S2GraphProvider.scala | 224 ++++++++++------
.../core/tinkerpop/structure/S2GraphTest.scala | 67 ++---
15 files changed, 799 insertions(+), 421 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/b639996b/dev_support/graph_mysql/schema.sql
----------------------------------------------------------------------
diff --git a/dev_support/graph_mysql/schema.sql b/dev_support/graph_mysql/schema.sql
index 047f8b2..58c4328 100644
--- a/dev_support/graph_mysql/schema.sql
+++ b/dev_support/graph_mysql/schema.sql
@@ -121,6 +121,20 @@ CREATE TABLE `labels` (
ALTER TABLE labels add FOREIGN KEY(service_id) REFERENCES services(id);
+-- ----------------------------
+-- Table structure for `global_index`
+-- ----------------------------
+DROP TABLE IF EXISTS `global_indices`;
+CREATE TABLE `global_indices` (
+ `id` integer NOT NULL AUTO_INCREMENT,
+ `prop_names` varchar(255) NOT NULL,
+ `index_name` varchar(64) NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `ux_global_index_index_name` (`index_name`),
+ UNIQUE KEY `ux_global_index_prop_names` (`prop_names`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+
+
-- ----------------------------
-- Table structure for `label_metas`
http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/b639996b/s2core/src/main/java/org/apache/s2graph/core/io/tinkerpop/optimize/S2GraphStep.java
----------------------------------------------------------------------
diff --git a/s2core/src/main/java/org/apache/s2graph/core/io/tinkerpop/optimize/S2GraphStep.java b/s2core/src/main/java/org/apache/s2graph/core/io/tinkerpop/optimize/S2GraphStep.java
index 783f9b5..6773d94 100644
--- a/s2core/src/main/java/org/apache/s2graph/core/io/tinkerpop/optimize/S2GraphStep.java
+++ b/s2core/src/main/java/org/apache/s2graph/core/io/tinkerpop/optimize/S2GraphStep.java
@@ -86,18 +86,16 @@ public class S2GraphStep<S, E extends Element> extends GraphStep<S, E> {
if (hasContainers.isEmpty()) {
return (Iterator) (isVertex ? graph.vertices() : graph.edges());
} else {
- String queryString = IndexProvider$.MODULE$.buildQueryString(hasContainers);
-
List<VertexId> vids = new ArrayList<>();
List<EdgeId> eids = new ArrayList<>();
if (isVertex) {
- List<VertexId> ids = graph.indexProvider().fetchVertexIds(queryString);
+ List<VertexId> ids = graph.indexProvider().fetchVertexIds(hasContainers);
if (ids.isEmpty()) return (Iterator) graph.vertices();
else return (Iterator) graph.vertices(ids.toArray());
}
else {
- List<EdgeId> ids = graph.indexProvider().fetchEdgeIds(queryString);
+ List<EdgeId> ids = graph.indexProvider().fetchEdgeIds(hasContainers);
if (ids.isEmpty()) return (Iterator) graph.edges();
else return (Iterator) graph.edges(ids.toArray());
}
http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/b639996b/s2core/src/main/resources/org/apache/s2graph/core/mysqls/schema.sql
----------------------------------------------------------------------
diff --git a/s2core/src/main/resources/org/apache/s2graph/core/mysqls/schema.sql b/s2core/src/main/resources/org/apache/s2graph/core/mysqls/schema.sql
index 51efd0b..521c9d2 100644
--- a/s2core/src/main/resources/org/apache/s2graph/core/mysqls/schema.sql
+++ b/s2core/src/main/resources/org/apache/s2graph/core/mysqls/schema.sql
@@ -109,6 +109,18 @@ CREATE TABLE `labels` (
ALTER TABLE labels add FOREIGN KEY(service_id) REFERENCES services(id);
+-- ----------------------------
+-- Table structure for `global_index`
+-- ----------------------------
+DROP TABLE IF EXISTS `global_indices`;
+CREATE TABLE `global_indices` (
+ `id` integer NOT NULL AUTO_INCREMENT,
+ `prop_names` varchar(255) NOT NULL,
+ `index_name` varchar(64) NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `ux_global_index_index_name` (`index_name`),
+ UNIQUE KEY `ux_global_index_prop_names` (`prop_names`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ----------------------------
@@ -153,29 +165,6 @@ CREATE TABLE `label_indices` (
ALTER TABLE label_indices ADD FOREIGN KEY(label_id) REFERENCES labels(id) ON DELETE CASCADE;
-
--- ----------------------------
--- Table structure for `service_column_indices`
--- ----------------------------
-DROP TABLE IF EXISTS `service_column_indices`;
-CREATE TABLE `service_column_indices` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `service_id` int(11) NOT NULL,
- `service_column_id` int(11) NOT NULL,
- `name` varchar(64) NOT NULL DEFAULT '_PK',
- `seq` tinyint(4) NOT NULL,
- `meta_seqs` varchar(64) NOT NULL,
- `options` text,
- PRIMARY KEY (`id`),
- UNIQUE KEY `ux_service_id_service_column_id_seq` (`service_id`,`service_column_id`,`seq`),
- UNIQUE KEY `ux_service_id_service_column_id_name` (`service_id`, `service_column_id`,`name`),
- UNIQUE KEY `ux_service_id_service_column_id_seqs` (`service_id`, `service_column_id`,`meta_seqs`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-
-ALTER TABLE service_column_indices ADD FOREIGN KEY(service_id) REFERENCES services(id) ON DELETE CASCADE;
-ALTER TABLE service_column_indices ADD FOREIGN KEY(service_column_id) REFERENCES service_columns(id) ON DELETE CASCADE;
-
-
-- ----------------------------
-- Table structure for `experiments`
-- ----------------------------
http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/b639996b/s2core/src/main/scala/org/apache/s2graph/core/Management.scala
----------------------------------------------------------------------
diff --git a/s2core/src/main/scala/org/apache/s2graph/core/Management.scala b/s2core/src/main/scala/org/apache/s2graph/core/Management.scala
index 63a1727..6713baf 100644
--- a/s2core/src/main/scala/org/apache/s2graph/core/Management.scala
+++ b/s2core/src/main/scala/org/apache/s2graph/core/Management.scala
@@ -348,6 +348,15 @@ class Management(graph: S2Graph) {
old.consistencyLevel, hTableName, old.hTableTTL, old.schemaVersion, old.isAsync, old.compressionAlgorithm, old.options)
}
+ def buildGlobalIndex(name: String, propNames: Seq[String]): GlobalIndex = {
+ GlobalIndex.findBy(name) match {
+ case None =>
+ val idxId = GlobalIndex.insert(name, propNames)
+ GlobalIndex.findBy(name).get
+ case Some(oldIndex) => oldIndex
+ }
+ }
+
def getCurrentStorageInfo(labelName: String): Try[Map[String, String]] = for {
label <- Try(Label.findByName(labelName, useCache = false).get)
} yield {
http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/b639996b/s2core/src/main/scala/org/apache/s2graph/core/S2Graph.scala
----------------------------------------------------------------------
diff --git a/s2core/src/main/scala/org/apache/s2graph/core/S2Graph.scala b/s2core/src/main/scala/org/apache/s2graph/core/S2Graph.scala
index 318c092..3b0a11c 100644
--- a/s2core/src/main/scala/org/apache/s2graph/core/S2Graph.scala
+++ b/s2core/src/main/scala/org/apache/s2graph/core/S2Graph.scala
@@ -67,8 +67,10 @@ object S2Graph {
"hbase.table.name" -> "s2graph",
"hbase.table.compression.algorithm" -> "gz",
"phase" -> "dev",
- "db.default.driver" -> "org.h2.Driver",
- "db.default.url" -> "jdbc:h2:file:./var/metastore;MODE=MYSQL",
+// "db.default.driver" -> "org.h2.Driver",
+// "db.default.url" -> "jdbc:h2:file:./var/metastore;MODE=MYSQL",
+ "db.default.driver" -> "com.mysql.jdbc.Driver",
+ "db.default.url" -> "jdbc:mysql://default:3306/graph_dev",
"db.default.password" -> "graph",
"db.default.user" -> "graph",
"cache.max.size" -> java.lang.Integer.valueOf(0),
@@ -1826,7 +1828,6 @@ class S2Graph(_config: Config)(implicit val ec: ExecutionContext) extends Graph
}
addVertexInner(vertex)
- indexProvider.mutateVertices(Seq(vertex))
vertex
}
@@ -1848,15 +1849,17 @@ class S2Graph(_config: Config)(implicit val ec: ExecutionContext) extends Graph
}
def addVertexInner(vertex: S2Vertex): S2Vertex = {
- val future = mutateVertices(Seq(vertex), withWait = true).map { rets =>
- if (rets.forall(identity)) vertex
- else throw new RuntimeException("addVertex failed.")
+ val future = mutateVertices(Seq(vertex), withWait = true).flatMap { rets =>
+ if (rets.forall(identity)) {
+ indexProvider.mutateVerticesAsync(Seq(vertex))
+ } else throw new RuntimeException("addVertex failed.")
}
Await.ready(future, WaitTimeout)
vertex
}
+ /* tp3 only */
def addEdge(srcVertex: S2Vertex, labelName: String, tgtVertex: Vertex, kvs: AnyRef*): Edge = {
val containsId = kvs.contains(T.id)
@@ -1884,10 +1887,11 @@ class S2Graph(_config: Config)(implicit val ec: ExecutionContext) extends Graph
val edge = newEdge(srcVertex, otherV, label, dir, op = op, version = ts, propsWithTs = propsWithTs)
- val future = mutateEdges(Seq(edge), withWait = true)
+ val future = mutateEdges(Seq(edge), withWait = true).flatMap { rets =>
+ indexProvider.mutateEdgesAsync(Seq(edge))
+ }
Await.ready(future, WaitTimeout)
- indexProvider.mutateEdges(Seq(edge))
edge
} catch {
case e: LabelNotExistException => throw new java.lang.IllegalArgumentException(e)
http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/b639996b/s2core/src/main/scala/org/apache/s2graph/core/S2Vertex.scala
----------------------------------------------------------------------
diff --git a/s2core/src/main/scala/org/apache/s2graph/core/S2Vertex.scala b/s2core/src/main/scala/org/apache/s2graph/core/S2Vertex.scala
index d485a01..c0dc23b 100644
--- a/s2core/src/main/scala/org/apache/s2graph/core/S2Vertex.scala
+++ b/s2core/src/main/scala/org/apache/s2graph/core/S2Vertex.scala
@@ -201,48 +201,6 @@ case class S2Vertex(graph: S2Graph,
override def addEdge(labelName: String, vertex: Vertex, kvs: AnyRef*): Edge = {
graph.addEdge(this, labelName, vertex, kvs: _*)
-// val containsId = kvs.contains(T.id)
-// vertex match {
-// case otherV: S2Vertex =>
-// if (!graph.features().edge().supportsUserSuppliedIds() && containsId) {
-// throw Exceptions.userSuppliedIdsNotSupported()
-// }
-//
-// val props = S2Property.kvsToProps(kvs)
-//
-// props.foreach { case (k, v) => S2Property.assertValidProp(k, v) }
-//
-// //TODO: direction, operation, _timestamp need to be reserved property key.
-//
-// try {
-// val direction = props.get("direction").getOrElse("out").toString
-// val ts = props.get(LabelMeta.timestamp.name).map(_.toString.toLong).getOrElse(System.currentTimeMillis())
-// val operation = props.get("operation").map(_.toString).getOrElse("insert")
-// val label = Label.findByName(labelName).getOrElse(throw new LabelNotExistException(labelName))
-// val dir = GraphUtil.toDir(direction).getOrElse(throw new RuntimeException(s"$direction is not supported."))
-// val propsPlusTs = props ++ Map(LabelMeta.timestamp.name -> ts)
-// val propsWithTs = label.propsToInnerValsWithTs(propsPlusTs, ts)
-// val op = GraphUtil.toOp(operation).getOrElse(throw new RuntimeException(s"$operation is not supported."))
-//
-// val edge = graph.newEdge(this, otherV, label, dir, op = op, version = ts, propsWithTs = propsWithTs)
-//// //TODO: return type of mutateEdges can contains information if snapshot edge already exist.
-//// // instead call checkEdges, we can exploit this feature once we refactor return type.
-//// implicit val ec = graph.ec
-//// val future = graph.checkEdges(Seq(edge)).flatMap { stepResult =>
-//// if (stepResult.edgeWithScores.nonEmpty)
-//// Future.failed(throw Graph.Exceptions.edgeWithIdAlreadyExists(edge.id()))
-//// else
-//// graph.mutateEdges(Seq(edge), withWait = true)
-//// }
-// val future = graph.mutateEdges(Seq(edge), withWait = true)
-// Await.ready(future, graph.WaitTimeout)
-// edge
-// } catch {
-// case e: LabelNotExistException => throw new java.lang.IllegalArgumentException(e)
-// }
-// case null => throw new java.lang.IllegalArgumentException
-// case _ => throw new RuntimeException("only S2Graph vertex can be used.")
-// }
}
override def property[V](key: String): VertexProperty[V] = {
http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/b639996b/s2core/src/main/scala/org/apache/s2graph/core/index/IndexProvider.scala
----------------------------------------------------------------------
diff --git a/s2core/src/main/scala/org/apache/s2graph/core/index/IndexProvider.scala b/s2core/src/main/scala/org/apache/s2graph/core/index/IndexProvider.scala
index ed97ed9..e3ab7bc 100644
--- a/s2core/src/main/scala/org/apache/s2graph/core/index/IndexProvider.scala
+++ b/s2core/src/main/scala/org/apache/s2graph/core/index/IndexProvider.scala
@@ -6,9 +6,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -23,17 +23,19 @@ import java.util
import com.typesafe.config.Config
import org.apache.lucene.analysis.standard.StandardAnalyzer
-import org.apache.lucene.document.{Document, Field, StringField, TextField}
+import org.apache.lucene.document._
import org.apache.lucene.index.{DirectoryReader, IndexWriter, IndexWriterConfig}
import org.apache.lucene.queryparser.classic.{ParseException, QueryParser}
import org.apache.lucene.search.IndexSearcher
-import org.apache.lucene.store.RAMDirectory
+import org.apache.lucene.store.{BaseDirectory, RAMDirectory}
import org.apache.s2graph.core.io.Conversions
import org.apache.s2graph.core.{EdgeId, S2Edge, S2Vertex}
import org.apache.s2graph.core.mysqls._
import org.apache.s2graph.core.types.{InnerValLike, VertexId}
import org.apache.s2graph.core.utils.logger
+import org.apache.tinkerpop.gremlin.process.traversal.{Compare, Contains, P}
import org.apache.tinkerpop.gremlin.process.traversal.step.util.HasContainer
+import org.apache.tinkerpop.gremlin.process.traversal.util.{AndP, OrP}
import play.api.libs.json.Json
import scala.concurrent.Future
@@ -41,6 +43,9 @@ import scala.concurrent.Future
object IndexProvider {
val vidField = "_vid_"
val eidField = "_eid_"
+ val labelField = "_label_"
+ val serviceField = "_service_"
+ val serviceColumnField = "_serviceColumn_"
def apply(config: Config): IndexProvider = {
val indexProviderType = "lucene"
@@ -51,22 +56,63 @@ object IndexProvider {
}
}
- def buildQueryString(hasContainers: java.util.List[HasContainer]): String = {
+ def buildQuerySingleString(container: HasContainer): String = {
import scala.collection.JavaConversions._
- hasContainers.map { container =>
- container.getKey + ":" + container.getValue
- }.mkString(" AND ")
+
+ val key = container.getKey
+ val value = container.getValue
+
+ val biPredicate = container.getBiPredicate
+
+ biPredicate match {
+ case Contains.within =>
+ key + ":(" + value.asInstanceOf[util.Collection[_]].toSeq.mkString(" OR ") + ")"
+ case Contains.without =>
+ key + ":NOT (" + value.asInstanceOf[util.Collection[_]].toSeq.mkString(" AND ") + ")"
+ case Compare.eq => s"${key}:${value}"
+ case Compare.gte => s"${key}:[${value} TO *] AND NOT ${key}:${value}"
+ case Compare.gt => s"${key}:[${value} TO *]"
+ case Compare.lte => s"${key}:[* TO ${value}]"
+ case Compare.lt => s"${key}:[* TO ${value}] AND NOT ${key}:${value}"
+ case Compare.neq => s"NOT ${key}:${value}"
+ case _ => throw new IllegalArgumentException("not supported yet.")
+ }
}
+ def buildQueryString(hasContainers: java.util.List[HasContainer]): String = {
+ import scala.collection.JavaConversions._
+ val builder = scala.collection.mutable.ArrayBuffer.empty[String]
+
+ hasContainers.foreach { container =>
+ container.getPredicate match {
+ case and: AndP[_] =>
+ val buffer = scala.collection.mutable.ArrayBuffer.empty[String]
+ and.getPredicates.foreach { p =>
+ buffer.append(buildQuerySingleString(new HasContainer(container.getKey, p)))
+ }
+ builder.append(buffer.mkString("(", " AND ", ")"))
+ case or: OrP[_] =>
+ val buffer = scala.collection.mutable.ArrayBuffer.empty[String]
+ or.getPredicates.foreach { p =>
+ buffer.append(buildQuerySingleString(new HasContainer(container.getKey, p)))
+ }
+ builder.append(buffer.mkString("(", " OR ", ")"))
+ case _ =>
+ builder.append(buildQuerySingleString(container))
+ }
+ }
+
+ builder.mkString(" AND ")
+ }
}
trait IndexProvider {
//TODO: Seq nee do be changed into stream
- def fetchEdgeIds(queryString: String): java.util.List[EdgeId]
- def fetchEdgeIdsAsync(queryString: String): Future[java.util.List[EdgeId]]
+ def fetchEdgeIds(hasContainers: java.util.List[HasContainer]): java.util.List[EdgeId]
+ def fetchEdgeIdsAsync(hasContainers: java.util.List[HasContainer]): Future[java.util.List[EdgeId]]
- def fetchVertexIds(queryString: String): java.util.List[VertexId]
- def fetchVertexIdsAsync(queryString: String): Future[java.util.List[VertexId]]
+ def fetchVertexIds(hasContainers: java.util.List[HasContainer]): java.util.List[VertexId]
+ def fetchVertexIdsAsync(hasContainers: java.util.List[HasContainer]): Future[java.util.List[VertexId]]
def mutateVertices(vertices: Seq[S2Vertex]): Seq[Boolean]
def mutateVerticesAsync(vertices: Seq[S2Vertex]): Future[Seq[Boolean]]
@@ -79,101 +125,179 @@ trait IndexProvider {
class LuceneIndexProvider(config: Config) extends IndexProvider {
import IndexProvider._
+ import scala.collection.mutable
+ import scala.collection.JavaConverters._
val analyzer = new StandardAnalyzer()
- val directory = new RAMDirectory()
- val indexConfig = new IndexWriterConfig(analyzer)
- val writer = new IndexWriter(directory, indexConfig)
+ val writers = mutable.Map.empty[String, IndexWriter]
+ val directories = mutable.Map.empty[String, BaseDirectory]
+
+ private def getOrElseCreateIndexWriter(indexName: String): IndexWriter = {
+ writers.getOrElseUpdate(indexName, {
+ val dir = directories.getOrElseUpdate(indexName, new RAMDirectory())
+ val indexConfig = new IndexWriterConfig(analyzer)
+ new IndexWriter(dir, indexConfig)
+ })
+ }
- override def mutateVertices(vertices: Seq[S2Vertex]): Seq[Boolean] = {
- vertices.map { vertex =>
+ private def toDocument(globalIndex: GlobalIndex, vertex: S2Vertex): Option[Document] = {
+ val props = vertex.props.asScala
+ val exist = props.exists(t => globalIndex.propNamesSet(t._1))
+ if (!exist) None
+ else {
val doc = new Document()
- val id = vertex.id.toString()
- doc.add(new StringField(vidField, id, Field.Store.YES))
+ val id = vertex.id.toString
- vertex.properties.foreach { case (dim, value) =>
- doc.add(new TextField(dim, value.toString, Field.Store.YES))
+ doc.add(new StringField(vidField, id, Field.Store.YES))
+ doc.add(new StringField(serviceField, vertex.serviceName, Field.Store.YES))
+ doc.add(new StringField(serviceColumnField, vertex.columnName, Field.Store.YES))
+
+ props.foreach { case (dim, s2VertexProperty) =>
+ val shouldIndex = if (globalIndex.propNamesSet(dim)) Field.Store.YES else Field.Store.NO
+ val field = s2VertexProperty.columnMeta.dataType match {
+ case "string" => new StringField(dim, s2VertexProperty.innerVal.value.toString, shouldIndex)
+ case _ => new StringField(dim, s2VertexProperty.innerVal.value.toString, shouldIndex)
+ }
+ doc.add(field)
}
- writer.addDocument(doc)
+
+ Option(doc)
}
- writer.commit()
- vertices.map(_ => true)
}
- override def mutateEdges(edges: Seq[S2Edge]): Seq[Boolean] = {
- edges.map { edge =>
+ private def toDocument(globalIndex: GlobalIndex, edge: S2Edge): Option[Document] = {
+ val props = edge.propsWithTs.asScala
+ val exist = props.exists(t => globalIndex.propNamesSet(t._1))
+ if (!exist) None
+ else {
val doc = new Document()
val id = edge.edgeId.toString
+
doc.add(new StringField(eidField, id, Field.Store.YES))
+ doc.add(new StringField(serviceField, edge.serviceName, Field.Store.YES))
+ doc.add(new StringField(labelField, edge.label(), Field.Store.YES))
+
+ props.foreach { case (dim, s2Property) =>
+ val shouldIndex = if (globalIndex.propNamesSet(dim)) Field.Store.YES else Field.Store.NO
+ val field = s2Property.labelMeta.dataType match {
+ case "string" => new StringField(dim, s2Property.innerVal.value.toString, shouldIndex)
+ case _ => new StringField(dim, s2Property.innerVal.value.toString, shouldIndex)
+ }
+ doc.add(field)
+ }
+
+ Option(doc)
+ }
+ }
+
+ override def mutateVertices(vertices: Seq[S2Vertex]): Seq[Boolean] = {
+ val globalIndexOptions = GlobalIndex.findAll()
+
+ globalIndexOptions.map { globalIndex =>
+ val writer = getOrElseCreateIndexWriter(globalIndex.indexName)
- edge.properties.foreach { case (dim, value) =>
- doc.add(new TextField(dim, value.toString, Field.Store.YES))
+ vertices.foreach { vertex =>
+ toDocument(globalIndex, vertex).foreach { doc =>
+ writer.addDocument(doc)
+ }
}
- writer.addDocument(doc)
+
+ writer.commit()
}
- writer.commit()
+
+ vertices.map(_ => true)
+ }
+
+ override def mutateEdges(edges: Seq[S2Edge]): Seq[Boolean] = {
+ val globalIndexOptions = GlobalIndex.findAll()
+
+ globalIndexOptions.map { globalIndex =>
+ val writer = getOrElseCreateIndexWriter(globalIndex.indexName)
+
+ edges.foreach { edge =>
+ toDocument(globalIndex, edge).foreach { doc =>
+ writer.addDocument(doc)
+ }
+ }
+
+ writer.commit()
+ }
+
edges.map(_ => true)
}
- override def fetchEdgeIds(queryString: String): java.util.List[EdgeId] = {
+ override def fetchEdgeIds(hasContainers: java.util.List[HasContainer]): java.util.List[EdgeId] = {
val field = eidField
val ids = new java.util.ArrayList[EdgeId]
- try {
- val q = new QueryParser(field, analyzer).parse(queryString)
- val hitsPerPage = 10
- val reader = DirectoryReader.open(directory)
- val searcher = new IndexSearcher(reader)
-
- val docs = searcher.search(q, hitsPerPage)
-
- docs.scoreDocs.foreach { scoreDoc =>
- val document = searcher.doc(scoreDoc.doc)
- val id = Conversions.s2EdgeIdReads.reads(Json.parse(document.get(field))).get
- ids.add(id);
- }
- reader.close()
- ids
- } catch {
- case ex: ParseException =>
- logger.error(s"[IndexProvider]: ${queryString} parse failed.", ex)
+ GlobalIndex.findGlobalIndex(hasContainers).map { globalIndex =>
+ val queryString = buildQueryString(hasContainers)
+
+ try {
+ val q = new QueryParser(field, analyzer).parse(queryString)
+ val hitsPerPage = 10
+ val reader = DirectoryReader.open(directories(globalIndex.indexName))
+ val searcher = new IndexSearcher(reader)
+
+ val docs = searcher.search(q, hitsPerPage)
+
+ docs.scoreDocs.foreach { scoreDoc =>
+ val document = searcher.doc(scoreDoc.doc)
+ val id = Conversions.s2EdgeIdReads.reads(Json.parse(document.get(field))).get
+ ids.add(id);
+ }
+
+ reader.close()
ids
+ } catch {
+ case ex: ParseException =>
+ logger.error(s"[IndexProvider]: ${queryString} parse failed.", ex)
+ ids
+ }
}
+ ids
}
- override def fetchVertexIds(queryString: String): java.util.List[VertexId] = {
+ override def fetchVertexIds(hasContainers: java.util.List[HasContainer]): java.util.List[VertexId] = {
val field = vidField
val ids = new java.util.ArrayList[VertexId]
- try {
- val q = new QueryParser(field, analyzer).parse(queryString)
- val hitsPerPage = 10
- val reader = DirectoryReader.open(directory)
- val searcher = new IndexSearcher(reader)
-
- val docs = searcher.search(q, hitsPerPage)
-
- docs.scoreDocs.foreach { scoreDoc =>
- val document = searcher.doc(scoreDoc.doc)
- val id = Conversions.s2VertexIdReads.reads(Json.parse(document.get(field))).get
- ids.add(id)
- }
+ GlobalIndex.findGlobalIndex(hasContainers).map { globalIndex =>
+ val queryString = buildQueryString(hasContainers)
- reader.close()
- ids
- } catch {
- case ex: ParseException =>
- logger.error(s"[IndexProvider]: ${queryString} parse failed.", ex)
+ try {
+ val q = new QueryParser(field, analyzer).parse(queryString)
+ val hitsPerPage = 10
+ val reader = DirectoryReader.open(directories(globalIndex.indexName))
+ val searcher = new IndexSearcher(reader)
+
+ val docs = searcher.search(q, hitsPerPage)
+
+ docs.scoreDocs.foreach { scoreDoc =>
+ val document = searcher.doc(scoreDoc.doc)
+ val id = Conversions.s2VertexIdReads.reads(Json.parse(document.get(field))).get
+ ids.add(id)
+ }
+
+ reader.close()
ids
+ } catch {
+ case ex: ParseException =>
+ logger.error(s"[IndexProvider]: ${queryString} parse failed.", ex)
+ ids
+ }
}
+
+ ids
}
+
override def shutdown(): Unit = {
- writer.close()
+ writers.foreach { case (_, writer) => writer.close() }
}
- override def fetchEdgeIdsAsync(queryString: String): Future[util.List[EdgeId]] = Future.successful(fetchEdgeIds(queryString))
+ override def fetchEdgeIdsAsync(hasContainers: java.util.List[HasContainer]): Future[util.List[EdgeId]] = Future.successful(fetchEdgeIds(hasContainers))
- override def fetchVertexIdsAsync(queryString: String): Future[util.List[VertexId]] = Future.successful(fetchVertexIds(queryString))
+ override def fetchVertexIdsAsync(hasContainers: java.util.List[HasContainer]): Future[util.List[VertexId]] = Future.successful(fetchVertexIds(hasContainers))
override def mutateVerticesAsync(vertices: Seq[S2Vertex]): Future[Seq[Boolean]] = Future.successful(mutateVertices(vertices))
http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/b639996b/s2core/src/main/scala/org/apache/s2graph/core/mysqls/GlobalIndex.scala
----------------------------------------------------------------------
diff --git a/s2core/src/main/scala/org/apache/s2graph/core/mysqls/GlobalIndex.scala b/s2core/src/main/scala/org/apache/s2graph/core/mysqls/GlobalIndex.scala
new file mode 100644
index 0000000..69323b7
--- /dev/null
+++ b/s2core/src/main/scala/org/apache/s2graph/core/mysqls/GlobalIndex.scala
@@ -0,0 +1,62 @@
+package org.apache.s2graph.core.mysqls
+
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.HasContainer
+import scalikejdbc.{AutoSession, DBSession, WrappedResultSet}
+import scalikejdbc._
+
+object GlobalIndex extends Model[GlobalIndex] {
+ import org.apache.s2graph.core.index.IndexProvider._
+
+ val DefaultIndexName = GlobalIndex(None, Seq(vidField, eidField, serviceField, serviceColumnField, labelField), "_default_")
+
+ val TableName = "global_indices"
+
+ def apply(rs: WrappedResultSet): GlobalIndex = {
+ GlobalIndex(rs.intOpt("id"), rs.string("prop_names").split(",").sorted, rs.string("index_name"))
+ }
+
+ def findBy(indexName: String, useCache: Boolean = true)(implicit session: DBSession = AutoSession): Option[GlobalIndex] = {
+ val cacheKey = s"indexName=$indexName"
+ lazy val sql = sql"""select * from global_indices where index_name = $indexName""".map { rs => GlobalIndex(rs) }.single.apply()
+ if (useCache) withCache(cacheKey){sql}
+ else sql
+ }
+
+ def insert(indexName: String, propNames: Seq[String])(implicit session: DBSession = AutoSession): Long = {
+ sql"""insert into global_indices(prop_names, index_name) values(${propNames.sorted.mkString(",")}, $indexName)"""
+ .updateAndReturnGeneratedKey.apply()
+ }
+
+ def findAll(useCache: Boolean = true)(implicit session: DBSession = AutoSession): Seq[GlobalIndex] = {
+ lazy val ls = sql"""select * from global_indices """.map { rs => GlobalIndex(rs) }.list.apply
+ if (useCache) {
+ listCache.withCache("findAll") {
+ putsToCache(ls.map { globalIndex =>
+ val cacheKey = s"indexName=${globalIndex.indexName}"
+ cacheKey -> globalIndex
+ })
+ ls
+ }
+ } else {
+ ls
+ }
+ }
+
+ def findGlobalIndex(hasContainers: java.util.List[HasContainer])(implicit session: DBSession = AutoSession): Option[GlobalIndex] = {
+ import scala.collection.JavaConversions._
+ val indices = findAll(useCache = true)
+ val keys = hasContainers.map(_.getKey)
+
+ val sorted = indices.map { index =>
+ val matched = keys.filter(index.propNamesSet)
+ index -> matched.length
+ }.filter(_._2 > 0).sortBy(_._2 * -1)
+
+ sorted.headOption.map(_._1)
+ }
+
+}
+
+case class GlobalIndex(id: Option[Int], propNames: Seq[String], indexName: String) {
+ lazy val propNamesSet = propNames.toSet
+}
http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/b639996b/s2core/src/main/scala/org/apache/s2graph/core/mysqls/LabelIndex.scala
----------------------------------------------------------------------
diff --git a/s2core/src/main/scala/org/apache/s2graph/core/mysqls/LabelIndex.scala b/s2core/src/main/scala/org/apache/s2graph/core/mysqls/LabelIndex.scala
index e82e502..1da0e55 100644
--- a/s2core/src/main/scala/org/apache/s2graph/core/mysqls/LabelIndex.scala
+++ b/s2core/src/main/scala/org/apache/s2graph/core/mysqls/LabelIndex.scala
@@ -20,7 +20,7 @@
package org.apache.s2graph.core.mysqls
import org.apache.s2graph.core.GraphUtil
-import org.apache.s2graph.core.mysqls.LabelIndex.IndexOption
+import org.apache.s2graph.core.mysqls.LabelIndex.LabelIndexMutateOption
import org.apache.s2graph.core.utils.logger
import play.api.libs.json.{JsObject, JsString, Json}
import scalikejdbc._
@@ -42,11 +42,11 @@ object LabelIndex extends Model[LabelIndex] {
)
}
- case class IndexOption(dir: Byte,
- method: String,
- rate: Double,
- totalModular: Long,
- storeDegree: Boolean) {
+ case class LabelIndexMutateOption(dir: Byte,
+ method: String,
+ rate: Double,
+ totalModular: Long,
+ storeDegree: Boolean) {
val isBufferIncrement = method == "drop" || method == "sample" || method == "hash_sample"
@@ -169,7 +169,44 @@ object LabelIndex extends Model[LabelIndex] {
}.toList)
}
}
-
+/**
+mgmt.buildIndex('nameAndAge',Vertex.class)
+.addKey(name,Mapping.TEXT.getParameter())
+.addKey(age,Mapping.TEXT.getParameter())
+.buildMixedIndex("search")
+
+v: {name: abc} - E1: {age: 20}, E2, E3....
+
+Management.createServiceColumn(
+ serviceName = serviceName, columnName = "person", columnType = "integer",
+ props = Seq(
+ Prop("name", "-", "string"),
+ Prop("age", "0", "integer"),
+ Prop("location", "-", "string")
+ )
+)
+
+management.createLabel(
+ label = "bought",
+ srcServiceName = serviceName, srcColumnName = "person", srcColumnType = "integer",
+ tgtServiceName = serviceName, tgtColumnName = "product", tgtColumnType = "integer", idDirected = true,
+ serviceName = serviceName,
+ indices = Seq(
+ Index("PK", Seq("amount", "created_at"), IndexType("mixed", propsMapping: Map[String, String]),
+{"in": {}, "out": {}})
+ ),
+ props = Seq(
+ Prop("amount", "0.0", "double"),
+ Prop("created_at", "2000-01-01", "string")
+ ),
+ consistencyLevel = "strong"
+)
+
+mgmt.buildIndex('PK', Edge.class)
+ .addKey(amount, Double)
+ .buildCompositeIndex
+
+*/
case class LabelIndex(id: Option[Int], labelId: Int, name: String, seq: Byte, metaSeqs: Seq[Byte], formulars: String,
dir: Option[Int], options: Option[String]) {
// both
@@ -191,7 +228,7 @@ case class LabelIndex(id: Option[Int], labelId: Int, name: String, seq: Byte, me
)
}
- def parseOption(dir: String): Option[IndexOption] = try {
+ def parseOption(dir: String): Option[LabelIndexMutateOption] = try {
options.map { string =>
val jsObj = Json.parse(string) \ dir
@@ -200,7 +237,7 @@ case class LabelIndex(id: Option[Int], labelId: Int, name: String, seq: Byte, me
val totalModular = (jsObj \ "totalModular").asOpt[Long].getOrElse(100L)
val storeDegree = (jsObj \ "storeDegree").asOpt[Boolean].getOrElse(true)
- IndexOption(GraphUtil.directions(dir).toByte, method, rate, totalModular, storeDegree)
+ LabelIndexMutateOption(GraphUtil.directions(dir).toByte, method, rate, totalModular, storeDegree)
}
} catch {
case e: Exception =>
http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/b639996b/s2core/src/test/scala/org/apache/s2graph/core/Integrate/LabelIndexOptionTest.scala
----------------------------------------------------------------------
diff --git a/s2core/src/test/scala/org/apache/s2graph/core/Integrate/LabelIndexOptionTest.scala b/s2core/src/test/scala/org/apache/s2graph/core/Integrate/LabelIndexOptionTest.scala
deleted file mode 100644
index 6e213b0..0000000
--- a/s2core/src/test/scala/org/apache/s2graph/core/Integrate/LabelIndexOptionTest.scala
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.s2graph.core.Integrate
-
-import org.apache.s2graph.core._
-import org.scalatest.BeforeAndAfterEach
-import play.api.libs.json._
-
-class LabelIndexOptionTest extends IntegrateCommon with BeforeAndAfterEach {
-
- import TestUtil._
-
- // called by start test, once
- override def initTestData(): Unit = {
- super.initTestData()
-
- val insert = "insert"
- val e = "e"
- val weight = "weight"
- val is_hidden = "is_hidden"
-
- insertEdgesSync(
- toEdge(1, insert, e, 0, 1, testLabelNameLabelIndex),
- toEdge(1, insert, e, 0, 2, testLabelNameLabelIndex),
- toEdge(1, insert, e, 0, 3, testLabelNameLabelIndex)
- )
- }
-
- def getQuery(ids: Seq[Int], direction: String, indexName: String): Query =
- Query(
- vertices = ids.map(graph.toVertex(testServiceName, testColumnName, _)),
- steps = Vector(
- Step(Seq(QueryParam(testLabelNameLabelIndex, direction = direction, indexName = indexName)))
- )
- )
-
- /**
- * "indices": [
- * {"name": "$index1", "propNames": ["weight", "time", "is_hidden", "is_blocked"]},
- * {"name": "$idxStoreInDropDegree", "propNames": ["time"], "options": { "in": {"storeDegree": false }, "out": {"method": "drop", "storeDegree": false }}},
- * {"name": "$idxStoreOutDropDegree", "propNames": ["weight"], "options": { "out": {"storeDegree": false}, "in": { "method": "drop", "storeDegree": false }}},
- * {"name": "$idxStoreIn", "propNames": ["is_hidden"], "options": { "out": {"method": "drop", "storeDegree": false }}},
- * {"name": "$idxStoreOut", "propNames": ["weight", "is_blocked"], "options": { "in": {"method": "drop", "storeDegree": false }, "out": {"method": "normal" }}},
- * {"name": "$idxDropInStoreDegree", "propNames": ["is_blocked"], "options": { "in": {"method": "drop" }, "out": {"method": "drop", "storeDegree": false }}},
- * {"name": "$idxDropOutStoreDegree", "propNames": ["weight", "is_blocked", "_timestamp"], "options": { "in": {"method": "drop", "storeDegree": false }, "out": {"method": "drop"}}}
- * ],
- **/
-
- /**
- * index without no options
- */
- test("normal index should store in/out direction Edges with Degrees") {
- var edges = getEdgesSync(getQuery(Seq(0), "out", index1))
- (edges \ "results").as[Seq[JsValue]].size should be(3)
- (edges \\ "_degree").map(_.as[Long]).sum should be(3)
-
- edges = getEdgesSync(getQuery(Seq(1, 2, 3), "in", index1))
- (edges \ "results").as[Seq[JsValue]].size should be(3)
- (edges \\ "_degree").map(_.as[Long]).sum should be(3)
- }
-
- /**
- * { "out": {"method": "drop", "storeDegree": false } }
- */
- test("storeDegree: store out direction Edge and drop Degree") {
- val edges = getEdgesSync(getQuery(Seq(0), "out", idxStoreOutDropDegree))
- (edges \ "results").as[Seq[JsValue]].size should be(3)
- (edges \\ "_degree").map(_.as[Long]).sum should be(0)
- }
-
- /**
- * { "in": { "method": "drop", "storeDegree": false } }
- */
- test("storeDegree: store in direction Edge and drop Degree") {
- val edges = getEdgesSync(getQuery(Seq(1, 2, 3), "in", idxStoreInDropDegree))
- (edges \ "results").as[Seq[JsValue]].size should be(3)
- (edges \\ "_degree").map(_.as[Long]).sum should be(0)
- }
-
- /**
- * { "out": {"method": "drop", "storeDegree": false } }
- */
- test("index for in direction should drop out direction edge") {
- val edges = getEdgesSync(getQuery(Seq(0), "out", idxStoreIn))
- (edges \ "results").as[Seq[JsValue]].size should be(0)
- (edges \\ "_degree").map(_.as[Long]).sum should be(0)
- }
-
- test("index for in direction should store in direction edge") {
- val edges = getEdgesSync(getQuery(Seq(1, 2, 3), "in", idxStoreIn))
- (edges \ "results").as[Seq[JsValue]].size should be(3)
- (edges \\ "_degree").map(_.as[Long]).sum should be(3)
- }
-
- /**
- * { "in": {"method": "drop", "storeDegree": false } }
- */
- test("index for out direction should store out direction edge") {
- val edges = getEdgesSync(getQuery(Seq(0), "out", idxStoreOut))
- (edges \ "results").as[Seq[JsValue]].size should be(3)
- (edges \\ "_degree").map(_.as[Long]).sum should be(3)
- }
-
- test("index for out direction should drop in direction edge") {
- val edges = getEdgesSync(getQuery(Seq(1, 2, 3), "in", idxStoreOut))
- (edges \ "results").as[Seq[JsValue]].size should be(0)
- (edges \\ "_degree").map(_.as[Long]).sum should be(0)
- }
-
- /**
- * { "out": {"method": "drop", "storeDegree": false} }
- */
- test("index for in direction should drop in direction edge and store degree") {
- val edges = getEdgesSync(getQuery(Seq(1, 2, 3), "in", idxDropInStoreDegree))
- (edges \ "results").as[Seq[JsValue]].size should be(0)
- (edges \\ "_degree").map(_.as[Long]).sum should be(3)
- }
-
- /**
- * { "in": {"method": "drop", "storeDegree": false }, "out": {"method": "drop"} }
- */
- test("index for out direction should drop out direction edge and store degree") {
- val edges = getEdgesSync(getQuery(Seq(0), "out", idxDropOutStoreDegree))
- (edges \ "results").as[Seq[JsValue]].size should be(0)
- (edges \\ "_degree").map(_.as[Long]).sum should be(3)
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/b639996b/s2core/src/test/scala/org/apache/s2graph/core/Integrate/LabelLabelIndexMutateOptionTest.scala
----------------------------------------------------------------------
diff --git a/s2core/src/test/scala/org/apache/s2graph/core/Integrate/LabelLabelIndexMutateOptionTest.scala b/s2core/src/test/scala/org/apache/s2graph/core/Integrate/LabelLabelIndexMutateOptionTest.scala
new file mode 100644
index 0000000..4855cfc
--- /dev/null
+++ b/s2core/src/test/scala/org/apache/s2graph/core/Integrate/LabelLabelIndexMutateOptionTest.scala
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.s2graph.core.Integrate
+
+import org.apache.s2graph.core._
+import org.scalatest.BeforeAndAfterEach
+import play.api.libs.json._
+
+class LabelLabelIndexMutateOptionTest extends IntegrateCommon with BeforeAndAfterEach {
+
+ import TestUtil._
+
+ // called by start test, once
+ override def initTestData(): Unit = {
+ super.initTestData()
+
+ val insert = "insert"
+ val e = "e"
+ val weight = "weight"
+ val is_hidden = "is_hidden"
+
+ insertEdgesSync(
+ toEdge(1, insert, e, 0, 1, testLabelNameLabelIndex),
+ toEdge(1, insert, e, 0, 2, testLabelNameLabelIndex),
+ toEdge(1, insert, e, 0, 3, testLabelNameLabelIndex)
+ )
+ }
+
+ def getQuery(ids: Seq[Int], direction: String, indexName: String): Query =
+ Query(
+ vertices = ids.map(graph.toVertex(testServiceName, testColumnName, _)),
+ steps = Vector(
+ Step(Seq(QueryParam(testLabelNameLabelIndex, direction = direction, indexName = indexName)))
+ )
+ )
+
+ /**
+ * "indices": [
+ * {"name": "$index1", "propNames": ["weight", "time", "is_hidden", "is_blocked"]},
+ * {"name": "$idxStoreInDropDegree", "propNames": ["time"], "options": { "in": {"storeDegree": false }, "out": {"method": "drop", "storeDegree": false }}},
+ * {"name": "$idxStoreOutDropDegree", "propNames": ["weight"], "options": { "out": {"storeDegree": false}, "in": { "method": "drop", "storeDegree": false }}},
+ * {"name": "$idxStoreIn", "propNames": ["is_hidden"], "options": { "out": {"method": "drop", "storeDegree": false }}},
+ * {"name": "$idxStoreOut", "propNames": ["weight", "is_blocked"], "options": { "in": {"method": "drop", "storeDegree": false }, "out": {"method": "normal" }}},
+ * {"name": "$idxDropInStoreDegree", "propNames": ["is_blocked"], "options": { "in": {"method": "drop" }, "out": {"method": "drop", "storeDegree": false }}},
+ * {"name": "$idxDropOutStoreDegree", "propNames": ["weight", "is_blocked", "_timestamp"], "options": { "in": {"method": "drop", "storeDegree": false }, "out": {"method": "drop"}}}
+ * ],
+ **/
+
+ /**
+ * index without no options
+ */
+ test("normal index should store in/out direction Edges with Degrees") {
+ var edges = getEdgesSync(getQuery(Seq(0), "out", index1))
+ (edges \ "results").as[Seq[JsValue]].size should be(3)
+ (edges \\ "_degree").map(_.as[Long]).sum should be(3)
+
+ edges = getEdgesSync(getQuery(Seq(1, 2, 3), "in", index1))
+ (edges \ "results").as[Seq[JsValue]].size should be(3)
+ (edges \\ "_degree").map(_.as[Long]).sum should be(3)
+ }
+
+ /**
+ * { "out": {"method": "drop", "storeDegree": false } }
+ */
+ test("storeDegree: store out direction Edge and drop Degree") {
+ val edges = getEdgesSync(getQuery(Seq(0), "out", idxStoreOutDropDegree))
+ (edges \ "results").as[Seq[JsValue]].size should be(3)
+ (edges \\ "_degree").map(_.as[Long]).sum should be(0)
+ }
+
+ /**
+ * { "in": { "method": "drop", "storeDegree": false } }
+ */
+ test("storeDegree: store in direction Edge and drop Degree") {
+ val edges = getEdgesSync(getQuery(Seq(1, 2, 3), "in", idxStoreInDropDegree))
+ (edges \ "results").as[Seq[JsValue]].size should be(3)
+ (edges \\ "_degree").map(_.as[Long]).sum should be(0)
+ }
+
+ /**
+ * { "out": {"method": "drop", "storeDegree": false } }
+ */
+ test("index for in direction should drop out direction edge") {
+ val edges = getEdgesSync(getQuery(Seq(0), "out", idxStoreIn))
+ (edges \ "results").as[Seq[JsValue]].size should be(0)
+ (edges \\ "_degree").map(_.as[Long]).sum should be(0)
+ }
+
+ test("index for in direction should store in direction edge") {
+ val edges = getEdgesSync(getQuery(Seq(1, 2, 3), "in", idxStoreIn))
+ (edges \ "results").as[Seq[JsValue]].size should be(3)
+ (edges \\ "_degree").map(_.as[Long]).sum should be(3)
+ }
+
+ /**
+ * { "in": {"method": "drop", "storeDegree": false } }
+ */
+ test("index for out direction should store out direction edge") {
+ val edges = getEdgesSync(getQuery(Seq(0), "out", idxStoreOut))
+ (edges \ "results").as[Seq[JsValue]].size should be(3)
+ (edges \\ "_degree").map(_.as[Long]).sum should be(3)
+ }
+
+ test("index for out direction should drop in direction edge") {
+ val edges = getEdgesSync(getQuery(Seq(1, 2, 3), "in", idxStoreOut))
+ (edges \ "results").as[Seq[JsValue]].size should be(0)
+ (edges \\ "_degree").map(_.as[Long]).sum should be(0)
+ }
+
+ /**
+ * { "out": {"method": "drop", "storeDegree": false} }
+ */
+ test("index for in direction should drop in direction edge and store degree") {
+ val edges = getEdgesSync(getQuery(Seq(1, 2, 3), "in", idxDropInStoreDegree))
+ (edges \ "results").as[Seq[JsValue]].size should be(0)
+ (edges \\ "_degree").map(_.as[Long]).sum should be(3)
+ }
+
+ /**
+ * { "in": {"method": "drop", "storeDegree": false }, "out": {"method": "drop"} }
+ */
+ test("index for out direction should drop out direction edge and store degree") {
+ val edges = getEdgesSync(getQuery(Seq(0), "out", idxDropOutStoreDegree))
+ (edges \ "results").as[Seq[JsValue]].size should be(0)
+ (edges \\ "_degree").map(_.as[Long]).sum should be(3)
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/b639996b/s2core/src/test/scala/org/apache/s2graph/core/index/IndexProviderTest.scala
----------------------------------------------------------------------
diff --git a/s2core/src/test/scala/org/apache/s2graph/core/index/IndexProviderTest.scala b/s2core/src/test/scala/org/apache/s2graph/core/index/IndexProviderTest.scala
index ce030bb..7c5d55d 100644
--- a/s2core/src/test/scala/org/apache/s2graph/core/index/IndexProviderTest.scala
+++ b/s2core/src/test/scala/org/apache/s2graph/core/index/IndexProviderTest.scala
@@ -20,7 +20,9 @@
package org.apache.s2graph.core.index
import org.apache.s2graph.core.Integrate.IntegrateCommon
-import org.apache.s2graph.core.{Management, S2Vertex}
+import org.apache.s2graph.core.S2Vertex
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.HasContainer
+import org.apache.tinkerpop.gremlin.process.traversal.P
import org.apache.s2graph.core.mysqls._
import org.apache.s2graph.core.types.{InnerVal, InnerValLikeWithTs}
import scala.collection.JavaConversions._
@@ -29,7 +31,10 @@ class IndexProviderTest extends IntegrateCommon {
val indexProvider = IndexProvider(config)
val numOfTry = 1
+ lazy val gIndex = management.buildGlobalIndex("test1", Seq("_timestamp", "weight", "time"))
+
test("test vertex write/query") {
+ gIndex
import TestUtil._
// Management.addVertexProp(testServiceName, testColumnName, "time", "long")
@@ -59,7 +64,9 @@ class IndexProviderTest extends IntegrateCommon {
indexProvider.mutateVertices(vertices)
(0 until numOfTry).foreach { ith =>
- var ids = indexProvider.fetchVertexIds("_timestamp: 1")
+ val hasContainer = new HasContainer("_timestamp", P.eq(Long.box(1)))
+
+ var ids = indexProvider.fetchVertexIds(Seq(hasContainer))
ids.head shouldBe vertex.id
ids.foreach { id =>
@@ -67,6 +74,7 @@ class IndexProviderTest extends IntegrateCommon {
}
}
}
+
test("test edge write/query ") {
import TestUtil._
val testLabelName = TestUtil.testLabelName
@@ -95,8 +103,9 @@ class IndexProviderTest extends IntegrateCommon {
// match
(0 until numOfTry).foreach { _ =>
-
- val ids = indexProvider.fetchEdgeIds("time: 10 AND _timestamp: 1")
+ val hasContainers = Seq(new HasContainer("time", P.eq(Int.box(10))),
+ new HasContainer("_timestamp", P.eq(Int.box(1))))
+ val ids = indexProvider.fetchEdgeIds(hasContainers)
ids.head shouldBe edge.edgeId
ids.foreach { id =>
@@ -106,7 +115,9 @@ class IndexProviderTest extends IntegrateCommon {
// match and not
(0 until numOfTry).foreach { _ =>
- val ids = indexProvider.fetchEdgeIds("time: 20 AND NOT _timestamp: 1")
+ val hasContainers = Seq(new HasContainer("time", P.eq(Int.box(20))),
+ new HasContainer("_timestamp", P.neq(Int.box(1))))
+ val ids = indexProvider.fetchEdgeIds(hasContainers)
// ids.size shouldBe 0
ids.size shouldBe numOfOthers
@@ -118,7 +129,9 @@ class IndexProviderTest extends IntegrateCommon {
// range
(0 until numOfTry).foreach { _ =>
- val ids = indexProvider.fetchEdgeIds("time: [0 TO 10]")
+ val hasContainers = Seq(new HasContainer("time",
+ P.inside(Int.box(0), Int.box(11))))
+ val ids = indexProvider.fetchEdgeIds(hasContainers)
// ids.size shouldBe 0
ids.size shouldBe 1
@@ -128,4 +141,52 @@ class IndexProviderTest extends IntegrateCommon {
}
}
}
+
+ test("buildQuerySingleString") {
+ // (weight: 34) AND (weight: [0.5 TO *] AND price: 30)
+
+ var hasContainer = new HasContainer("weight", P.eq(Double.box(0.5)))
+
+ var queryString = IndexProvider.buildQuerySingleString(hasContainer)
+
+ println(s"[[QueryString]]: ${queryString}")
+
+ hasContainer = new HasContainer("weight", P.gte(Double.box(0.5)))
+ queryString = IndexProvider.buildQuerySingleString(hasContainer)
+
+ println(s"[[QueryString]]: ${queryString}")
+
+ hasContainer = new HasContainer("weight", P.within(Double.box(0.5), Double.box(0.7)))
+ queryString = IndexProvider.buildQuerySingleString(hasContainer)
+
+ println(s"[[QueryString]]: ${queryString}")
+
+ hasContainer = new HasContainer("weight", P.without(Double.box(0.5), Double.box(0.7)))
+ queryString = IndexProvider.buildQuerySingleString(hasContainer)
+
+ println(s"[[QueryString]]: ${queryString}")
+ }
+
+ test("buildQueryString") {
+ // (weight: 34) AND (weight: [1 TO 100])
+
+ var hasContainers = Seq(
+ new HasContainer("weight", P.eq(Int.box(34))),
+ new HasContainer("weight", P.between(Int.box(1), Int.box(100)))
+ )
+
+ var queryString = IndexProvider.buildQueryString(hasContainers)
+ println(s"[[QueryString]: ${queryString}")
+
+ hasContainers = Seq(
+ new HasContainer("weight", P.eq(Int.box(34))),
+ new HasContainer("weight", P.outside(Int.box(1), Int.box(100)))
+ )
+
+ queryString = IndexProvider.buildQueryString(hasContainers)
+ println(s"[[QueryString]: ${queryString}")
+ }
+
+
+
}
http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/b639996b/s2core/src/test/scala/org/apache/s2graph/core/models/GlobalIndexTest.scala
----------------------------------------------------------------------
diff --git a/s2core/src/test/scala/org/apache/s2graph/core/models/GlobalIndexTest.scala b/s2core/src/test/scala/org/apache/s2graph/core/models/GlobalIndexTest.scala
new file mode 100644
index 0000000..18b1572
--- /dev/null
+++ b/s2core/src/test/scala/org/apache/s2graph/core/models/GlobalIndexTest.scala
@@ -0,0 +1,59 @@
+package org.apache.s2graph.core.models
+
+import org.apache.s2graph.core.TestCommonWithModels
+import org.apache.s2graph.core.mysqls.GlobalIndex
+import org.apache.tinkerpop.gremlin.process.traversal.P
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.HasContainer
+import org.scalatest.{BeforeAndAfterAll, FunSuite, Matchers}
+import scala.collection.JavaConversions._
+
+class GlobalIndexTest extends FunSuite with Matchers with TestCommonWithModels with BeforeAndAfterAll {
+ override def beforeAll(): Unit = {
+ initTests()
+ }
+
+ override def afterAll(): Unit = {
+ graph.shutdown()
+ }
+
+ test("test buildGlobalIndex.") {
+ management.buildGlobalIndex("test_global", Seq("weight", "date", "name"))
+ }
+
+ test("findGlobalIndex.") {
+ // (weight: 34) AND (weight: [1 TO 100])
+ val idx1 = management.buildGlobalIndex("test-1", Seq("weight", "age", "name"))
+ val idx2 = management.buildGlobalIndex("test-2", Seq("gender", "age"))
+ val idx3 = management.buildGlobalIndex("test-3", Seq("class"))
+
+ var hasContainers = Seq(
+ new HasContainer("weight", P.eq(Int.box(34))),
+ new HasContainer("age", P.between(Int.box(1), Int.box(100)))
+ )
+
+ GlobalIndex.findGlobalIndex(hasContainers) shouldBe(Option(idx1))
+
+ hasContainers = Seq(
+ new HasContainer("gender", P.eq(Int.box(34))),
+ new HasContainer("age", P.eq(Int.box(34))),
+ new HasContainer("class", P.eq(Int.box(34)))
+ )
+
+ GlobalIndex.findGlobalIndex(hasContainers) shouldBe(Option(idx2))
+
+ hasContainers = Seq(
+ new HasContainer("class", P.eq(Int.box(34))),
+ new HasContainer("_", P.eq(Int.box(34)))
+ )
+
+ GlobalIndex.findGlobalIndex(hasContainers) shouldBe(Option(idx3))
+
+ hasContainers = Seq(
+ new HasContainer("key", P.eq(Int.box(34))),
+ new HasContainer("value", P.eq(Int.box(34)))
+ )
+
+ GlobalIndex.findGlobalIndex(hasContainers) shouldBe(None)
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/b639996b/s2core/src/test/scala/org/apache/s2graph/core/tinkerpop/S2GraphProvider.scala
----------------------------------------------------------------------
diff --git a/s2core/src/test/scala/org/apache/s2graph/core/tinkerpop/S2GraphProvider.scala b/s2core/src/test/scala/org/apache/s2graph/core/tinkerpop/S2GraphProvider.scala
index 1d06e46..e71ccb3 100644
--- a/s2core/src/test/scala/org/apache/s2graph/core/tinkerpop/S2GraphProvider.scala
+++ b/s2core/src/test/scala/org/apache/s2graph/core/tinkerpop/S2GraphProvider.scala
@@ -154,6 +154,7 @@ class S2GraphProvider extends AbstractGraphProvider {
val defaultService = Service.findByName(S2Graph.DefaultServiceName).getOrElse(throw new IllegalStateException("default service is not initialized."))
val defaultServiceColumn = ServiceColumn.find(defaultService.id.get, S2Graph.DefaultColumnName).getOrElse(throw new IllegalStateException("default column is not initialized."))
+ val allProps = scala.collection.mutable.Set.empty[Prop]
var knowsProp = Vector(
Prop("weight", "0.0", "double"),
Prop("data", "-", "string"),
@@ -171,8 +172,9 @@ class S2GraphProvider extends AbstractGraphProvider {
Prop("data", "-", "string"),
Prop("name", "-", "string")
)
+ allProps ++= knowsProp
- // Change dataType for ColumnMeta('aKey') for PropertyFeatureSupportTest
+ // Change dataType for ColumnMeta('aKey') for PropertyFeatureSupportTest
if (testClass.getSimpleName == "PropertyFeatureSupportTest") {
knowsProp = knowsProp.filterNot(_.name == "aKey")
@@ -210,28 +212,40 @@ class S2GraphProvider extends AbstractGraphProvider {
}
// columns
- val personColumn = Management.createServiceColumn(defaultService.serviceName, "person", "integer",
- Seq(Prop("name", "-", "string"), Prop("age", "0", "integer"), Prop("location", "-", "string")))
- val softwareColumn = Management.createServiceColumn(defaultService.serviceName, "software", "integer",
- Seq(Prop("name", "-", "string"), Prop("lang", "-", "string"), Prop("temp", "-", "string")))
-
- val productColumn = Management.createServiceColumn(defaultService.serviceName, "product", "integer", Nil)
- val dogColumn = Management.createServiceColumn(defaultService.serviceName, "dog", "integer", Nil)
- val animalColumn = Management.createServiceColumn(defaultService.serviceName, "animal", "integer", Seq(Prop("age", "0", "integer"), Prop("name", "-", "string")))
- val songColumn = Management.createServiceColumn(defaultService.serviceName, "song", "integer",
- Seq(Prop("name", "-", "string"), Prop("songType", "-", "string"), Prop("performances", "0", "integer"))
- )
- val artistColumn = Management.createServiceColumn(defaultService.serviceName, "artist", "integer",
- Seq(Prop("name", "-", "string"))
- )
- val stephenColumn = Management.createServiceColumn(defaultService.serviceName, "STEPHEN", "integer",
- Seq(Prop("name", "-", "string"))
- )
-// val vertexColumn = Management.createServiceColumn(service.serviceName, "vertex", "integer", Seq(Prop(T.id.toString, "-1", "integer"), Prop("name", "-", "string"), Prop("age", "-1", "integer"), Prop("lang", "scala", "string")))
+ val personProps = Seq(Prop("name", "-", "string"), Prop("age", "0", "integer"), Prop("location", "-", "string"))
+ allProps ++= personProps
+ val personColumn = Management.createServiceColumn(defaultService.serviceName, "person", "integer", personProps)
+
+ val softwareProps = Seq(Prop("name", "-", "string"), Prop("lang", "-", "string"), Prop("temp", "-", "string"))
+ allProps ++= softwareProps
+ val softwareColumn = Management.createServiceColumn(defaultService.serviceName, "software", "integer", softwareProps)
+
+ val productProps = Nil
+ val productColumn = Management.createServiceColumn(defaultService.serviceName, "product", "integer", productProps)
+
+ val dogProps = Nil
+ val dogColumn = Management.createServiceColumn(defaultService.serviceName, "dog", "integer", dogProps)
+
+ val animalProps = Seq(Prop("age", "0", "integer"), Prop("name", "-", "string"))
+ allProps ++= animalProps
+ val animalColumn = Management.createServiceColumn(defaultService.serviceName, "animal", "integer", animalProps)
+
+ val songProps = Seq(Prop("name", "-", "string"), Prop("songType", "-", "string"), Prop("performances", "0", "integer"))
+ allProps ++= songProps
+ val songColumn = Management.createServiceColumn(defaultService.serviceName, "song", "integer", songProps)
+
+ val artistProps = Seq(Prop("name", "-", "string"))
+ allProps ++= artistProps
+ val artistColumn = Management.createServiceColumn(defaultService.serviceName, "artist", "integer", artistProps)
+
+
+ val stephenProps = Seq(Prop("name", "-", "string"))
+ allProps ++= stephenProps
+ val stephenColumn = Management.createServiceColumn(defaultService.serviceName, "STEPHEN", "integer", stephenProps)
// labels
val createdProps = Seq(Prop("weight", "0.0", "double"), Prop("name", "-", "string"))
-
+ allProps ++= createdProps
val created =
if (loadGraphWith != null && loadGraphWith.value() == GraphData.MODERN) {
mnt.createLabel("created",
@@ -245,17 +259,21 @@ class S2GraphProvider extends AbstractGraphProvider {
true, defaultService.serviceName, Nil, createdProps, "strong", None, None)
}
-
+ val boughtProps = Seq(Prop("x", "-", "string"), Prop("y", "-", "string"))
+ allProps ++= boughtProps
val bought = mnt.createLabel("bought", defaultService.serviceName, "person", "integer", defaultService.serviceName, "product", "integer",
- true, defaultService.serviceName, Nil, Seq(Prop("x", "-", "string"), Prop("y", "-", "string")), "strong", None, None,
+ true, defaultService.serviceName, Nil, boughtProps, "strong", None, None,
options = Option("""{"skipReverse": true}"""))
+ val testProps = Seq(Prop("xxx", "-", "string"))
+ allProps ++= testProps
val test = mnt.createLabel("test", defaultService.serviceName, defaultServiceColumn.columnName, defaultServiceColumn.columnType, defaultService.serviceName, defaultServiceColumn.columnName, defaultServiceColumn.columnType,
- true, defaultService.serviceName, Nil, Seq(Prop("xxx", "-", "string")), "weak", None, None,
+ true, defaultService.serviceName, Nil, testProps, "weak", None, None,
options = Option("""{"skipReverse": true}"""))
val selfProps = Seq(Prop("__id", "-", "string"), Prop("acl", "-", "string"),
Prop("test", "-", "string"), Prop("name", "-", "string"), Prop("some", "-", "string"))
+ allProps ++= selfProps
val self =
if (loadGraphWith != null && loadGraphWith.value() == GraphData.CLASSIC) {
@@ -271,188 +289,230 @@ class S2GraphProvider extends AbstractGraphProvider {
options = Option("""{"skipReverse": false}"""))
}
+ val friendsProps = Seq(Prop("weight", "0.0", "double"))
+ allProps ++= friendsProps
+
val friends =
if (testClass.getSimpleName == "IoVertexTest") {
mnt.createLabel("friends",
defaultService.serviceName, "person", "integer",
defaultService.serviceName, "person", "integer",
- true, defaultService.serviceName, Nil, Seq(Prop("weight", "0.0", "double")),
+ true, defaultService.serviceName, Nil, friendsProps,
"strong", None, None,
options = Option("""{"skipReverse": false}"""))
} else {
- mnt.createLabel("friends", defaultService.serviceName, defaultServiceColumn.columnName, defaultServiceColumn.columnType, defaultService.serviceName, defaultServiceColumn.columnName, defaultServiceColumn.columnType,
+ mnt.createLabel("friends", defaultService.serviceName, defaultServiceColumn.columnName,
+ defaultServiceColumn.columnType, defaultService.serviceName, defaultServiceColumn.columnName, defaultServiceColumn.columnType,
true, defaultService.serviceName, Nil, Nil,
"strong", None, None,
options = Option("""{"skipReverse": false}"""))
}
+ val friendProps = Seq(
+ Prop("name", "-", "string"),
+ Prop("location", "-", "string"),
+ Prop("status", "-", "string"),
+ Prop("weight", "0.0", "double"),
+ Prop("acl", "-", "string")
+ )
+ allProps ++= friendProps
+
val friend =
if (testClass.getSimpleName == "IoEdgeTest") {
mnt.createLabel("friend",
defaultService.serviceName, "person", "integer",
defaultService.serviceName, "person", "integer",
true, defaultService.serviceName, Nil,
- Seq(
- Prop("name", "-", "string"),
- Prop("location", "-", "string"),
- Prop("status", "-", "string"),
- Prop("weight", "0.0", "double"),
- Prop("acl", "-", "string")
- ), "strong", None, None,
+ friendProps, "strong", None, None,
options = Option("""{"skipReverse": false}"""))
} else {
mnt.createLabel("friend",
defaultService.serviceName, defaultServiceColumn.columnName, defaultServiceColumn.columnType,
defaultService.serviceName, defaultServiceColumn.columnName, defaultServiceColumn.columnType,
true, defaultService.serviceName, Nil,
- Seq(
- Prop("name", "-", "string"),
- Prop("location", "-", "string"),
- Prop("status", "-", "string"),
- Prop("weight", "0.0", "double"),
- Prop("acl", "-", "string")
- ), "strong", None, None,
+ friendProps, "strong", None, None,
options = Option("""{"skipReverse": false}""")
)
}
- val hate = mnt.createLabel("hate", defaultService.serviceName, defaultServiceColumn.columnName, defaultServiceColumn.columnType, defaultService.serviceName, defaultServiceColumn.columnName, defaultServiceColumn.columnType,
- true, defaultService.serviceName, Nil, Nil, "strong", None, None,
+ val hateProps = Nil
+ val hate = mnt.createLabel("hate", defaultService.serviceName, defaultServiceColumn.columnName, defaultServiceColumn.columnType,
+ defaultService.serviceName, defaultServiceColumn.columnName, defaultServiceColumn.columnType,
+ true, defaultService.serviceName, Nil, hateProps, "strong", None, None,
options = Option("""{"skipReverse": false}""")
)
+ val collaboratorProps = Seq(Prop("location", "-", "string"))
+ allProps ++= collaboratorProps
+
val collaborator = mnt.createLabel("collaborator", defaultService.serviceName, defaultServiceColumn.columnName, defaultServiceColumn.columnType, defaultService.serviceName, defaultServiceColumn.columnName, defaultServiceColumn.columnType,
true, defaultService.serviceName, Nil,
- Seq(
- Prop("location", "-", "string")
- ),
- "strong", None, None,
+ collaboratorProps, "strong", None, None,
options = Option("""{"skipReverse": true}""")
)
- val test1 = mnt.createLabel("test1", defaultService.serviceName, defaultServiceColumn.columnName, defaultServiceColumn.columnType, defaultService.serviceName, defaultServiceColumn.columnName, defaultServiceColumn.columnType,
- true, defaultService.serviceName, Nil, Nil, "weak", None, None,
+ val test1Props = Nil
+ val test1 = mnt.createLabel("test1", defaultService.serviceName, defaultServiceColumn.columnName, defaultServiceColumn.columnType,
+ defaultService.serviceName, defaultServiceColumn.columnName, defaultServiceColumn.columnType,
+ true, defaultService.serviceName, Nil, test1Props, "weak", None, None,
options = Option("""{"skipReverse": false}""")
)
- val test2 = mnt.createLabel("test2", defaultService.serviceName, defaultServiceColumn.columnName, defaultServiceColumn.columnType, defaultService.serviceName, defaultServiceColumn.columnName, defaultServiceColumn.columnType,
- true, defaultService.serviceName, Nil, Nil, "weak", None, None,
+
+ val test2Props = Nil
+ val test2 = mnt.createLabel("test2", defaultService.serviceName, defaultServiceColumn.columnName, defaultServiceColumn.columnType,
+ defaultService.serviceName, defaultServiceColumn.columnName, defaultServiceColumn.columnType,
+ true, defaultService.serviceName, Nil, test2Props, "weak", None, None,
options = Option("""{"skipReverse": false}""")
)
- val test3 = mnt.createLabel("test3", defaultService.serviceName, defaultServiceColumn.columnName, defaultServiceColumn.columnType, defaultService.serviceName, defaultServiceColumn.columnName, defaultServiceColumn.columnType,
- true, defaultService.serviceName, Nil, Nil, "weak", None, None,
+
+ val test3Props = Nil
+ val test3 = mnt.createLabel("test3", defaultService.serviceName, defaultServiceColumn.columnName, defaultServiceColumn.columnType,
+ defaultService.serviceName, defaultServiceColumn.columnName, defaultServiceColumn.columnType,
+ true, defaultService.serviceName, Nil, test3Props, "weak", None, None,
options = Option("""{"skipReverse": false}""")
)
- val pets = mnt.createLabel("pets", defaultService.serviceName, defaultServiceColumn.columnName, defaultServiceColumn.columnType, defaultService.serviceName, defaultServiceColumn.columnName, defaultServiceColumn.columnType,
- true, defaultService.serviceName, Nil, Nil, "strong", None, None,
+
+ val petsProps = Nil
+ val pets = mnt.createLabel("pets", defaultService.serviceName, defaultServiceColumn.columnName, defaultServiceColumn.columnType,
+ defaultService.serviceName, defaultServiceColumn.columnName, defaultServiceColumn.columnType,
+ true, defaultService.serviceName, Nil, petsProps, "strong", None, None,
options = Option("""{"skipReverse": false}""")
)
- val walks = mnt.createLabel("walks", defaultService.serviceName, defaultServiceColumn.columnName, defaultServiceColumn.columnType, defaultService.serviceName, defaultServiceColumn.columnName, defaultServiceColumn.columnType,
+
+ val walksProps = Seq(Prop("location", "-", "string"))
+ allProps ++= walksProps
+
+ val walks = mnt.createLabel("walks", defaultService.serviceName, defaultServiceColumn.columnName, defaultServiceColumn.columnType,
+ defaultService.serviceName, defaultServiceColumn.columnName, defaultServiceColumn.columnType,
true, defaultService.serviceName, Nil,
- Seq(
- Prop("location", "-", "string")
- ), "strong", None, None,
+ walksProps, "strong", None, None,
options = Option("""{"skipReverse": false}""")
)
+
+ val livesWithProps = Nil
val livesWith = mnt.createLabel("livesWith", defaultService.serviceName, defaultServiceColumn.columnName, defaultServiceColumn.columnType, defaultService.serviceName, defaultServiceColumn.columnName, defaultServiceColumn.columnType,
- true, defaultService.serviceName, Nil, Nil, "strong", None, None,
+ true, defaultService.serviceName, Nil, livesWithProps, "strong", None, None,
options = Option("""{"skipReverse": false}""")
)
+ val hatesProps = Nil
val hates = mnt.createLabel("hates", defaultService.serviceName, defaultServiceColumn.columnName, defaultServiceColumn.columnType, defaultService.serviceName, defaultServiceColumn.columnName, defaultServiceColumn.columnType,
- true, defaultService.serviceName, Nil, Nil, "weak", None, None,
+ true, defaultService.serviceName, Nil, hatesProps, "weak", None, None,
options = Option("""{"skipReverse": false}""")
)
+ val linkProps = Nil
val link = mnt.createLabel("link", defaultService.serviceName, defaultServiceColumn.columnName, defaultServiceColumn.columnType, defaultService.serviceName, defaultServiceColumn.columnName, defaultServiceColumn.columnType,
- true, defaultService.serviceName, Nil, Nil, "strong", None, None,
+ true, defaultService.serviceName, Nil, linkProps, "strong", None, None,
options = Option("""{"skipReverse": false}""")
)
+ val codeveloperProps = Seq( Prop("year", "0", "integer"))
+ allProps ++= codeveloperProps
+
val codeveloper = mnt.createLabel("codeveloper",
defaultService.serviceName, "person", "integer",
defaultService.serviceName, "person", "integer",
true, defaultService.serviceName, Nil,
- Seq(
- Prop("year", "0", "integer")
- ), "strong", None, None,
+ codeveloperProps, "strong", None, None,
options = Option("""{"skipReverse": false}""")
)
+ val createdByProps = Seq(
+ Prop("weight", "0.0", "double"),
+ Prop("year", "0", "integer"),
+ Prop("acl", "-", "string")
+ )
+ allProps ++= createdByProps
+
val createdBy = mnt.createLabel("createdBy",
defaultService.serviceName, "software", "integer",
defaultService.serviceName, "person", "integer",
true, defaultService.serviceName, Nil,
- Seq(
- Prop("weight", "0.0", "double"),
- Prop("year", "0", "integer"),
- Prop("acl", "-", "string")
- ), "strong", None, None)
+ createdByProps, "strong", None, None)
+
+ val existsWithProps = Seq(Prop("time", "-", "string"))
+ allProps ++= existsWithProps
val existsWith = mnt.createLabel("existsWith",
defaultService.serviceName, defaultServiceColumn.columnName, defaultServiceColumn.columnType,
defaultService.serviceName, defaultServiceColumn.columnName, defaultServiceColumn.columnType,
- true, defaultService.serviceName, Nil, Seq(Prop("time", "-", "string")), "strong", None, None,
+ true, defaultService.serviceName, Nil, existsWithProps, "strong", None, None,
options = Option("""{"skipReverse": false}""")
)
+ val followedByProps = Seq(Prop("weight", "0.0", "double"))
+ allProps ++= followedByProps
+
val followedBy = mnt.createLabel("followedBy",
defaultService.serviceName, "song", "integer",
defaultService.serviceName, "song", "integer",
- true, defaultService.serviceName, Nil, Seq(Prop("weight", "0.0", "double")), "strong", None, None,
+ true, defaultService.serviceName, Nil, followedByProps, "strong", None, None,
options = Option("""{"skipReverse": false}""")
)
+ val writtenByProps = Seq(Prop("weight", "0.0", "double"))
+ allProps ++= writtenByProps
+
val writtenBy = mnt.createLabel("writtenBy",
defaultService.serviceName, "song", "integer",
defaultService.serviceName, "artist", "integer",
- true, defaultService.serviceName, Nil, Seq(Prop("weight", "0.0", "double")), "strong", None, None,
+ true, defaultService.serviceName, Nil, writtenByProps, "strong", None, None,
options = Option("""{"skipReverse": false}""")
)
+ val sungByProps = Seq(Prop("weight", "0.0", "double"))
+ allProps ++= sungByProps
+
val sungBy = mnt.createLabel("sungBy",
defaultService.serviceName, "song", "integer",
defaultService.serviceName, "artist", "integer",
- true, defaultService.serviceName, Nil, Seq(Prop("weight", "0.0", "double")), "strong", None, None,
+ true, defaultService.serviceName, Nil, sungByProps, "strong", None, None,
options = Option("""{"skipReverse": false}""")
)
+ val usesProps = Nil
val uses = mnt.createLabel("uses",
defaultService.serviceName, "person", "integer",
defaultService.serviceName, "software", "integer",
- true, defaultService.serviceName, Nil, Nil, "strong", None, None,
+ true, defaultService.serviceName, Nil, usesProps, "strong", None, None,
options = Option("""{"skipReverse": false}""")
)
+ val likesProps = Seq(Prop("year", "0", "integer"))
+ allProps ++= likesProps
+
val likes = mnt.createLabel("likes",
defaultService.serviceName, "person", "integer",
defaultService.serviceName, "person", "integer",
true, defaultService.serviceName, Nil,
- Seq(
- Prop("year", "0", "integer")
- ), "strong", None, None,
+ likesProps, "strong", None, None,
options = Option("""{"skipReverse": false}""")
)
+ val fooProps = Seq(Prop("year", "0", "integer"))
+ allProps ++= fooProps
+
val foo = mnt.createLabel("foo",
defaultService.serviceName, "person", "integer",
defaultService.serviceName, "person", "integer",
true, defaultService.serviceName, Nil,
- Seq(
- Prop("year", "0", "integer")
- ), "strong", None, None,
+ fooProps, "strong", None, None,
options = Option("""{"skipReverse": false}""")
)
+ val barProps = Seq(Prop("year", "0", "integer"))
+ allProps ++= barProps
+
val bar = mnt.createLabel("bar",
defaultService.serviceName, "person", "integer",
defaultService.serviceName, "person", "integer",
true, defaultService.serviceName, Nil,
- Seq(
- Prop("year", "0", "integer")
- ), "strong", None, None,
+ barProps, "strong", None, None,
options = Option("""{"skipReverse": false}""")
)
+ val globalIndex = mnt.buildGlobalIndex("global", allProps.map(_.name).toSeq)
super.loadGraphData(graph, loadGraphWith, testClass, testName)
}
http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/b639996b/s2core/src/test/scala/org/apache/s2graph/core/tinkerpop/structure/S2GraphTest.scala
----------------------------------------------------------------------
diff --git a/s2core/src/test/scala/org/apache/s2graph/core/tinkerpop/structure/S2GraphTest.scala b/s2core/src/test/scala/org/apache/s2graph/core/tinkerpop/structure/S2GraphTest.scala
index 3fcfb2b..3e618ea 100644
--- a/s2core/src/test/scala/org/apache/s2graph/core/tinkerpop/structure/S2GraphTest.scala
+++ b/s2core/src/test/scala/org/apache/s2graph/core/tinkerpop/structure/S2GraphTest.scala
@@ -24,10 +24,10 @@ import java.util.function.Predicate
import org.apache.s2graph.core.GraphExceptions.LabelNotExistException
import org.apache.s2graph.core.Management.JsonModel.Prop
import org.apache.s2graph.core._
-import org.apache.s2graph.core.mysqls.{Service, ServiceColumn}
+import org.apache.s2graph.core.mysqls.{GlobalIndex, Service, ServiceColumn}
import org.apache.s2graph.core.tinkerpop.S2GraphProvider
import org.apache.s2graph.core.utils.logger
-import org.apache.tinkerpop.gremlin.process.traversal.Scope
+import org.apache.tinkerpop.gremlin.process.traversal.{Compare, P, Scope}
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.{in, out}
import org.apache.tinkerpop.gremlin.structure._
@@ -41,7 +41,7 @@ class S2GraphTest extends FunSuite with Matchers with TestCommonWithModels {
initTests()
val g = new S2Graph(config)
-
+ lazy val gIndex = management.buildGlobalIndex("S2GraphTest", Seq("weight"))
def printEdges(edges: Seq[Edge]): Unit = {
edges.foreach { edge =>
logger.debug(s"[FetchedEdge]: $edge")
@@ -153,33 +153,33 @@ class S2GraphTest extends FunSuite with Matchers with TestCommonWithModels {
// true, service.serviceName, Nil, Seq(Prop("weight", "0.0", "float")), "strong", None, None)
//
- test("tinkerpop class graph test.") {
- val marko = graph.addVertex(T.label, "person", T.id, Int.box(1))
- marko.property("name", "marko")
- marko.property("age", Int.box(29))
- val vadas = graph.addVertex(T.label, "person", T.id, Int.box(2))
- vadas.property("name", "vadas", "age", Int.box(27))
- val lop = graph.addVertex(T.label, "software", T.id, Int.box(3), "name", "lop", "lang", "java")
- val josh = graph.addVertex(T.label, "person", T.id, Int.box(4), "name", "josh", "age", Int.box(32))
- val ripple = graph.addVertex(T.label, "software", T.id, Int.box(5), "name", "ripple", "lang", "java")
- val peter = graph.addVertex(T.label, "person", T.id, Int.box(6), "name", "peter", "age", Int.box(35))
-
- marko.addEdge("knows", vadas, T.id, Int.box(7), "weight", Float.box(0.5f))
- marko.addEdge("knows", josh, T.id, Int.box(8), "weight", Float.box(1.0f))
- marko.addEdge("created", lop, T.id, Int.box(9), "weight", Float.box(0.4f))
- josh.addEdge("created", ripple, T.id, Int.box(10), "weight", Float.box(1.0f))
- josh.addEdge("created", lop, T.id, Int.box(11), "weight", Float.box(0.4f))
- peter.addEdge("created", lop, T.id, Int.box(12), "weight", Float.box(0.2f))
- graph.tx().commit()
-
- graph.traversal().V().inV()
- val verticees = graph.traversal().V().asAdmin()
-
-
- val vs = verticees.toList
-
-
- }
+// test("tinkerpop class graph test.") {
+// val marko = graph.addVertex(T.label, "person", T.id, Int.box(1))
+// marko.property("name", "marko")
+// marko.property("age", Int.box(29))
+// val vadas = graph.addVertex(T.label, "person", T.id, Int.box(2))
+// vadas.property("name", "vadas", "age", Int.box(27))
+// val lop = graph.addVertex(T.label, "software", T.id, Int.box(3), "name", "lop", "lang", "java")
+// val josh = graph.addVertex(T.label, "person", T.id, Int.box(4), "name", "josh", "age", Int.box(32))
+// val ripple = graph.addVertex(T.label, "software", T.id, Int.box(5), "name", "ripple", "lang", "java")
+// val peter = graph.addVertex(T.label, "person", T.id, Int.box(6), "name", "peter", "age", Int.box(35))
+//
+// marko.addEdge("knows", vadas, T.id, Int.box(7), "weight", Float.box(0.5f))
+// marko.addEdge("knows", josh, T.id, Int.box(8), "weight", Float.box(1.0f))
+// marko.addEdge("created", lop, T.id, Int.box(9), "weight", Float.box(0.4f))
+// josh.addEdge("created", ripple, T.id, Int.box(10), "weight", Float.box(1.0f))
+// josh.addEdge("created", lop, T.id, Int.box(11), "weight", Float.box(0.4f))
+// peter.addEdge("created", lop, T.id, Int.box(12), "weight", Float.box(0.2f))
+// graph.tx().commit()
+//
+// graph.traversal().V().inV()
+// val verticees = graph.traversal().V().asAdmin()
+//
+//
+// val vs = verticees.toList
+//
+//
+// }
// test("addVertex with empty parameter") {
//
@@ -417,7 +417,10 @@ class S2GraphTest extends FunSuite with Matchers with TestCommonWithModels {
//// }
// }
test("Modern") {
+ gIndex
val mnt = graph.management
+
+
S2GraphProvider.cleanupSchema
S2GraphProvider.initDefaultSchema(graph)
@@ -428,7 +431,7 @@ class S2GraphTest extends FunSuite with Matchers with TestCommonWithModels {
val knows = mnt.createLabel("knows",
S2Graph.DefaultServiceName, "person", "integer",
S2Graph.DefaultServiceName, "person", "integer",
- true, S2Graph.DefaultServiceName, Nil, Seq(Prop("since", "0", "integer"), Prop("year", "0", "integer")), consistencyLevel = "strong", None, None)
+ true, S2Graph.DefaultServiceName, Nil, Seq(Prop("weight", "0.0", "double"), Prop("year", "0", "integer")), consistencyLevel = "strong", None, None)
val created = mnt.createLabel("created",
S2Graph.DefaultServiceName, "person", "integer",
@@ -463,7 +466,7 @@ class S2GraphTest extends FunSuite with Matchers with TestCommonWithModels {
val e12 = v6.addEdge("created", v3, "weight", Double.box(0.2))
- val ls = graph.traversal().V().has("name", "josh")
+ val ls = graph.traversal().E().has("weight", P.eq(Double.box(0.5)))
val l = ls.toList
println(s"[Size]: ${l.size}")