Creating edges in strict mode in schema-full graph: problems with LINKBAG

199 views
Skip to first unread message

alicia....@gmail.com

unread,
Jul 2, 2015, 8:51:07 AM7/2/15
to orient-...@googlegroups.com
Hello,
I am new to OrientDB and I'm running into issues when creating edges in a schema-full graph.

I have 2 vertex classes:
  * Property 
  * Owner
both of which are in strict mode: vertexClass.setStrictMode(true)

I have 1 edge class:
  * Owns
which is also in strict mode and connects owners and properties:
  [Owner] ---[Owns]---> [Property]

An owner can own several properties.
A property can be owned by several owners.

I have the following requirements:
  * Everything must be strict:
      * Undeclared properties (properties that haven't been created with oClass.createProperty(...)) cannot be set in Owner, Owns and Property.
      * An Owns property cannot be used to connect anything other than an Owner to a Property (e.g., it cannot connect an Owner to an Owner)
  * There can be at most 1 Owns edge between an Owner and a Property.
  * The relationship must be bidirectional: there are use cases when I need to traverse from an Owner to all his Properties, and cases where I need to traverse from a Property to all its Owners.

Creating the classes for vertices Owner and Property is pretty straightforward. However the class for edge Owns is giving me trouble.
(I'll explain in detail in the hope of helping people who may run into the same issue)


Attempt #1

I created the following method...

protected OClass createEdgeClass(OSchemaProxy schema, String className, OClass superEdgeClass, OClass inVertexClass, OClass outVertexClass, boolean uniqueLink) {
   
if (superEdgeClass == null) {
      superEdgeClass
= schema.getClass(E);
   
}
   
OClass edgeClass = schema.createClass(className, superEdgeClass);
   edgeClass
.setStrictMode(true);
   edgeClass
.createProperty("in", OType.LINK, inVertexClass)
     
.setMandatory(true).setNotNull(true);
   edgeClass
.createProperty("out", OType.LINK, outVertexClass)
     
.setMandatory(true).setNotNull(true);
   
if (uniqueLink) {
     
// To prevent a pair of vertices (inVertex, outVertex) to be connected by more than 1 edge of this class.
      edgeClass
.createIndex("uniqueInOut", INDEX_TYPE.UNIQUE, "in", "out");
   
}
   
return edgeClass;
}

...which I invoke like this:

OClass ownsEdgeClass = createEdgeClass(schema, "owns", null, propertyVertexClass, ownerVertexClass, true);

This executes fine. However, later on, when I try to add an edge...

owner.addEdge(null, property, "owns");

...I get:

Caused by: com.orientechnologies.orient.core.exception.OValidationException: Found additional field 'out_owns'. It cannot be added because the schema class 'Owner' is defined as STRICT
at com.orientechnologies.orient.core.record.impl.ODocument.validate(ODocument.java:1948)
at com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx.save(ODatabaseDocumentTx.java:2252)
at com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx.save(ODatabaseDocumentTx.java:118)
at com.orientechnologies.orient.core.record.impl.ODocument.save(ODocument.java:1727)
at com.orientechnologies.orient.core.record.impl.ODocument.save(ODocument.java:1718)
at com.orientechnologies.orient.core.record.impl.ODocument.save(ODocument.java:76)
at com.orientechnologies.orient.core.serialization.serializer.record.binary.ORecordSerializerBinaryV0.recursiveLinkSave(ORecordSerializerBinaryV0.java:674)
at com.orientechnologies.orient.core.serialization.serializer.record.binary.ORecordSerializerBinaryV0.writeOptimizedLink(ORecordSerializerBinaryV0.java:688)
at com.orientechnologies.orient.core.serialization.serializer.record.binary.ORecordSerializerBinaryV0.writeSingleValue(ORecordSerializerBinaryV0.java:572)
at com.orientechnologies.orient.core.serialization.serializer.record.binary.ORecordSerializerBinaryV0.serialize(ORecordSerializerBinaryV0.java:261)
at com.orientechnologies.orient.core.serialization.serializer.record.binary.ORecordSerializerBinary.toStream(ORecordSerializerBinary.java:104)
at com.orientechnologies.orient.core.record.impl.ODocument.toStream(ODocument.java:2100)
at com.orientechnologies.orient.core.record.impl.ODocument.toStream(ODocument.java:695)
at com.orientechnologies.orient.client.remote.OStorageRemote.commitEntry(OStorageRemote.java:1998)
... 10 more

Because Owner and Property are strict, I have to explicitly declare the properties corresponding to the Owns in/out links.
=> attempt #2


Attempt #2

In my createEdgeClass method I add a couple of lines that declare the in/out properties in the inVertexClass and outVertexClass:

protected OClass createEdgeClass(OSchemaProxy schema, String className, OClass superEdgeClass, OClass inVertexClass, OClass outVertexClass, boolean uniqueLink) {
   
if (superEdgeClass == null) {
      superEdgeClass 
= schema.getClass(E);
   
}
   
OClass edgeClass = schema.createClass(className, superEdgeClass);
   edgeClass
.setStrictMode(true);
   edgeClass
.createProperty("in", OType.LINK, inVertexClass)
      
.setMandatory(true).setNotNull(true);
   edgeClass
.createProperty("out", OType.LINK, outVertexClass)
      
.setMandatory(true).setNotNull(true);
   
if (uniqueLink) {
      
// To prevent a pair of vertices (inVertex, outVertex) to be connected by more than 1 edge of this class.
      edgeClass
.createIndex("uniqueInOut", INDEX_TYPE.UNIQUE, "in", "out");
   
}
   inVertexClass.createProperty("in_" + className, OType.LINKSET, edgeClass);    // <---- this is new
   outVertexClass.createProperty("out_" + className, OType.LINKSET, edgeClass);  // <---- this is new
   
return edgeClass;
}

Now when I try to add an edge I get this:

Exception in thread "main" java.lang.IllegalStateException: Type of field provided in schema 'LINKSET' can not be used for link creation.
at com.tinkerpop.blueprints.impls.orient.OrientVertex.createLink(OrientVertex.java:144)
at com.tinkerpop.blueprints.impls.orient.OrientVertex.addEdge(OrientVertex.java:919)
at com.tinkerpop.blueprints.impls.orient.OrientVertex.addEdge(OrientVertex.java:807)

It turns out I should be using LINKBAG instead of LINKSET.
=> attempt #3


Attempt #3

I change the in_/out_ properties from LINKSET to LINKBAG:

protected OClass createEdgeClass(OSchemaProxy schema, String className, OClass superEdgeClass, OClass inVertexClass, OClass outVertexClass, boolean uniqueLink) {
   
if (superEdgeClass == null) {
      superEdgeClass 
= schema.getClass(E);
   
}
   
OClass edgeClass = schema.createClass(className, superEdgeClass);
   edgeClass
.setStrictMode(true);
   edgeClass
.createProperty("in", OType.LINK, inVertexClass)
      
.setMandatory(true).setNotNull(true);
   edgeClass
.createProperty("out", OType.LINK, outVertexClass)
      
.setMandatory(true).setNotNull(true);
   
if (uniqueLink) {
      
// To prevent a pair of vertices (inVertex, outVertex) to be connected by more than 1 edge of this class.
      edgeClass
.createIndex("uniqueInOut", INDEX_TYPE.UNIQUE, "in", "out");
   
}
   inVertexClass.createProperty("in_" + className, OType.LINKBAG, edgeClass);    // <---- changed from LINKSET to LINKBAG
   outVertexClass.createProperty("out_" + className, OType.LINKBAG, edgeClass);  // <---- changed from LINKSET to LINKBAG
   
return edgeClass;
}

Now I get:

Exception in thread "main" com.orientechnologies.orient.core.exception.OSchemaException: Linked class is not supported for type: LINKBAG
at com.orientechnologies.orient.core.metadata.schema.OPropertyImpl.setLinkedClassInternal(OPropertyImpl.java:394)
at com.orientechnologies.orient.core.metadata.schema.OClassImpl.addPropertyInternal(OClassImpl.java:1383)
at com.orientechnologies.orient.core.sql.OCommandExecutorSQLCreateProperty.execute(OCommandExecutorSQLCreateProperty.java:140)
at com.orientechnologies.orient.core.sql.OCommandExecutorSQLDelegate.execute(OCommandExecutorSQLDelegate.java:64)
at com.orientechnologies.orient.core.storage.impl.local.OAbstractPaginatedStorage.executeCommand(OAbstractPaginatedStorage.java:1194)
at com.orientechnologies.orient.core.storage.impl.local.OAbstractPaginatedStorage.command(OAbstractPaginatedStorage.java:1183)
at com.orientechnologies.orient.core.command.OCommandRequestTextAbstract.execute(OCommandRequestTextAbstract.java:63)
at com.orientechnologies.orient.server.network.protocol.binary.ONetworkProtocolBinary.command(ONetworkProtocolBinary.java:1179)
at com.orientechnologies.orient.server.network.protocol.binary.ONetworkProtocolBinary.executeRequest(ONetworkProtocolBinary.java:386)
at com.orientechnologies.orient.server.network.protocol.binary.OBinaryNetworkProtocolAbstract.execute(OBinaryNetworkProtocolAbstract.java:217)
at com.orientechnologies.common.thread.OSoftThread.run(OSoftThread.java:69)

because these two lines do not check against LINKBAG. IMO this is a bug; if not, what should I do differently? (And, in general: is this the right approach?)

Thanks,
Alicia

Luigi Dell'Aquila

unread,
Jul 3, 2015, 2:59:27 AM7/3/15
to orient-...@googlegroups.com
Hi Alicia,

yes, this is the right approach.
You can just avoid to define the linked class for LINKBAG, because if you use Graph API in_owns and out_owns will be guaranteed to contain only references to "owns" edges. So the following should be enough:

inVertexClass.createProperty("in_" + className, OType.LINKBAG); 

Thanks

Luigi

--

---
You received this message because you are subscribed to the Google Groups "OrientDB" group.
To unsubscribe from this group and stop receiving emails from it, send an email to orient-databa...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Alicia Lobo

unread,
Jul 3, 2015, 5:01:17 AM7/3/15
to orient-...@googlegroups.com
Hi Luigi,

Now it works, thanks :)
I'll post the working code in case it helps other people:


Attempt #4: success

protected OClass createEdgeClass(OSchemaProxy schema, String className, OClass superEdgeClass, OClass inVertexClass, OClass outVertexClass, boolean uniqueLink) {
   
if (superEdgeClass == null) {
      superEdgeClass
= schema.getClass(E);
   
}
   
OClass edgeClass = schema.createClass(className, superEdgeClass);
   edgeClass
.setStrictMode(true);
   edgeClass
.createProperty("in", OType.LINK, inVertexClass)
     
.setMandatory(true).setNotNull(true);
   edgeClass
.createProperty("out", OType.LINK, outVertexClass)
     
.setMandatory(true).setNotNull(true);
   
if (uniqueLink) {
     
// To prevent a pair of vertices (inVertex, outVertex) to be connected by more than 1 edge of this class.
      edgeClass
.createIndex("uniqueInOut", INDEX_TYPE.UNIQUE, "in", "out");
   
}
   inVertexClass.createProperty("in_" + className, OType.LINKBAG);
   outVertexClass
.createProperty("out_" + className, OType.LINKBAG);
   
return edgeClass;
}


This is fine for me now so I need no further help (for now... ;)), but IMHO OPropertyImpl.setLinkedClassInternal(OClass) should check against LINKBAG. It seems that LINKBAG was added in 1.7rc1; maybe no one remembered to update OPropertyImpl.setLinkedClassInternal(OClass) to check against it?

