OrientDB inconsistent vertex persist after remove edge with MMAPI - orientdb

Consider this code:
private void testMMAPIinLab() {
OrientDB orientDB = new OrientDB("remote:localhost",OrientDBConfig.defaultConfig());
OrientDBConfigBuilder poolCfg = OrientDBConfig.builder();
poolCfg.addConfig(OGlobalConfiguration.DB_POOL_MIN, 5);
poolCfg.addConfig(OGlobalConfiguration.DB_POOL_MAX, 10);
//poolCfg.addConfig(OGlobalConfiguration.RID_BAG_EMBEDDED_TO_SBTREEBONSAI_THRESHOLD, -1);
ODatabasePool dbPool = new ODatabasePool(orientDB,"lab", "root", "toor", poolCfg.build());
ODatabaseSession db = dbPool.acquire();
db.begin();
System.out.println("creando el vértice....");
OVertex v1 = db.newVertex();
v1.save();
System.out.println("save rid: "+v1.getIdentity().toString());
OVertex v2 = db.newVertex();
v2.save();
System.out.println("v2 save rid: "+v2.getIdentity().toString());
System.out.println("crear un edge.");
OEdge oe = v1.addEdge(v2);
v1.save();
System.out.println("llamando a commit...");
db.commit();
db.close();
System.out.println("configuración grabada:");
System.out.println("v1: "+v1.getIdentity().toString());
System.out.println("v2: "+v2.getIdentity().toString());
System.out.println("edge: "+oe.getFrom()+" --> "+oe.getTo());
// abrir otra transacción
db = dbPool.acquire();
db.begin();
System.out.println("crear v3");
OVertex v3 = db.newVertex();
v3.save();
System.out.println("v3 save rid: "+v3.getIdentity().toString());
System.out.println("modificar v1...");
v1.setProperty("value", "test");
System.out.println("borrar relación con v2");
// borrar el edge anterior
Iterator<OEdge> toRemove = v1.getEdges(ODirection.OUT).iterator();
while (toRemove.hasNext()) {
OEdge removeEdge = toRemove.next();
//removeEdge = (OEdge) edge;
removeEdge.delete();
removeEdge.save();
}
System.out.println("agregar una relación de v1 a v3");
OEdge oe2 = v1.addEdge(v3);
v1.save();
// crera en edge nuevo a v3
db.commit();
System.out.println("v1 edges: "+v1.getEdges(ODirection.OUT));
System.out.println("v3 post-commit rid: "+v3.getIdentity().toString());
System.out.println("oe2: "+oe2.getFrom()+" --> "+oe2.getTo());
db.close();
}
When you run it you get V1 with two out edges. One with the EdgeRID of the removed edge and one that point to V3.
I you clic over the removed edge it show {} and report a 404 error. The vertex are persisted so the error is inside the database.
The error is in the while that remove the edges. If you use the edge reference it work, but in the real code I do not know how many edges the vertex have.
V2 and V3 have the correct IN references.
How could I fix this?

This depends on the fact that vertices are shared between different database sessions.
An easy fix consists in reloading the vertices by ID before using them in the second session:
// abrir otra transacción
db = dbPool.acquire();
db.begin();
//RELOAD THE VERTEX BEFORE USING IT AGAIN!
v1 = db.load(v1.getIdentity());

Related

Identifying if 2 Vertices are connected with edge using Orientdb 3 and tinkerpop 3

I have been trying to look through documentation. I am just trying to find a simple example to identify as mentioned in the title if 2 vertices are connected to each other. This is for OrientDB 3 using the tinkerpop API blueprints 2.6.
Ex:
Vertex v1;
Vertex v2;
boolean connected = false;
connected = <somefunction returns true/false if v1 and v2 connected by an edge>;
Can someone please provide an example if they have seen something like this?
try this:
String db_name = "dbname";
String path = "remote:localhost/" + db_name;
OrientDB orientDB = new OrientDB("remote:localhost", "username", "password", OrientDBConfig.defaultConfig());
try(ODatabaseSession db = orientDB.open(db_name,"username","password"))
{
ORID theEdge = new ORecordId("edge_rid");
OEdge e = db.load(theEdge);
ORID theVertex = new ORecordId("v1_rid");
OVertex v1 = db.load(theVertex);
ORID theVertex2 = new ORecordId("v2_rid");
OVertex v2 = db.load(theVertex2);
boolean connected = false;
OVertex from = e.getFrom();
OVertex to = e.getTo();
if(from.getIdentity().equals(v1) && to.getIdentity().equals(v2))
{
connected = true;
}
if(connected)
{
System.out.println("Vertex v1: " + from.getIdentity());
System.out.println("Vertex v2: " + to.getIdentity());
}
}
Hope it helps
Regards
You need iterate one vertex(v1) edges and check if it s connecting to the other vertex(v2):
OrientVertex v1,v2;
for (Edge e : (Iterable<Edge>)() -> v1.edges(Direction.OUT))
if (e.vertices(Direction.IN).next().id().equals(v2.id())) {
}

