mpollmeier / gremlin-scala

[unmaintained] Scala wrapper for Apache TinkerPop 3 Graph DSL
Apache License 2.0
481 stars 75 forks source link

`both` and `where` steps inside `repeat`-`until` do not compile #116

Closed albertotonon closed 8 years ago

albertotonon commented 8 years ago

Hello everybody, thanks for the project: the DSL is awesome!

Unfortunately I have an issue when I try to compile the code reported below. The compiler stops executing the last instruction and tells me that "both is not a member of gremlin.scala.GremlinScala[Any, shapeless.HNil]. The issue persists if I use a TinkerGraph.

Does anybody have any idea what's going wrong?

def main(args: Array[String]): Unit = {
import gremlin.scala._
import org.apache.tinkerpop.gremlin.orientdb._
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph._
import org.apache.tinkerpop.gremlin.process.traversal.{Order, P, Scope}
import shapeless._

    val graph = new OrientGraphFactory(s"memory:test-${math.random}").getTx.asScala
    val e0 = graph.addVertex("User", ("name", "e0"))
    val e1 = graph.addVertex("User", ("name", "e1"))
    val e2 = graph.addVertex("User", ("name", "e2"))
    val e3 = graph.addVertex("User", ("name", "e3"))
    val e4 = graph.addVertex("User", ("name", "e4"))
    e0.addEdge("Feedbacks", e2)
    e0.addEdge("Meets", e1)
    e0.addEdge("Meets", e4)
    e2.addEdge("Feedbacks", e4)
    e2.addEdge("Meets", e4)
    e3.addEdge("Feedbacks", e0)
    e3.addEdge("Meets", e2)
    e4.addEdge("Feedbacks", e0)
    e4.addEdge("Meets", e0)

    graph.V.as("e0").out("Feedbacks").as("e1").select("e0")
      .repeat(_.both("Meets")).until(_.where(eq("e1")))
      .path()
  }
mpollmeier commented 8 years ago

Sounds like you literally translated a gremlin groovy traversal. The problem is that you are loosing the types on the way because you labelled the steps with a String (e.g. "e0") - after the select step the compiler does not know the e0 is a Vertex, and the both step only works on vertices. This is to prevent you from writing an invalid traversal :)

To fix that problem you can use a StepLabel as below.

  val E0 = StepLabel[Vertex]("e0")
  val E1 = StepLabel[Vertex]("e1")
  graph.V.as(E0).out("Feedbacks").as(E1).select(E0).repeat(_.both("Meets"))

You'll still have to work on the until part - I'd encourage you to have a look at the shortest path example here: http://www.michaelpollmeier.com/2014/12/27/gremlin-scala-shortest-path/

Pro tip: use the nice DSL for adding vertices and edges:

  val Name = Key[String]("name")
  val e0 = graph + ("User", (Name -> "e0"))
  val e1 = graph + ("User", (Name -> "e1"))
  ...

  e0 --- "Feedbacks" --> e2
  ...

Can you describe in plain english what you're trying to achieve with your traversal?

albertotonon commented 8 years ago

Thanks, Michael, for your advice. Indeed it was taken from a gremlin groovy traversal, this one to be precise.

My goal is to find all the vertices directly connected by a 'Feedbacks' edge that are also connected by a 'Meets' path (with one or more steps).

I read your example and modified my traversal, now it looks like this:

val e0select = StepLabel[Vertex]("e0")
val e1select = StepLabel[Vertex]("e1")
graph.V.as(e0select)
      .out("Feedbacks").as(e1select)
      .select(e1select)
      .repeat(_.out("Meets")).until(_.is(e1select)))
      .path()

and now the code gets compiled successfully.

I used _.is() inside the until() step since I noticed you did something similar in your shortest path example, and replaced the both() step inside the repeat() with out(). Moreover, when testing I removed the e4 --> e0 edge to avoid having cycles, and used out() instead of both() inside the repeat() step.

Nevertheless the traversal does not return the right result ([[e2, e4]]). I guess I haven't completely understood how to use StepLabels in traversals (specifically in comparisons) and I haven't found any example for that. Will you elucidate this matter, if you have time?

albertotonon commented 8 years ago

I've got what I wanted by using

graph.V.as(e0select).out("Feedbacks").as(e1select).select(e0select).repeat(_.out("Meets")).until(_.where(P.eq("e1"))).path().by("name").toList()

Thanks for helping and sorry for disturbing for such a trivial matter. Some documentation on StepLabels would be useful, though :)

Cheers!

mpollmeier commented 8 years ago

btw there is (and was) documentation on StepLabels in the readme - any ideas on how to improve that?