8000 feat: add reverse edge pattern by goungoun · Pull Request #716 · graphframes/graphframes · GitHub
[go: up one dir, main page]

Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 29 additions & 23 deletions core/src/main/scala/org/graphframes/pattern/patterns.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,42 +31,48 @@ private[graphframes] object PatternParser extends RegexParsers {
private val anonymousVertex: Parser[Vertex] = "" ^^ { _ => AnonymousVertex }
private val vertex: Parser[Vertex] = "(" ~> (vertexName | anonymousVertex) <~ ")"
private val namedEdge: Parser[Edge] =
vertex ~ "-" ~ "[" ~ "[a-zA-Z0-9_]+".r ~ "]" ~ "->" ~ vertex ^^ {
vertex ~ ("<-" | "-") ~ "[" ~ "[a-zA-Z0-9_]+".r ~ "]" ~ ("->" | "-") ~ vertex ^^ {
case src ~ "-" ~ "[" ~ name ~ "]" ~ "->" ~ dst => NamedEdge(name, src, dst)
case dst ~ "<-" ~ "[" ~ name ~ "]" ~ "-" ~ src => NamedEdge(name, src, dst)
case _ => throw new GraphFramesUnreachableException()
}
val anonymousEdge: Parser[Edge] =
vertex ~ "-" ~ "[" ~ "]" ~ "->" ~ vertex ^^ {
vertex ~ ("<-" | "-") ~ "[" ~ "]" ~ ("->" | "-") ~ vertex ^^ {
case src ~ "-" ~ "[" ~ "]" ~ "->" ~ dst => AnonymousEdge(src, dst)
case dst ~ "<-" ~ "[" ~ "]" ~ "-" ~ src => AnonymousEdge(src, dst)
case _ => throw new GraphFramesUnreachableException()
}
private val edge: Parser[Edge] = namedEdge | anonymousEdge
private val negatedEdge: Parser[Pattern] =
"!" ~ edge ^^ { case _ ~ e =>
Negation(e)
}
private val fixedLengthPattern: Parser[List[Edge]] =
vertex ~ "-" ~ "[" ~ "[a-zA-Z0-9_]*".r ~ "*" ~ "[0-9]+".r ~ "]" ~ "->" ~ vertex ^^ {
case src ~ "-" ~ "[" ~ name ~ "*" ~ num ~ "]" ~ "->" ~ dst => {
val hop: Int = num.toInt
if (hop == 1) {
List(if (name.isEmpty) AnonymousEdge(src, dst) else NamedEdge(name, src, dst))
} else if (hop > 1) {
val midVertices = (1 until hop).map(i => NamedVertex(s"_v$i"))
val vertices = src +: midVertices :+ dst
vertices
.sliding(2)
.zipWithIndex
.map {
case (Seq(v1, v2), i) =>
if (name.isEmpty) AnonymousEdge(v1, v2) else NamedEdge(s"_$name${i + 1}", v1, v2)
case _ => throw new GraphFramesUnreachableException()
}
.toList
} else {
throw new GraphFramesUnreachableException()

def generateFixedLengthPattern(src: Vertex, name: String, hop: Int, dst: Vertex): List[Edge] = {
if (hop == 1) {
List(if (name.isEmpty) AnonymousEdge(src, dst) else NamedEdge(name, src, dst))
} else if (hop > 1) {
val midVertices = (1 until hop).map(i => NamedVertex(s"_v$i"))
val vertices = src +: midVertices :+ dst
vertices
.sliding(2)
.zipWithIndex
.map {
case (Seq(v1, v2), i) =>
if (name.isEmpty) AnonymousEdge(v1, v2) else NamedEdge(s"_$name${i + 1}", v1, v2)
case _ => throw new GraphFramesUnreachableException()
}
}
.toList
} else {
throw new GraphFramesUnreachableException()
}
}
private val fixedLengthPattern: Parser[List[Edge]] =
vertex ~ ("<-" | "-") ~ "[" ~ "[a-zA-Z0-9_]*".r ~ "*" ~ "[0-9]+".r ~ "]" ~ ("->" | "-") ~ vertex ^^ {
case src ~ "-" ~ "[" ~ name ~ "*" ~ num ~ "]" ~ "->" ~ dst =>
generateFixedLengthPattern(src, name, num.toInt, dst)
case dst ~ "<-" ~ "[" ~ name ~ "*" ~ num ~ "]" ~ "-" ~ src =>
generateFixedLengthPattern(src, name, num.toInt, dst)
case _ => throw new GraphFramesUnreachableException()
}
private val pattern: Parser[Pattern] = edge | vertex | negatedEdge
Expand Down
10 changes: 10 additions & 0 deletions core/src/test/scala/org/graphframes/pattern/PatternSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,16 @@ class PatternSuite extends SparkFunSuite {
AnonymousEdge(NamedVertex("_v9"), NamedVertex("v"))))
}

test("good parses - reverse edge pattern") {
assert(Pattern.parse("(u)-[e]->(v)") === Pattern.parse("(v)<-[e]-(u)"))
assert(Pattern.parse("(u)-[]->(v)") === Pattern.parse("(v)<-[]-(u)"))
assert(Pattern.parse("(u)-[*5]->(v)") === Pattern.parse("(v)<-[*5]-(u)"))
assert(Pattern.parse("()-[e]->()") === Pattern.parse("()<-[e]-()"))
assert(
Pattern.parse("(u)-[]->(v); (v)-[]->(w); !(u)-[]->(w)") === Pattern.parse(
"(u)-[]->(v); (w)<-[]-(v); !(w)<-[]-(u)"))
}

test("bad parses") {
withClue("Failed to catch parse error with lone anonymous vertex") {
intercept[InvalidParseException] {
Expand Down
0