简体   繁体   中英

Neo4J cypher query for “inherited” terms

Using the community edition of neo4j v2.1.7, I am creating nodes to represent licenses.

Each license has terms and can "inherit" terms from another license. Terms local to a license shadow the same terms in the inherited license.

I am attempting to write a cypher query that will match on local and inherited terms.

This is easier to demonstrate with some code.

I create a license that inherits from another license:

create 
(l1:License)-[:inherits]->(l2:License),
(l1)-[:term]->(:Foo{value:"A"}),
(l1)-[:term]->(:Lar{value:"C"}),
(l2)-[:term]->(:Lar{value:"D"}),
(l2)-[:term]->(:Bar{value:"B"})

I want a query that will find licenses that have or inherit the following terms: Foo = A, Bar = B, Lar = C

So l1 would match since it has the right values for Lar and Foo and inherits Bar with the right value.

l2 wouldn't match since it does not have the right Lar and is missing Foo.

I tried the following, but it seems cumbersome and has at least two issues:

  1. I added "optional match (l1)-[:inherits]->(l2:License)" because I wanted to match on licenses that did not inherit other license terms. However, for some reason I don't grok, the optional match gives me both License nodes in the graph.

  2. How can I test whether a property is in a range? In other words, what if a License has a property that is a date like "20150101" and I want to test for values between 20140101 and 20140101? Since my "where" is testing the existence of paths, I don't see how to test whether a property is greater than or less than another value.

Incorrect cypher query:

match (l1:License)
optional match (l1)-[:inherits]->(l2:License)
where 
( 
   (l1)-[:term]->(:Foo{value:"A"}) OR 
   (
       not((l1)-[:term]->(:Foo{value:"A"}))
       and
       (l2)-[:term]->(:Foo{value:"A"})
   )
)
AND
(
   (l1)-[:term]->(:Bar{value:"B"}) or 
   (   
      not((l1)-[:term]->(:Bar{value:"B"}))
      and 
      (l2)-[:term]->(:Bar{value:"B"})
    )
)
AND
(
   (l1)-[:term]->(:Lar{value:"C"}) or 
   (
      not((l1)-[:term]->(:Lar{value:"C"})) and
      (l2)-[:term]->(:Lar{value:"C"})
   )
)
return count(l1)

Thanks in advance!

I think you still think too much in relational terms, your query looks like a lot of joins.

I think something like this will suffice.

// find the 3 terms
MATCH (t1:Foo {value:"A"}),(t2:Bar {value:"B"}), (t3:Lar {value:"C"})
UNWIND [t1,t2,t3] as term
// use them as starting point
MATCH path = (l:License)-[:INHERITS*0..]->(l2)-[:TERM]->(term)
RETURN l,l2,term, path

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM