Controlling edge multiplicity and direction in OrientDB, can it be improved?

744 views
Skip to first unread message

scott molinari

unread,
Oct 27, 2015, 8:30:36 AM10/27/15
to OrientDB
Hi,

This comes from a discussion and resulting inquiry in the ODB Gitter chat, which got overlooked. 

It seems there is a way to control multiplicity of edges in ODB through edge constraints. 


The edge constraints are one of those usability things that make ODB less user friendly IMHO. 

Here are some multiplicity types taken from Titan's manual (because the way they are explained is simple to understand):

MULTI: Allows multiple edges of the same label between any pair of vertices. In other words, the graph is a multi graph with respect to such edge label. There is no constraint on edge multiplicity.
SIMPLE: Allows at most one edge of such label between any pair of vertices. In other words, the graph is a simple graph with respect to the label. Ensures that edges are unique for a given label and pairs of vertices.
MANY2ONE: Allows at most one outgoing edge of such label on any vertex in the graph but places no constraint on incoming edges. The edge label mother is an example with MANY2ONE multiplicity since each person has at most one mother but mothers can have multiple children.
ONE2MANY: Allows at most one incoming edge of such label on any vertex in the graph but places no constraint on outgoing edges. The edge label winnerOf is an example with ONE2MANY multiplicity since each contest is won by at most one person but a person can win multiple contests.
ONE2ONE: Allows at most one incoming and one outgoing edge of such label on any vertex in the graph. The edge label marriedTo is an example with ONE2ONE multiplicity since a person is married to exactly one other person.

Needless to say, because of this kind of abstraction, implementing such multiplicity while creating edges in Titan is fairly straight forward and simple. In ODB, well, it isn't quite so transparent or simple. This is along the lines of the requested usability abstraction discussed in this issue on Github

Let's go through the possibilities and see how ODB does them (and according to my understanding of ODB, which admittedly isn't great, so I could be wrong. Please correct me if I am!).

MULTI

This is a standard heavy weight edge in ODB. So, creating a heavy weight edge follows the MULTI multiplicity rule automatically.

SIMPLE

This seems like it would fall under the "UNIQUE" indexing method of an edge. However, I don't think that is completely right, because the UNIQUE index enforces a single in and out between two vertices. So using a UNIQUE index is more like the ONE2ONE. I believe this might be the equivalent to a light weight edge, but with an added unique index.(?)

MANY2ONE

I believe this can be done with the in and out constraints.

ONE2MANY

Same as above.

ONE2ONE

Available through the UNIQUE constraint.

So, through this exercise, I think I have learned that ODB can cover all multiplicity scenarios, though, I am absolutely not certain. Why must I be uncertain? This whole concept could be simplified by using the same terms Titan uses. It seems the abstraction is necessary. I believe it would make ODB easier to understand. 

Maybe these suggestions could be worth thinking about. Starting from the Cars database example taken from the docs

Creating the edge classes stays the same. 

orientdb> CREATE CLASS Owns EXTENDS E
orientdb> CREATE CLASS Lives EXTENDS E

SIMPLE (a standard light weight edge, but automatically allows multiple light weight edges, which seems a step above TItan!)

orientdb> CREATE EDGE Owns FROM ( SELECT FROM Person ) TO ( SELECT FROM Car )

MULTI (an edge with properties is created/ heave weight edge, with in and out mandatory)

orientdb> CREATE MULTI EDGE Owns FROM ( SELECT FROM Person ) TO ( SELECT FROM Car )

MANY2ONE (not sure what needs to happen with in and out here)

orientdb> CREATE MANY2ONE EDGE Lives FROM ( SELECT FROM Country ) TO ( SELECT FROM Person )

ONE2MANY (same as above, not sure about what needs to happen with in and out)

orientdb> CREATE ONE2MANY EDGE Owns FROM ( SELECT FROM Person ) TO ( SELECT FROM Cars )

ONE2ONE (this is a heavy weight edge, with an automatic UNIQUE constraint)

orientdb> CREATE ONE2ONE EDGE Owns FROM ( SELECT FROM Person ) TO ( SELECT FROM Cars )

UNIQUE (an additional constraint, only for light weight edges)

orientdb> CREATE UNIQUE EDGE Owns FROM ( SELECT FROM Person ) TO ( SELECT FROM Car )


To be honest, I am really not sure this covers all needed or wanted possibilities, when it comes to edge direction constraints or multiplicity. However, I know for a fact the above suggest SQL is a lot easier for me to understand., which is the goal of a declarative language like SQL. We are abstracting out three things as I see it. Edge type creation (light or heavy weight), edge direction and multiplicity.

As I look back at what I just wrote, I guess what I am uncertain about is how to actually create many-to-one and one-to-many edges in ODB. 

