2

H-i, I want to display a force directed graph using in D3. I'm trying to model it with Neo4j.

The requirements are to decorate "Topics" and "Edges" with "Attachments". Topics and Edges display in the D3 graph. Attachments in a detail view of a Topic or Edge.

This is the conceptual model (Topics and Edges graphed in D3):

(attach1) -> (topic1) --edge12--> (topic2) <--edge23-- (topic3) <- (attach2)
                |         |           |          |
          (attach3)    (attach4)   (attach4)  (attach5)

The simplest thing that doesn't seem to work is:

Topics -> Nodes
Edges -> Relationships
Attachments -> Nodes

Neo4j doesn't have "hyperedges", so this instead:

Topics -> Nodes
Edges -> Nodes that relate only to Topics
Attachments -> Nodes that relate to Topics and Edges

That's wonky, but workable. An alternative would be make an Edge property with Attachment Ids, but that seems messy.

The next requirement is to do "Multi-topic search", which is a list of shortest paths between 2+ Topics - but only over Topics and Edges.

I found these questions that give I don't completely grok, but seem to explain how to filter the results. They don't seem very performant for an OLAP.

Is there a better way to model this directed graph in Neo4j?

Is there a better way to do the filtered multi-node search?

Thanks!

Community
  • 1
  • 1
Michael Cole
  • 15,473
  • 7
  • 79
  • 96

2 Answers2

2

[UPDATED]

Original answer

For historical interest, and as a comparison to the final solution, below, here is my original answer.

Since you cannot have a relationship connected directly to another relationship, you can reify Edge as a node. For example, here is a possible model:

(:Attachment) -[:FOR]-> (:Topic)
(:Attachment) -[:FOR]-> (:Edge)
(:Topic) <-[:FROM]- (:Edge) -[:TO]-> (:Topic)

Here is the query find the shortest path (or paths, if there is a tie) between any 2 specific Topics:

MATCH (t1:Topic { id: 't1' }), (t2:Topic { id: 't2' })
RETURN ALLSHORTESTPATHS((t1)-[:FROM|TO*]-(t2))

And here is a console that demos this.

Caveat: The above query does not enforce "sensible" directionality. So, for example, suppose the data looked like this (I replace the Edge nodes with arrows, for simplicity): (t1)->(t2)<-(t3). If we wanted the shortest path from t1 to t3, my query would return a path consisting of t1, t2, and t3, even though you cannot go from t2 to t3. Enforcing sensibility should be possible, but would make the query a bit more complex...

Improved answer

To enable "sensible" directionality (see above), we just have to make a minor change to my original data model by making the relationships to/from each Edge point in the same direction.

That is, instead of doing this:

(:Topic) <-[:FROM]- (:Edge) -[:TO]-> (:Topic)

we do this:

(:Topic) -[:TO_EDGE]-> (:Edge) -[:FROM_EDGE]-> (:Topic)

With this improved data model, the following query will enforce "sensible" directionality. Notice how the query now includes the < or > arrow to indicate the desired directionality:

MATCH (t1:Topic { id: 't1' }),(t2:Topic { id: 't2' })
RETURN ALLSHORTESTPATHS((t1)-[:FROM_EDGE|TO_EDGE*]->(t2))

Here is a console that demonstrates this improved data model and query. It returns the 2-edge path (from t1 to t2) as the "shortest path", since the 1-edge path has the wrong directionality.

Community
  • 1
  • 1
cybersam
  • 63,203
  • 6
  • 53
  • 76
  • Ok, thanks! An Attachment could point to two topics, making it part of the shortest path. Is there an easy way to exclude nodes and relationships by Label (or ?) with ALLSHORTESTPATHS? Is that what the [:FROM|TO*] is doing? (Sorry, have a bit to learn about Cypher) – Michael Cole May 29 '15 at 17:30
  • You got it, the attachments would use a `FOR` relationship type, and my query does not specify that as a type to match. Therefore, attachments will never be included in the shortest paths. – cybersam May 29 '15 at 17:33
  • Awesome! I win StackOverflow. Thanks :-) – Michael Cole May 29 '15 at 17:34
  • 2
    To be complete, I have added a caveat to the end of my answer. – cybersam May 29 '15 at 17:46
  • @cybersam: This is a very helpful answer. I'm currently running into the same problem. Could you give us a hint on how to specify sensible directionality? From what I understand of Neo4j's shortest path syntax in Cypher, I feel like it might not be possible at all. Please enlighten me. – mhelvens Sep 29 '15 at 18:43
  • 1
    OK, see my improved answer. – cybersam Sep 29 '15 at 19:50
  • That makes sense. :-) Small correction: In your new data model, you probably want both arrows to point in the other direction (or swap `TO_EDGE` with `FROM_EDGE`). – mhelvens Sep 29 '15 at 20:57
  • I actually meant to use that naming, but it is admittedly less readable than in the original answer. You can use whatever names you want, of course... – cybersam Sep 29 '15 at 21:03
  • Oh, my mistake. I see how to read your names now. Bit of an English ambiguity problem. – mhelvens Sep 29 '15 at 21:06
1

What about this kind of graph structure:

(topic_attachment_1)--(topic1)--(edge_attachment_1_2)--(topic2)--(topic_attachment_2)
                          |                                |
                      (topic3)                          topic(4)

Basically the idea is that attachments are modeled as nodes; a topic attachment just hangs off a topic, where an edge attachment sits between the two topics (so the edge attachment requires you to split the edge into two edges.

maxymoo
  • 35,286
  • 11
  • 92
  • 119