Thanks a lot!
Alicia

Sam Halliday

unread,
Dec 20, 2015, 6:07:42 PM12/20/15
to OrientDB
Thank you, this thread was very useful!

However, I'm still confused about how it works. This is my code (scala, but the Java interpretation should be obvious)

    val fileLink = schema.createClass(DefinedInS.label, g.getEdgeBaseType())
    fileLink.setStrictMode(true)
    fileLink.createProperty("out", OType.LINK, fqnSymbol).setNotNull(true)
    fileLink.createProperty("in", OType.LINK, fileCheck).setNotNull(true)
    fqnSymbol.createProperty("out_" + DefinedInS.label, OType.LINKBAG).setNotNull(true)
    fileCheck.createProperty("in_" + DefinedInS.label, OType.LINKBAG).setNotNull(true)

I'm confused why I need to create in_ and out_ properties on the vertices at all. It would appear that this is completely redundant. Also, I'm unable to set LINK constraints on the vertices, it has to be LINKBAG. But for this particular example, I want exactly one link from a fqnSymbol to a fileCheck.

In addition, what benefit would adding an index on fileLink give me? Is it going to result in faster lookup of a fileCheck when I have a fileSymbol?

I raised https://github.com/orientechnologies/orientdb/issues/5494 to request better documentation around this area.


Best regards,
Sam
...
Reply all
Reply to author
Forward
0 new messages