Any other thoughts on this and corrections to my thinking would be greatly appreciated.  

Scott
Message has been deleted

Ziink A

unread,
Oct 29, 2015, 12:06:01 PM10/29/15
to OrientDB
It seems to me that OrientDB's way is more versatile.

The 5 scenarios would be UNIQUE INDEX ON

1. no index
2. (in, out)
3. (in)
4. (out)
5. Two indices. (in), (out)

Why OrientDB is more versatile is that you could also include one or more edge properties in the index. So for example, if you are tracking the user who creates an edge and you want a user to have at most one edge connecting two vertices. Then the unique index would be on (in, out, user)

scott molinari

unread,
Oct 30, 2015, 8:39:08 AM10/30/15
to orient-...@googlegroups.com
Thanks for the input Ziink A. Though, you completely lost me with your example. 

I can't deny that ODB's approach might be more versatile. However, controlling multiplicity should be a lot more straightforward and I just don't see how it works with the available commands. Let me give it a try playing  with Studio and get back later.

Scott

Ata Annamamedov

unread,
Oct 31, 2015, 6:27:55 AM10/31/15
to orient-...@googlegroups.com
Agree to what Ziink said.

What is most important for us - syntax is consistent and not bloated with external logic.
Having this described in metadata (indexes) gives you the chance to change actual behaviour without rewriting the code.

WBR,
Ata

scott molinari

unread,
Oct 31, 2015, 7:15:18 AM10/31/15
to OrientDB
What external logic? You mean having to bind the logic for graph multiplicity and direction in your own code? I can agree with that. That would be ridiculous and why we ended up finding ODB too! We don't want to have to think about all that in detail.   

However, in this thread, we are talking about abstracting operations within the database to end up with more logical language constructs, so the ODB SQL+ is more declarative and concise, when building edge relationships and their direction. 

I still can't figure out how to do multiplicities of MANY2ONE and ONE2MANY with IN, OUT and UNIQUE constraints. That might be because, I just turned on light weight edges and am going bonkers with Studio trying to create edges that show up properly in the graph view with the right relationships. LOL! But, that is probably just me and my lack of knowledge. Though, if the change to heavy weight edges by default in 2.0.X was a matter of simplicity of use, I can now fully understand why light weight edges are now off by default. Using heavy weight edges seems so much easier. :-) 

I think I'll change back to heavy weight edges and see if I can do the  MANY2ONE and ONE2MANY with IN, OUT and UNIQUE constraints. 

Scott

scott molinari

unread,
Oct 31, 2015, 8:39:05 AM10/31/15
to OrientDB
I am going batty in general with Studio and creating edges. How come I can create a light weight edges, when the setting "useLightweightEdges" is set to false? Or do I need to create new classes after the setting was changed and only then will this setting be taken into account?

Scott

Ziink A

unread,
Oct 31, 2015, 12:05:32 PM10/31/15
to OrientDB
The 'useLightweightEdges' setting does not change any existing edges. So you need to create the classes after the setting change if that's what you want. Additionally, if you add a property to the lightweight edge, it is converted to a regular edge. 

As for Many2One and One2Many, you do need regular edges for that (not lightweight). For example

create class Owns extends E
create property out link Person
create property in link Tool
create index on Owns(in) unique

This will set up a One2Many where a Person 'Owns' one or more Tool but a Tool can be owned by only one Person because of the unique index on 'in'.

Similarly for Many2One

create class Belongs extends E
create property out link Tool
create property in link Person
create index on Belongs(out) unique

Here any given Tool can belong to only one Person but other Tools can also belong to the same Person.

Note: The syntax may be a little off.

scott molinari

unread,
Oct 31, 2015, 12:17:05 PM10/31/15
to OrientDB
Thanks Ziink A. 

But, be honest. Wouldn't a simple

orientdb> CREATE ONE2MANY EDGE Belongs FROM Person TO Tool

be easier, where ODB does the "linking" itself and with the right unique indexing on the right in or out properties?

Scott

Ziink A

unread,
Oct 31, 2015, 2:01:54 PM10/31/15
to OrientDB
You mean when you are actually defining the class, right? Otherwise, what happens when you use ONE2MANY in one statement but not in another?

So maybe something like this 

CREATE CLASS Belongs EXTENDS E FROM Person TO Tool ONE2MANY


I'd definitely like that too. However, considering there are already a number of issues with SQL parsing, I certainly wouldn't push for syntactic sugar. 

scott molinari

unread,
Nov 1, 2015, 2:31:37 AM11/1/15
to orient-...@googlegroups.com
Yes, exactly. I am looking for simpler commands, which help set up edge multiplicity and direction. I mean, it is the relationships and how they can be handled better/ easier/ more flexible, which make graph databases so cool. But, if you need to study a book and practice and practice just to create such relationships and, more importantly, to get them right for a particular data model, so they all work properly in an application, it just makes the hurdle to start with a graph database that much higher. I am already frustrated myself.....

