Más contenido relacionado La actualidad más candente (20) Similar a Cypher inside out: Como a linguagem de pesquisas em grafo do Neo4j foi construída e como usá-la (20) Más de adrianoalmeida7 (6) Cypher inside out: Como a linguagem de pesquisas em grafo do Neo4j foi construída e como usá-la1. Cypher: Como a query
language do Neo4j foi
construída e como usá-la
tldr: Cypher internals em 15 minutos
3. Quem é vc?
Adriano Almeida
@adrianoalmeida7
ahalmeida.com
4. Quem é vc?
Adriano Almeida
@adrianoalmeida7
ahalmeida.com
5. Quem é vc?
Adriano Almeida
@adrianoalmeida7
ahalmeida.com
6. Quem é vc?
Adriano Almeida
@adrianoalmeida7
ahalmeida.com
9. Buscando dados no Neo4j
1. Traverse API Clássica
private static Traverser quemCodouOMatrix(final Node startNode) {
return startNode.traverse(Order.BREADTH_FIRST,
StopEvaluator.END_OF_GRAPH, new ReturnableEvaluator() {
@Override
public boolean isReturnableNode(final TraversalPosition currentPos) {
return !currentPos.isStartNode()
&& currentPos.lastRelationshipTraversed().isType(RelTypes.CODED_BY);
}
}, RelTypes.CODED_BY, Direction.OUTGOING, RelTypes.KNOWS,
Direction.OUTGOING
);
}
11. Buscando dados no Neo4j
2. Traverse API Nova
private static Traverser quemCodouOMatrix( final Node startNode )
{
TraversalDescription td = Traversal.description()
.breadthFirst()
.relationships( RelTypes.CODED_BY, Direction.OUTGOING )
.relationships( RelTypes.KNOWS, Direction.OUTGOING )
.evaluator(
Evaluators.returnWhereLastRelationshipTypeIs( RelTypes.CODED_BY ) );
return td.traverse( startNode );
}
13. Buscando dados no Neo4j
3. Cypher
start programmer=(3)
match (programmer)-[:PAIRED]->(pair)
where pair.age > 30
return pair
order by pair.age
skip 5 limit 10
14. Buscando dados no Neo4j
3. Cypher
private static Iterator<Node> comQuemUmDevPareou()
{
ExecutionEngine engine = new ExecutionEngine(db);
ExecutionResult result = engine.execute( "start programmer=(3) " +
"match (programmer)-[:PAIRED]->(pair) where pair.age > 30 " +
"return pair " +
"order by pair.age " +
"skip 5 limit 10" );
Iterator<Node> pairs = result.columnAs( "pair" );
return pairs;
}
16. Definindo a linguagem
Start
Match start programmer=(3)
match (programmer)-[:PAIRED]->(pair)
Where where pair.age > 30
Return return pair
order by pair.age
Order By skip 5 limit 10
Skip & Limit
17. Por partes: Start Clause
start ::= "start" {"," nodeByIds | nodeByIndex | nodeByIndexQuery |
relsByIds | relsByIndex }
nodeByIds ::= identity "=" "(" {"," number} ")"
nodeByIndex ::= identity "=" "(" identity "," identity "," string ")"
nodeByIndexQuery ::= identity "=" "(" identity "," string ")"
relsByIds ::= identity "=" "<" { "," number } ">"
relsByIndex ::= identity "=" "<" identity "," identity "," string ">"
20. Por partes: Start Clause
package org.neo4j.cypher.parser
trait StartClause extends JavaTokenParsers with Tokens {
def start: Parser[Start] = ignoreCase("start") ~> rep1sep(nodeByIds | nodeByIndex | nodeByIndexQuery |
relsByIds | relsByIndex, ",") ^^ (Start(_: _*))
def nodeByIds = identity ~ "=" ~ "(" ~ rep1sep(wholeNumber, ",") ~ ")" ^^ {
case varName ~ "=" ~ "(" ~ id ~ ")" => NodeById(varName, id.map(_.toLong).toSeq: _*)
}
def nodeByIndex = identity ~ "=" ~ "(" ~ identity ~ "," ~ identity ~ "," ~ string ~ ")" ^^ {
case varName ~ "=" ~ "(" ~ index ~ "," ~ key ~ "," ~ value ~ ")" => NodeByIndex(varName, index, key, value)
}
def nodeByIndexQuery = identity ~ "=" ~ "(" ~ identity ~ "," ~ string ~ ")" ^^ {
case varName ~ "=" ~ "(" ~ index ~ "," ~ query ~ ")" => NodeByIndexQuery(varName, index, query)
}
def relsByIds = identity ~ "=" ~ "<" ~ rep1sep(wholeNumber, ",") ~ ">" ^^ {
case varName ~ "=" ~ "<" ~ id ~ ">" => RelationshipById(varName, id.map(_.toLong).toSeq: _*)
}
def relsByIndex = identity ~ "=" ~ "<" ~ identity ~ "," ~ identity ~ "," ~ string ~ ">" ^^ {
case varName ~ "=" ~ "<" ~ index ~ "," ~ key ~ "," ~ value ~ ">" => RelationshipByIndex(varName, index, key,
value)
}
}
21. Por partes: Start Clause
package org.neo4j.cypher.parser
trait StartClause extends JavaTokenParsers with Tokens {
def start: Parser[Start] = ignoreCase("start") ~> rep1sep(nodeByIds | nodeByIndex | nodeByIndexQuery |
relsByIds | relsByIndex, ",") ^^ (Start(_: _*))
def nodeByIds = identity ~ "=" ~ "(" ~ rep1sep(wholeNumber, ",") ~ ")" ^^ {
case varName ~ "=" ~ "(" ~ id ~ ")" => NodeById(varName, id.map(_.toLong).toSeq: _*)
}
def nodeByIndex = identity ~ "=" ~ "(" ~ identity ~ "," ~ identity ~ "," ~ string ~ ")" ^^ {
case varName ~ "=" ~ "(" ~ index ~ "," ~ key ~ "," ~ value ~ ")" => NodeByIndex(varName, index, key, value)
}
def nodeByIndexQuery = identity ~ "=" ~ "(" ~ identity ~ "," ~ string ~ ")" ^^ {
case varName ~ "=" ~ "(" ~ index ~ "," ~ query ~ ")" => NodeByIndexQuery(varName, index, query)
}
def relsByIds = identity ~ "=" ~ "<" ~ rep1sep(wholeNumber, ",") ~ ">" ^^ {
case varName ~ "=" ~ "<" ~ id ~ ">" => RelationshipById(varName, id.map(_.toLong).toSeq: _*)
}
def relsByIndex = identity ~ "=" ~ "<" ~ identity ~ "," ~ identity ~ "," ~ string ~ ">" ^^ {
case varName ~ "=" ~ "<" ~ index ~ "," ~ key ~ "," ~ value ~ ">" => RelationshipByIndex(varName, index, key,
value)
}
}
22. Por partes: Start Clause
package org.neo4j.cypher.parser
trait StartClause extends JavaTokenParsers with Tokens {
def start: Parser[Start] = ignoreCase("start") ~> rep1sep(nodeByIds | nodeByIndex | nodeByIndexQuery |
relsByIds | relsByIndex, ",") ^^ (Start(_: _*))
def nodeByIds = identity ~ "=" ~ "(" ~ rep1sep(wholeNumber, ",") ~ ")" ^^ {
case varName ~ "=" ~ "(" ~ id ~ ")" => NodeById(varName, id.map(_.toLong).toSeq: _*)
}
def nodeByIndex = identity ~ "=" ~ "(" ~ identity ~ "," ~ identity ~ "," ~ string ~ ")" ^^ {
case varName ~ "=" ~ "(" ~ index ~ "," ~ key ~ "," ~ value ~ ")" => NodeByIndex(varName, index, key, value)
}
def nodeByIndexQuery = identity ~ "=" ~ "(" ~ identity ~ "," ~ string ~ ")" ^^ {
case varName ~ "=" ~ "(" ~ index ~ "," ~ query ~ ")" => NodeByIndexQuery(varName, index, query)
}
def relsByIds = identity ~ "=" ~ "<" ~ rep1sep(wholeNumber, ",") ~ ">" ^^ {
case varName ~ "=" ~ "<" ~ id ~ ">" => RelationshipById(varName, id.map(_.toLong).toSeq: _*)
}
def relsByIndex = identity ~ "=" ~ "<" ~ identity ~ "," ~ identity ~ "," ~ string ~ ">" ^^ {
case varName ~ "=" ~ "<" ~ index ~ "," ~ key ~ "," ~ value ~ ">" => RelationshipByIndex(varName, index, key,
value)
}
}
23. Por partes: Start Clause
package org.neo4j.cypher.parser
trait StartClause extends JavaTokenParsers with Tokens {
def start: Parser[Start] = ignoreCase("start") ~> rep1sep(nodeByIds | nodeByIndex | nodeByIndexQuery |
relsByIds | relsByIndex, ",") ^^ (Start(_: _*))
def nodeByIds = identity ~ "=" ~ "(" ~ rep1sep(wholeNumber, ",") ~ ")" ^^ {
case varName ~ "=" ~ "(" ~ id ~ ")" => NodeById(varName, id.map(_.toLong).toSeq: _*)
}
def nodeByIndex = identity ~ "=" ~ "(" ~ identity ~ "," ~ identity ~ "," ~ string ~ ")" ^^ {
case varName ~ "=" ~ "(" ~ index ~ "," ~ key ~ "," ~ value ~ ")" => NodeByIndex(varName, index, key, value)
}
def nodeByIndexQuery = identity ~ "=" ~ "(" ~ identity ~ "," ~ string ~ ")" ^^ {
case varName ~ "=" ~ "(" ~ index ~ "," ~ query ~ ")" => NodeByIndexQuery(varName, index, query)
}
def relsByIds = identity ~ "=" ~ "<" ~ rep1sep(wholeNumber, ",") ~ ">" ^^ {
case varName ~ "=" ~ "<" ~ id ~ ">" => RelationshipById(varName, id.map(_.toLong).toSeq: _*)
}
def relsByIndex = identity ~ "=" ~ "<" ~ identity ~ "," ~ identity ~ "," ~ string ~ ">" ^^ {
case varName ~ "=" ~ "<" ~ index ~ "," ~ key ~ "," ~ value ~ ">" => RelationshipByIndex(varName, index, key,
value)
}
}
24. AST
Query.scala
package org.neo4j.cypher.commands
case class Start(startItems: StartItem*)
StartItem.scala
package org.neo4j.cypher.commands
abstract sealed class StartItem(val variable:String)
abstract class NodeStartItem(varName:String) extends StartItem(varName)
case class NodeById(varName:String, id: Long*) extends NodeStartItem(varName)
26. Toda a query
package org.neo4j.cypher.parser
class CypherParser extends JavaTokenParsers with StartClause with MatchClause with WhereClause
with ReturnClause with SkipLimitClause with OrderByClause with StringExtras {
def query: Parser[Query] = start ~ opt(matching) ~ opt(where) ~ returns ~ opt(order) ~ opt(skip) ~ opt(limit) ^^ {
case start ~ matching ~ where ~ returns ~ order ~ skip ~ limit => {
val slice = (skip,limit) match {
case (None,None) => None
case (s,l) => Some(Slice(s,l))
}
val (pattern:Option[Match], namedPaths:Option[NamedPaths]) = matching match {
case Some((p,NamedPaths())) => (Some(p),None)
case Some((Match(),nP)) => (None,Some(nP))
case Some((p,nP)) => (Some(p),Some(nP))
case None => (None,None)
}
Query(returns._1, start, pattern, where, returns._2, order, slice, namedPaths)
}
}
35. Prós e Contras
+ Objetiva
+ Ops Friendly
+ Poderosa (algoritmos de grafos e pattern matching)
- Verbosa
- Performance (ainda)
+/- Work In Progress
Notas del editor \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n