creating edges by "joining" 2 classes

In Orientdb 3.0 RC1 (Tinkerpop/Gremlin community edition) I have 2 vertex classes:
- 'Company' with 1 property 'address'
- 'Address' with 1 property 'address' having a UNIQUE_HASH_INDEX on this property
Need to create edges of class 'Location' between 'Company' vertexes to the corresponding 'Address' vertex based on having the same 'address' property value.
First I tried using Gremlin the following way:
g.V().hasLabel("Company").as("a").
V().hasLabel("Address").as("b").
where("a", eq("b")).by("address").
addE("Location").next()
But the mid-traversal is not hitting the index .....I guess the OrientDB-Gremlin implementation not complete yet or my above query not good.
Then I converted the above to use a sideEffect():
g.V().hasLabel("Company").sideEffect{g.V().hasLabel("Address").has("address",it.get().property('address').value()).addE('Location').from(it.get()).next()}
but after quickly adding around 1k edges the query abruptly aborts and the OrientDB logs a lot of warnings like this:
"WARNI {db=ter1050} This database instance has 1280 open command/query result sets, please make sure you close them with OResultSet.close()"
So once again .....my query has a problem or I hit a bug.
I didn't find a way to do it in OrientDB SQL also.
I know this can be done using Tinkerpop API in Java but I was hoping for something more simple.
Try this:
OrientDB orientDB = new OrientDB("remote:localhost/", "<username>", "<password>", OrientDBConfig.defaultConfig());
ODatabaseDocument db = orientDB.open("<db name>","<username>", "<password>");
OResultSet result = db.command("select from Company");
OResultSet address_class = db.command("select from Address");
List<OResult> company = new ArrayList<OResult>();
List<OResult> address = new ArrayList<OResult>();
while(result.hasNext())
{
OResult record = result.next();
company.add(record);
}
while(address_class.hasNext())
{
OResult record = address_class.next();
address.add(record);
}
for(int i = 0; i < company.size(); i++)
{
String company_address = company.get(i).getProperty("address");
for(int j = 0; j < address.size(); j++)
{
String addresses = address.get(j).getProperty("address");
if(company_address.equals(addresses))
{
ORecordId company_rid = company.get(i).getProperty("#rid");
ORecordId addresses_rid = address.get(j).getProperty("#rid");
db.command("create edge Location from " + company_rid + " to " + addresses_rid);
}
}
}
db.close();
orientDB.close()
this is the result:
Hope it helps
Regards

