Run Cypher statement on a filtered graph

Is there a way to run an arbitrary cypher statement on a filtered graph? By filtered, I mean a graph that consists of those nodes and relationships that fulfill a certain property. I'm thinking of some 2-phase structure, where the first part filters the graph and the second part could be any vaild cypher query. If it makes things easier, the second part may be read-only...

Hi Matt
In order to determine whether or not there is a way it would help if you could share a specific example of the "2-phase structure" what you have in mind
Rgds

Hey Arthur

I wanted to keep this as generic as possible to not restrict the possible solutions :grin:
But since you're asking: I've been thinking of either

  • a combined cypher statement where one part is kind of static (only depending on the filter) and the other part is the arbitrary cypher statement or
  • a procedure which can be called to yield the desired filtered graph on which the arbitrary cypher statement can be run or
  • any other idea on how the requirement of having some 'static' and some 'dynamic' part could be achieved

Best regards

hi Matt
Thanks for your clarification; however the question is still to general and thus also i believe the answer at this point in time
Cypher is very flexibel and I am sure that there will be a solution for your thoughts.
As said as soon you have a more specific example and there is still need for some help kindly let me know.
Rgds

Not sure if you need to implement query using WITH clause
https://neo4j.com/docs/cypher-manual/current/clauses/with/

Allright...

in our use cases, we often have to query and traverse a graph, that only consists of nodes and relationships that match certain conditions.

In this case, it's temporal information, meaning a node and a relationship has some validity and the query should only be applied to the nodes and relationships that are vaild at a given time.

Let's say, we have some companies and people (nodes) that exist for some interval and :works_for relationships.

Now I'd like to have a kind of extracted graph for lets say 2019 to answer who works for which company.
So there are two parts in this:

  • a filtering for x.start <= 2019 AND x.end > 2019 which is kind of always the same and thus 'static' and
  • a query (a) -[:works_for]-> (b) which could be any arbitrary query

Hope that helps to see my thoughts...

Hi, Matt
Are you talking about something like a virtual graph maybe?
http://neo4j-contrib.github.io/neo4j-apoc-procedures/3.5/virtual/virtual-graph/

Hi Vlad

That looks really promising! Can you give an example on how the part with (a) -[:works_for]-> (b) would be applied then? I mean, I think there needs to be some 'glue' between the YIELD graph and the other cypher statement...

Actually, I am not sure that it is really something what you want - it's just create an object (map) matched queried graph of structure:
{
"name": "",
"relationships": [ ],
"nodes": ,
"properties": { }
}
Then you can filter this object not a "graph" anymore.
Created a small example here:

1 Like

Just realize, maybe you need a custom cypher execution?
Then you can try apoc run.
You can use it as "graph" to "graph" projection with any hell inside:
http://neo4j-contrib.github.io/neo4j-apoc-procedures/3.5/cypher-execution/running-cypher/

Well, I think it's close to what I'm looking for! Had to tweak it a bit for my use case (see comment in your gist) and it works under certain conditions :grin:
However, I see some limitations:

  • for {lookAt: '1'} it should yield a lone node (N1). The query doesn't because the restriction is on the relationship… not sure yet how to fix that :roll_eyes:
  • correct me if I'm wrong, but with this approach, body can't be a more sophisticated query, right? sometimes there would be the need for WHERE clauses and the like...

One more fancy example for you, now with apoc.cypher.run. same gist, Matt.

In your example in gist comment for me is too hard to understand, what you try to achieve. Can you provide me exact needs: let's have a graph of nodes and relationships, so you can express what we looking for and I will write query with static and dynamic parts for you?2019-11-28_165551

First of all, thanks for your effort :slightly_smiling_face:

In the given example, I tried to verify the different approaches. I made a sketch for me, what filtered graph I'm expecting for a given lookAt:

Working with this, I'd like to compose queries like

MATCH (a) -[r]-> (b)
WHERE a.anyProperty=x AND r.anyOtherProperty=y
RETURN b

(what I call the 'dynamic' part)

Depending on the lookAt Parameter I would expect different results then.

1 Like

Here is a graph, where potentially some nodes can match or not match one of your 10 patterns.
2019-11-29_102839

(n1:Root:Red { id:'N1', color: "Red", size: 1000 }),
(n2:Root:Green { id:'N2', color: "Green", size: 2000 }),
(n3:Root:Blue { id:'N3', color: "Blue", size: 3000 }),
(n4:Root:Purple { id:'N2', color: "Purple", size: 2000 }),
(n5:Root:Orange { id:'N1', color: "Orange", size: 3000 });

Cypher here, hope it is helpful for your:

1 Like

Hm, not sure if you got me right.. the graphs on my sketch represent the virtual / filtered / sub- graphs of my "main graph" depending on the selected lookAt. I think a flattened graph like the one you created is not what I want.

But maybe let me take another step back. I want to show how the "interaction" with the query should look like - at least in my perception.

I'd like to build something like this (some pseudo code):

testExecution() {
  var query = 
    "MATCH (a) -[r]-> (b)
        WHERE a.anyProperty=x AND r.anyOtherProperty=y
        RETURN b";

  var ans1 = executeQueryForLookAt(query, "3");

  assertThat(ans1).hasCountOfNodes(2);
  assertThat(ans1)
    .hasNode("N1").and()
    .hasNode("N2").and()
    .not().hasNode("N3");
  assertThat(ans1)
    .hasRelationship("r1");

  var ans2 = executeQueryForLookAt(query, "6");

  assertThat(ans2).hasCountOfNodes(3);
  assertThat(ans2)
    .hasNode("N1").and()
    .hasNode("N2").and()
    .hasNode("N3");
  assertThat(ans1)
    .hasRelationship("r2").and()
    .hasRelationship("r3").and()
    .hasRelationship("r4").and()
    .not().hasRelationship("r1");
}

executeQueryForLookAt(query: string, lookAt: string) {
  var template = "..."; // i.e. the magic thing I'm looking for
  template.$lookAt = lookAt;
  template.$q = query;
  return db.run(template.resolved());
}

it's not possible out of the box.
Basically what you want is views, which is a planned feature but not worked on yet.

I thought about adding it to apoc to create a temporary in-memory instance populate it with the virtual graph and query it there. (need to create that as a GH issue)

Depending a bit how complex your derived statement/graph is you could either try:

  1. to use a temporary label on nodes
  2. to create virtual nodes and then use a procedure to "operate" on those nodes with getRelationships etc.
  3. there were some approaches to implement a cypher runtime on other datastructures but afaik it's not been published yet
2 Likes

Hi Michael

Is there any timeline for this feature? :grimacing:

Thanks anyway for your response! Could you illustrate the first two options you mentioned?

Rgds
Matt

no timeline unfortunately.

The first one would be just to label nodes (temporarily even in a tx) with a "ViewXx" label and then only using nodes with that additional label in your derived query.

The 2nd is just to use the VirtualNode/Rel from APOC, and then have in the "query" code using the Java API on top of those.