I tried out your examples for MANY2ONE and ONE2MANY and they worked great. Thank you! 

Now another multiplicity scenario I need help with. The ONE2ONE. I created a "MariedTo" edge linked to the "Person" vertex in both in and out properties and with both in and out given a UNIQUE index, but that didn't work. I could still create another "MariedTo" edge to another Person Vertex. If you could help me out once more, what are the commands needed to create a bidirectional one to one relationship with a normal edge? 

Scott

Ziink A

unread,
Nov 1, 2015, 7:27:55 PM11/1/15
to OrientDB
This is a tricky one. From what I could make out OrientDB doesn't have support for ONE2ONE within a class. So I guess they do need to extend their SQL for this.

You could use one of two workarounds that might work

1. Have a spouse property of type link on Person where the linked type is Person. Update both records in your application code.

2. Use a stored function to add a property on the Edge that is an array containing both 'in' and 'out'. Create a unique index on this property.



I think you should add this as an Issue on Github.

scott molinari

unread,
Nov 2, 2015, 1:42:39 AM11/2/15
to OrientDB
Is there a way to do ONE2ONE between different classes? I'd play around with getting that going, but I upgraded my dev version of ODB and now Studio isn't working. :-(

I also created a suggestion and an issue. 

Ata Annamamedov

unread,
Nov 2, 2015, 2:35:06 AM11/2/15
to orient-...@googlegroups.com
Scott, to add what Ziink said,

this is tricky one not because of OrientDB, but because of nature of Graph with directed edges (relations).
The problem here, is that A could be "husband" of B and B could be "husband" of C. 
Actually, there are more options to resolve that issue - one of them - you might want to have two different relations inherited from MarriedTo - isHusbandOf and isWifeOf.
Make two unique indexes for MarriedTo abstract class (for MarriedTo(in) and MarriedTo(out)). Then you might add some hook for every isHsubandOf insert, adding new corresponding isWifeOf edge with reversed in and out.

Now if you search for whom A MarriedTo (MarriedTo.out=A) - you have relation object of one of the two distinct classes: isHusbandOf or isWifeOf.

Ata Annamamedov

unread,
Nov 2, 2015, 2:42:32 AM11/2/15
to orient-...@googlegroups.com
Is there a way to do ONE2ONE between different classes?

Sure, it is as easy, as adding two indexes for in and out of the relation.

Just as in previous Ziink example:
create index on Owns(in) unique
create index on Owns(out) unique


It might be easier to understand, if you imagine, that vertexes don't know anything about their relations to other vertexes, only relations (themselves are objects, stored in one list) are aware of it. So you don't need to think about vertexes cardinality, but instead trying to make those relations as unique, as needed.

scott molinari

unread,
Nov 2, 2015, 3:03:21 AM11/2/15
to OrientDB
You see, that is the problem with me. ODB says, "Use the graph API, because then the graph relationships are handled automatically for you:" Well, that seems to be true, but only to a point. When you say I  have to still think about relationships being stored in some list and that vertexes are actually oblivious to how they relate to other vertexes, well, to me, that isn't a graph database. That is a document database with edges stored in a collection of documents. 

In other words, the fact that is actually what is happening in the background, shouldn't matter at all. The graph database should abstract the relationships to be meaningful, both from a graph usage perspective and a database operational perspective.

Scott 


Ata Annamamedov

unread,
Nov 2, 2015, 3:18:02 AM11/2/15
to OrientDB
I understand your point, but want to warn - if we are talking about graph database - understanfing, that edges are "first class citizens" - is essential.

Working with relations directly, thinking of them as of real (not hidden) part of the system is what makes this concept so powerful.

As in example with MarriedTo - it is ok to have this kind of link (named MarriedTo) in Document or Relational database and Ziink's first suggestion was to emulate that way for if you are easier with links. But here, in a Graph world - you have to think about directions and true meanings of relations you are going to map.

As of my suggestion to think about uniquness of edges - cardinality is just subset of way more possible constraints. You might have more properties in every edge and then, again, make them unique or not.

scott molinari

unread,
Nov 2, 2015, 4:48:45 PM11/2/15
to OrientDB
If I want to map marriedTo, (for monogamous marriages), then I want a one2one relationship. No more, no less. 

Thinking about if I wanted "IsHusbandOf" and "IsWifeOf" edges, those would be unidirectional edges. Hmm....that scenario isn't covered in my suggestion. Maybe that was the "SIMPLE" in Titan's multiplicity definitions? 

I understand the flexibility offered with ODB's edge constraints. I still think that flexibility could be abstracted out to more common sense and simpler commands. 

Scott
Reply all
Reply to author
Forward
0 new messages