Ostico / PhpOrient

PhpOrient - Official Php driver based on the binary protocol of OrientDB.
Other
68 stars 37 forks source link

How to create an edge in a transaction #72

Open forty1 opened 8 years ago

forty1 commented 8 years ago

I use PHP 5.5 and try to create an edge. I used the command function:

function createEdge($rIdVertex1, $rIdVertex2, $paramValue){
    $SQL = 'CREATE EDGE MyEdge'.
            ' FROM #'.$rIdVertex1->cluster.':'.$rIdVertex1->position.
            ' TO #'.$rIdVertex2->cluster.':'.$rIdVertex2->position.
            ' SET paramvalue='.$paramValue;
    return $this->dbclient->command($SQL);
}

It worked fine but now I need it in a transaction. My code looks like the next example:

$tx = $this->client->getTransactionStatement();
try{
            $tx = $tx->begin();
            $createCommand = $this->daoSimilarities->createEdge($recVertex1->getRid(), $recVertex2->getRid(), 0);
            $tx->attach($createCommand);
            $result = $tx->commit();
            ...
}catch( Exception $e){
            $tx->rollback();
            return self::getErrorResult(....);
}

But I get an error by using commands in a transaction (ERROR: Wrong command type PhpOrient\Protocols\Binary\Operations\Command).

I changed the type and used recordCreate.

function createEdge($rIdVertex1, $rIdVertex2, $paramValue){
    return $this->dbclient->recordCreate(
                (new Record())
                    ->setOData( ['paramvalue' => $paramValue, 'out' => $rIdVertex1, 'in' => $rIdVertex2] )
                    ->setOClass('MyEdge')
                    ->setRid(new ID($this->cluster))
            );
}

Finally my edge was created but only the edge had 'out' and 'in' parameters, not the verteces (vertex1, vertex2). If I use shortestPath of vertex1 and vertex2 it will not find any path. Does somebody has a solution for that problem?

forty1 commented 8 years ago

I am sorry to ask it again but are there any solutions to create an egde in a transaction?

smolinari commented 8 years ago

Out of curiosity, but what leads you to believe you need a transaction to create an edge?

Scott

andreyvk commented 8 years ago

Makes sense to me. Sometimes a few records within a transaction could get connected. Besides, edge is also a record, if it's not a light edge. Therefore, any record should be able to be placed within a transaction

Sent from my iPhone

On May 20, 2016, at 23:02, Scott notifications@github.com wrote:

Out of curiosity, but what leads you to believe you need a transaction to create an edge?

Scott

— You are receiving this because you are subscribed to this thread. Reply to this email directly or view it on GitHub

smolinari commented 8 years ago

Yes, if you are doing more than just creating an edge, you might want a transaction. But, isn't the creation of an edge atomic itself?

Scott

forty1 commented 8 years ago

Thanks for your response. The clue is, that it is not allowed to have two edges between two vertices.

Example: Users can vote the similarity between two movies. If there’s no connection, an edge (similarity) will be created. If one already exist, only the weight of the edge will be changed.

Finally I have to check if a direct path exist between the two specific movies, if not I create one. So how should I avoid that two user vote the same movies at the same time? Is it possible to adjust that only one similar edge exist? Lightweight Edge is not a solution for me because I have a property on my edge.

smolinari commented 8 years ago

Your domain problem sounds similar to another thread I was discussing in the ODB Google group and I believe your logic problem is similar. To find out if someone has already done a "vote" (or rating), one would have to know about the votes (or ratings). That means, the votes are an object and should be a vertex and not an edge. Once votes are a vertex, then thinking logically about them becomes much easier. Working with them also becomes easier in ODB, because you can use the unique index on the relationships (the edges) between the votes, the users and the movies. You can do a lot more with that data structure, than you can with trying to make an edge work like an object, which it isn't. An edge should only signify a relationship. This is the structure I'd suggest.

user <=voted=> similarity_vote <=similar_to=> movie1 .................................................<=similar_to=> movie2

So the logic is...

  1. Check to see if the vote is already made between two particular movies.
  2. If not, add vote and connect them with the 3 edges accordingly. And, that would require a transaction and we are back to your old problem.

Check out this test on how a transaction (sh)could be used.(?)

https://github.com/Ostico/PhpOrient/blob/master/tests/PhpOrient/TxCommitTest.php

Maybe it might help. :smile:

Scott

forty1 commented 8 years ago

Thank you for the detailed answer and I am sorry if we lose the focus of the question.

I am open-minded for the structure and I had a similar one at the beginning. How do you select all similar movies of a reference movie for all user votes? For the current structure queries would look like:

Example for current structure: movie1 <= (0,5) => movie2 <= (0,4) => movie3 <= (0,5) => movie4 The similarity of the movies 1 and 4 is 10%, for example.

How do you find out the similarity of movie 1 and 4 at the new structure? Is the new structure right?

User1 <= (voted) => vote: 50% <= (similar_to) => movie1
............................. <= (similar_to) => movie2

..... <= (voted) => vote: 50% <= (similar_to) => movie3
............................. <= (similar_to) => movie4

User2 <= (voted) => vote: 40% <= (similar_to) => movie2
............................. <= (similar_to) => movie3

Maybe it will help me if you send me the link of the ODB Google group discussing?

smolinari commented 8 years ago

Naw, the discussion in GG is a bit different.

Now that you've explained a bit more, I understand your domain a bit better. I was under the impression, the votes had to be related to the users. If that isn't the case, then you are right. The relationship is the similarity and not the vote itself.

This will probably show my incompetence, but how did you come up with the 10% similarity in your example?

Scott

forty1 commented 8 years ago

Hey Scott. The calculation was:

movie1 - movie2: 100 *0,5 = 50%
movie1 - movie3: 50  *0,4 = 20%
movie1 - movie4: 20  *0,5 = 10%

Finally I still have the problem: how do I avoid that two user vote the same movies at the same time? Transaction is the only way I know, but it doesn't work :(

smolinari commented 8 years ago

Ahhh! See, I knew I was on to something. If you need to know about the votes made between users, then you need the votes as vertices. If you need the calculation of the relationships to each movie, that is a different graph. I would assume, the votes also change the amount of the relationship? So, you need both.

movie <= similarity => movie

and

user <= voted => vote <= similar_to => movie1 ----------------------------<= similar_to => movie2

Whether or not you can do the same calculation with only the lower graph, is beyond my own capabilities. Sorry....

Scott

forty1 commented 8 years ago

Hey Scott,

thank you for your advice and your help. I will think about it. But I am thinking "similar" as andreyvk ;D There are plenty of reasons why an edge should be created in a transaction. You can even find one example in OrientDB documentation (http://orientdb.com/docs/2.1/Concurrency.html).

smolinari commented 8 years ago

Yes, I am not denying the edge in this case should be created in a transaction with the other tasks that need to get done.

Actually now digging into your code, what is $this->daoSimilarities? Because, theoretically, the returned value of your createEdge function should be the input to the attach method.

Scott

dadagama commented 7 years ago

i'm having the same issue trying to create a bunch of edges with transactions, so tried a workaround using sqlBatch approach:

  $cmd = 'BEGIN;';
  foreach ($edges as $edge) {
    $cmd .= 'CREATE EDGE myClass FROM ' . $edge['in'] . ' TO ' . $edge['out'] . ';';
  }
  $cmd .= 'COMMIT RETRY 100;';
  $this->client->sqlBatch( $cmd );

https://github.com/Ostico/PhpOrient#execute-orientdb-sql-batch not sure if that has the same effect