OrientDB fails to persist a Vertex, returns ORID but with null vertex eg v(null)[#3:4]

I cant get OrientDB to persist an OrientVertex or an oDocument using the java API.
although its works when I use SQL and the OCommand.
trying to persist a vertex with foll code
val factory: OrientGraphFactory = new OrientGraphFactory("plocal:localhost/database", "admin", "admin");
val graph = factory.getTx
val oDocument: ODocument = UserEntityMapper.toODocument(user)
println("ODocument = = "+ oDocument)
val orientVertex = new OrientVertex(graph, oDocument)
println("BEFORE orientVertex = "+ orientVertex)
graph.commit()
println("AFTER orientVertex = "+ orientVertex)
I get debug printouts as
ODocument = {phoneNumber:45435345,email:moses#email.com,dateOfBirth:-766198800000,lastName:Johnson,firstName:Moses,avatarURL:null,loginInfo:{providerID:credentials,providerKey:moses#email.com},userID:a8d96be9-1d09-4e8f-bf8d-6a0d32e1e5aa}
BEFORE orientVertex = v(null)[#3:-2]
AFTER orientVertex = v(null)[#3:4]
As you can see, the vertex is null. Nothing is persisted. I get an ORID that changes the cluster position number.
When I repeat the save the cluster position number is incremented
BEFORE orientVertex = v(null)[#3:-3]
AFTER orientVertex = v(null)[#3:7]
Why does this happen and how can I fix this please? There are no exceptions so i cant tell whats wrong. The cluster/table for User exists on the DB with all teh right fields.
I am using orientdb-community-2.2.0 and Scala.
regards
Sorted it out at last. I was instantiating the ODocument without the class name. In
UserEntityMapper.toODocument(user)
I was doing the equivalent of this
new ODocument(Map("name"->"john", "city" -> "London"))
instead of this
new ODocument("User").fromMap(Map("name"->"john", "city" -> "London"))
So the DB did not pick up the User class.
Thanks actual for pointing me in the right direction

Entities may have been modified or deleted since entities were loaded. Error during transaction

During the execution of the following piece of code, I get the message
Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries.
And there are loads of occurrences of that in here, but I didn't find a solution to my problem.
This only happens to me because I'm running _db.SaveChanges() two times inside one transaction (_db is my database context object), and I HAVE to do so because I need the generated ID that it gives me in order to proceed with the code.
If anyone can help me, I'd appreciate it. Also, if you know a way to proceed without the two _db.SaveChanges() or with a different way of approaching the transaction, I welcome you to show it.
using (var trans = _db.Database.BeginTransaction())
{
try
{
var f = cbxFornecedor.SelectedItem as Fornecedor;
var c = new Compra
{
CompraId = compra.CompraId,
DataCompra = dtpDataCompra.Value,
ListaProdutos = new List<ListaProdutos>(),
Fornecedor = f,
Referencia = tbxReferencia.Text,
Situacao = rbtEntregue.Checked
};
_db.Compras.Add(c);
_db.SaveChanges();
foreach (var cada in _itens)
c.ListaProdutos.Add(new ListaProdutos
{
Compra = c,
CompraId = c.CompraId,
Produto = cada.ProdutoClasse,
ProdutoId = cada.ProdutoClasse.ProdutoId,
Valor = cada.ValorTotal,
Quantidade = cada.Quantidade,
});
foreach (var cada in c.ListaProdutos)
if (_db.ListaProdutos.Find(cada.CompraId, cada.ProdutoId) != null)
_db.Entry(cada).State = EntityState.Modified;
else
_db.ListaProdutos.Add(cada);
_db.Entry(c).State = EntityState.Modified;
_db.SaveChanges();
trans.Commit();
}
catch (Exception ex)
{
trans.Rollback();
MessageBox.Show(this, ex.Message, #"Erro", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
And, just to be clear, I know that my problem is with that fact that the transaction is there. I tried removing it and it worked. Also, if I take out the second _db.SaveChanges(), it works too.
The exception is only thrown in the second _db.SaveChanges(), and only if it is surrounded by the transaction block.
It is not direct answer to your question, but it may be helpful.
You do not need to specify Compra and CompraId for new ListaProdutos because EF smart enough to figure it out. Also it looks like that you do not need _db.ListaProdutos.Find(cada.CompraId, cada.ProdutoId) != null check because cada.CompraId - is new Id and it can not be in DB at this moment. Also you do not need _db.ListaProdutos.Add(cada); because EF already new that you are adding this records. Can you try next code?
var f = cbxFornecedor.SelectedItem as Fornecedor;
var c = new Compra
{
DataCompra = dtpDataCompra.Value,
ListaProdutos = new List<ListaProdutos>(),
Fornecedor = f,
Referencia = tbxReferencia.Text,
Situacao = rbtEntregue.Checked
};
_db.Compras.Add(c);
foreach (var cada in _itens)
c.ListaProdutos.Add(new ListaProdutos
{
Produto = cada.ProdutoClasse,
ProdutoId = cada.ProdutoClasse.ProdutoId,
Valor = cada.ValorTotal,
Quantidade = cada.Quantidade,
});
_db.SaveChanges();

Load the graph from the titan db for a specified depth in a single or efficitent query

We are using titan db to store the graph infomation. we have cassandra + es as backend storage and index. We are trying to load the graph data to represent the graph in the webui.
This is the approach i am following.
public JSONObject getGraph(long vertexId, final int depth) throws Exception {
JSONObject json = new JSONObject();
JSONArray vertices = new JSONArray();
JSONArray edges = new JSONArray();
final int currentDepth = 0;
TitanGraph graph = GraphFactory.getInstance().getGraph();
TitanTransaction tx = graph.newTransaction();
try {
GraphTraversalSource g = tx.traversal();
Vertex parent = graphDao.getVertex(vertexId);
loadGraph(g, parent, currentDepth + 1, depth, vertices, edges);
json.put("vertices", vertices);
json.put("edges", edges);
return json;
} catch (Throwable e) {
log.error(e.getMessage(), e);
if (tx != null) {
tx.rollback();
}
throw new Exception(e.getMessage(), e);
} finally {
if (tx != null) {
tx.close();
}
}
}
private void loadGraph(final GraphTraversalSource g, final Vertex vertex, final int currentDepth,
final int maxDepth, final JSONArray vertices, final JSONArray edges) throws Exception {
vertices.add(toJSONvertex));
List<Edge> edgeList = g.V(vertex.id()).outE().toList();
if (edgeList == null || edgeList.size() <= 0) {
return;
}
for (Edge edge : edgeList) {
Vertex child = edge.inVertex();
edges.add(Schema.toJSON(vertex, edge, child));
if (currentDepth < maxDepth) {
loadGraph(g, child, currentDepth + 1, maxDepth, vertices, edges);
}
}
}
But this is taking a bit lot of time for the depth 3 when we have more number of nodes exist in the tree it is taking about 1 min to load the data.
Please help me are there any better mechanisms to load the graph efficiently?
You might see better performance performing your full query across a single traversal execution - e.g., g.V(vertex.id()).outV().outV().outE() for depth 3 - but any vertices with very high edge cardinality are going to make this query slow no matter how you execute it.
To add to the answer by #Benjamin performing one traversal as opposed to many little ones which are constantly expanding will indeed be faster. Titan uses lazy loading so you should take advantage of that.
The next thing I would recommend is to also multithread each of your traversals and writes. Titan actually supports simultaneous writes very nicely. You can achieve this using Transactions.