简体   繁体   中英

Cypher query based on node attributes

In an effort to teach myself neo4j, I've modelled some behaviours in a game I play.

I have created a neo4j database with schema: My database schema

So Platform's have Equipment which have Modes. In the game, Platforms can interact when they have a common mode. Any object in the game can be affected by events in time which makes them non-functional. In the graph database, these events are modelled as events, which may affect one or more node.

I created a query which enables me to ask 'what does the network look like in year {year}', which works by saying return all nodes that do not have an association with an event:

MATCH (any)
OPTIONAL MATCH (any)--(event:Event) 
WHERE event.year < 2031
WITH any, event
WHERE event IS NULL AND NOT "Event" in LABELS(any)
MATCH(any)
OPTIONAL MATCH (any)<-[:PARTIAL]-(e:Event)
RETURN any, e

Which gives me the graph which represents the network I am modelling in the year '2030'. Here is the graph before any events (year=2000) Here is the graph after the first event (year=2031)

I would like to ask further questions of the subgraph returned by the above query, such as 'How many modes does a platform have access to in a given year?'. I'm tried adapting the above query:

MATCH (p:Platform),(e:Equipment),(m:Mode)
OPTIONAL MATCH (p)--(event:Event), (e)--(event), (m)--(event) 
WHERE event.year < 2031
WITH p,e,m, event 
WHERE event IS NULL 
MATCH(p),(e),(m) 
RETURN p, e, m

But this doesnt get me closer to where I want because it returns everything.

Assuming I'm not attempting to do something which is inherently crazy (I'm struggling to find good resources to learn how to do similar queries), how can I bend cypher to get the information. I apologise for clarity- I am not so familiar with the domain to use the correct terms for what I am attempting to do. The closest description I've found is "Extracting sub-graphs where no node in that sub-graph has a relationship with a node of particular type with particular attributes"

Any help appreciated!

Edit : After some playing I came up with (I suspect a really inefficent way) of returning all equipment that has no events, or has events that happen beyond a given year:

MATCH (e:Equipment)--(ev:Event)
WHERE ev.year > {year}
RETURN e
UNION 
MATCH (e:Equipment)
WHERE NOT (e)<--(:Event)
RETURN e

I also found this stack post that helped me, but I'm not sure if it can get me all of the way

This query might do what you want.

MATCH (p:Platform)
OPTIONAL MATCH (event:Event)--(p)
WHERE event.year < 2031
OPTIONAL MATCH (e:Equipment)--(event)
OPTIONAL MATCH (m:Mode)--(event) 
RETURN p, COLLECT(event) AS events, COLLECT(e) AS es, COLLECT(m) AS ms

For each Platform node, it looks for:

  • optional related Event nodes whose year < 2031.
  • optional Equipment nodes related to the above Event nodes.
  • optional Mode nodes related to the above Event nodes.

and returns, for each Platform node, a collection of its its related events, equipment, and modes.

Multiple hours head scratching and I have a way which works. I realise its probably an awful solution...

OPTIONAL MATCH (e:Equipment)--(ev:Event)
WHERE ev.year > {year}
WITH collect(e) as validE
MATCH (e:Equipment)
WHERE NOT (e)<--(:Event)
WITH (validE+collect(e)) as validE
UNWIND validE as e
WITH e
OPTIONAL MATCH (m:Mode)--(ev:Event)
WHERE ev.year > {year}
WITH e, collect(m) as validM
MATCH (m:Mode)
WHERE NOT (m)<--(:Event)
WITH e, (collect(m)+validM) as validM2
UNWIND validM2 as m
WITH m, e
MATCH (p:Platform)--(e)--(m)
RETURN p.name, count(m)

How it works:

  • Collect equipment that has no relationships to node events with property year value less than the year we are interested in
  • Unwind the equipment and use that to find related modes , again checking the year validity.
  • Finally, having collected the modes and equipments we are interested in, match the platforms .

Note:

  • In my instance the Optional match is important because it is possible that for the year of interest, there are no more 'future' events. This will cause the query to return no results.

I hope this helps someone in the future - any help making this slightly more optimal/friendly would be useful!

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