Specific relationship vs Label

Hi guys, newbie here! I'm kinda in doubt if it's better using specific relationships or labels, but first let me give you a little bit more context.

Suppose that the graph should be able to answer the following questions/queries:

  • Given a person, return all the emails associated;
  • Given a person, return all the contacts;

I've come up with these 2 possible models:

They're both able to fulfill the require requests with the following queries:

First model:

  • MATCH (p:Person {name:"Bob"})-[:REACHABLE_BY]-(e:Email)
    RETURN p.name AS Name, e.contact​ AS Contact
    
  • MATCH (p:Person {name:"Bob"})-[:REACHABLE_BY]-(c:Contact)
    RETURN p.name AS Name, c.contact​ AS Contact
    

Second model:

  • MATCH (p:Person {name:"Bob"})-[:REACHABLE_BY_EMAIL]-(c:Contact)
    RETURN p.name AS Name, c.contact​ AS Contact
    
  • MATCH (p:Person {name:"Bob"})-[:REACHABLE_BY_FAX]-(c:Contact)
    RETURN p.name AS Name, c.contact AS Contact
    UNION ALL
    MATCH (p)-[:REACHABLE_BY_EMAIL]-(c2:Contact)
    RETURN p.name AS Name, c2.contact AS Contact
    

    But I'm wondering if there's a best practice to follow in this case. I mean, I know that having specific relationships in some cases is better since we reduce the number of nodes involved in the query (instead of filtering later by some property), but I feel like that in this case we can achieve the same result (maybe also in performance) by considering different labels.

I think the appropriate data model is determined by your query patterns. In your case, the query will find one of the relationship nodes as the anchor node for the query. It will then will 'expand all' to find the appropriate relationships. After that, it will filter on the other node to meet the pattern conditions. As you correctly stated, having a general relationship type requires the query to examine all nodes of the relationship to determine if each node meets the node's criteria, while a specific relationship type can filter out the relationships that don't match; thereby, potentially reducing the number of nodes to evaluate. Based on your query pattern, it seems the specific relationship types may be better.

By the way, are you getting the results you expect with the 'UNION' query? The Person node 'p' is not passed to the second match, but will match with all nodes. The following refactor should work:

MATCH (p:Person{name: "Bob"})
call {
    with p
    MATCH (p)-[:REACHABLE_BY_FAX]-(c:Contact)
    RETURN c.contact AS Contact
    UNION
    with p
    MATCH (p)-[:REACHABLE_BY_EMAIL]-(c:Contact)
    RETURN c.contact AS Contact
}
RETURN p.name AS Name, Contact

You can also perform the same query as follows:

MATCH (p:Person {name:"Bob"})-[:REACHABLE_BY_FAX|REACHABLE_BY_EMAIL]-(c:Contact)
RETURN p.name AS Name, c.contact​ AS Contact

Thanks @glilienfield for the clear explanation! And yeah, you were totally right on the fact that I was using the UNION clause incorrectly, much appreciated also on that one.

So, now, considering the second model, I've another (possibly silly) doubt and that is the fact of having the properties on the node or on the relationship. Basically:
a)1.png

b)2.png

I mean, giving the fact that in this particular model a single contact is always associated with a single person, is there any pros/cons having the details of the "contact" as a relation properties? The only one the pops in my mind is the fact that there will be a single node "Contact" and that all the "Person" will have at least one arrow pointing to that node (i.e. a single node with tons of incoming arrows), but I'm not really sure if that's really a problem at all in Neo4j.

I generally only use relationship properties if the describe something between the two entities, like a weight property, or quantity property, etc. In your case, the properties seem to be attributes of the contact.