2013-03-01 122 views
6

ArangoDB提供文檔和邊緣作爲生成圖形的低級方法。如何用ArangoDB和PHP遍歷圖形

假設我們已經設置了一些帶有頂點和邊的圖。 該圖表示頂點之間的關係。

V2是V1
V3的孩子V2
V4的孩子V3
V5的孩子V1
V6的孩子V5的孩子

我們希望能夠查詢:

  1. 從V4的路徑V1
  2. V1的所有後代
  3. V1的孩子
  4. V4的所有祖先
  5. V4的父母

如何做到這一點在PHP?

回答

11

要做到這一點的方法是通過查詢ArangoDB的AQL(ArangoDB查詢語言)。

在AQL中使用圖表有幾條命令。 使用PHP,我們必須創建一個包含查詢的語句並執行它。

附加的代碼使用TRAVERSAL函數爲結果提供問題中提到的查詢。

該腳本設置文檔和邊緣集合,用頂點和邊連接邊緣,最後執行查詢以提供結果。

它可以按原樣執行並打印出所有結果。

<?php 

namespace triagens\ArangoDb; 


    // use this and change it to the path to autoload.php of the arangodb-php client if you're using the client standalone... 
    // require __DIR__ . '/../vendor/triagens/ArangoDb/autoload.php'; 

// ...or use this and change it to the path to autoload.php in the vendor directory if you're using Composer/Packagist 
require __DIR__ . '/../vendor/autoload.php'; 

// This function will provide us with our pre-configured connection options. 
function getConnectionOptions() 
{ 
    $traceFunc = function ($type, $data) { 
     print "TRACE FOR " . $type . PHP_EOL; 
    }; 

    return array(
     ConnectionOptions::OPTION_ENDPOINT  => 'tcp://localhost:8529/', 
     // endpoint to connect to 
     ConnectionOptions::OPTION_CONNECTION => 'Close', 
     // can use either 'Close' (one-time connections) or 'Keep-Alive' (re-used connections) 
     ConnectionOptions::OPTION_AUTH_TYPE  => 'Basic', 
     // use basic authorization 
     /* 
     ConnectionOptions::OPTION_AUTH_USER  => '',      // user for basic authorization 
     ConnectionOptions::OPTION_AUTH_PASSWD  => '',      // password for basic authorization 
     ConnectionOptions::OPTION_PORT   => 8529,     // port to connect to (deprecated, should use endpoint instead) 
     ConnectionOptions::OPTION_HOST   => "localhost",    // host to connect to (deprecated, should use endpoint instead) 
     */ 
     ConnectionOptions::OPTION_TIMEOUT  => 5, 
     // timeout in seconds 
     //ConnectionOptions::OPTION_TRACE   => $traceFunc,    // tracer function, can be used for debugging 
     ConnectionOptions::OPTION_CREATE  => false, 
     // do not create unknown collections automatically 
     ConnectionOptions::OPTION_UPDATE_POLICY => UpdatePolicy::LAST, 
     // last update wins 
    ); 
} 

// This function tries to create vertices and edges for the example 
function setupVerticesAndEdges($connection, $vertexCollection, $edgeCollection) 
{ 

echo "We are creating 6 vertices...<br> "; 
    //create example documents for the vertices 
    $nameV1  = 'v1'; 
    $documentV1 = Document::createFromArray(
     array('name' => $nameV1, '_key' => $nameV1) 
    ); 
    $nameV2  = 'v2'; 
    $documentV2 = Document::createFromArray(
     array('name' => $nameV2, '_key' => $nameV2) 
    ); 
    $nameV3  = 'v3'; 
    $documentV3 = Document::createFromArray(
     array('name' => $nameV3, '_key' => $nameV3) 
    ); 
    $nameV4  = 'v4'; 
    $documentV4 = Document::createFromArray(
     array('name' => $nameV4, '_key' => $nameV4) 
    ); 
    $nameV5  = 'v5'; 
    $documentV5 = Document::createFromArray(
     array('name' => $nameV5, '_key' => $nameV5) 
    ); 
    $nameV6  = 'v6'; 
    $documentV6 = Document::createFromArray(
     array('name' => $nameV6, '_key' => $nameV6) 
    ); 

    echo "We are creating 5 edges...<br> "; 
    //create example documents for the edges 
    $nameE1  = 'e1'; 
    $documentE1 = Edge::createFromArray(
     array('name' => $nameE1, 'label' => 'child_of') 
    ); 
    $nameE2  = 'e2'; 
    $documentE2 = Edge::createFromArray(
     array('name' => $nameE2, 'label' => 'child_of') 
    ); 
    $nameE3  = 'e3'; 
    $documentE3 = Edge::createFromArray(
     array('name' => $nameE3, 'label' => 'child_of') 
    ); 
    $nameE4  = 'e4'; 
    $documentE4 = Edge::createFromArray(
     array('name' => $nameE4, 'label' => 'child_of') 
    ); 
    $nameE5  = 'e5'; 
    $documentE5 = Edge::createFromArray(
     array('name' => $nameE5, 'label' => 'child_of') 
    ); 


    // Get instances of the vertice- and edgehandlers 
    $documentHandler = new DocumentHandler($connection); 
    $edgeHandler  = new EdgeHandler($connection); 

    // Save the vertices 
    try { 
     // query the given $collectionId by example using the previously declared $exampleDocument array 
     $result['v'][] = $documentHandler->save($vertexCollection, $documentV1); 
     $result['v'][] = $documentHandler->save($vertexCollection, $documentV2); 
     $result['v'][] = $documentHandler->save($vertexCollection, $documentV3); 
     $result['v'][] = $documentHandler->save($vertexCollection, $documentV4); 
     $result['v'][] = $documentHandler->save($vertexCollection, $documentV5); 
     $result['v'][] = $documentHandler->save($vertexCollection, $documentV6); 
    } catch (Exception $e) { 
      // any other error 
      echo ('An error occured. Exception: ' . $e); 
    } 


    // Save the edges 
    try { 
     echo "$nameV2 is a child of $nameV1<br> "; 
     $result['e'][] = $edgeHandler->saveEdge(
      $edgeCollection, 
      $vertexCollection . '/' . $nameV2, 
      $vertexCollection . '/' . $nameV1, 
      $documentE1, 
      $options = array() 
     ); 
     echo "$nameV3 is a child of $nameV2<br> "; 
     $result['e'][] = $edgeHandler->saveEdge(
      $edgeCollection, 
      $vertexCollection . '/' . $nameV3, 
      $vertexCollection . '/' . $nameV2, 
      $documentE2, 
      $options = array() 
     ); 
     echo "$nameV4 is a child of $nameV3<br> "; 
     $result['e'][] = $edgeHandler->saveEdge(
      $edgeCollection, 
      $vertexCollection . '/' . $nameV4, 
      $vertexCollection . '/' . $nameV3, 
      $documentE3, 
      $options = array() 
     ); 
     echo "$nameV5 is a child of $nameV1<br> "; 
     $result['e'][] = $edgeHandler->saveEdge(
      $edgeCollection, 
      $vertexCollection . '/' . $nameV5, 
      $vertexCollection . '/' . $nameV1, 
      $documentE4, 
      $options = array() 
     ); 
     echo "$nameV6 is a child of $nameV5<br> "; 
     $result['e'][] = $edgeHandler->saveEdge(
      $edgeCollection, 
      $vertexCollection . '/' . $nameV6, 
      $vertexCollection . '/' . $nameV5, 
      $documentE5, 
      $options = array() 
     ); 
     echo "<font style='font-family: monospace;'>"; 
     echo "$nameV1<br> "; 
     echo "+ $nameV2<br> "; 
     echo "| + $nameV3<br> "; 
     echo "| | + $nameV4<br> "; 
     echo "+ $nameV5<br> "; 
     echo "+ $nameV5<br> "; 
     echo "| + $nameV6<br> "; 
     echo "</font>"; 

     // return the result; 
     return $result; 
    } catch (Exception $e) { 
      // any other error 
      echo ('An error occured. Exception: ' . $e); 
    } 
} 


// helper function that takes the connection and the query to execute. 
function doAQLQuery($connection, $query) 
{ 
    // query through AQL 

    $statement = new \triagens\ArangoDb\Statement($connection, array(
                    "query"  => '', 
                    "count"  => true, 
                    "batchSize" => 1000, 
                    "_sanitize" => true, 
                   )); 
    $statement->setQuery($query); 
    $cursor = $statement->execute(); 

    $result = $cursor->getAll(); 

    return $result; 
} 


// AQL query example functions 


// Function that gets all paths from vertex v4 to v1 
function getPathFromV4ToV1($connection) 
{ 
    $query = 'FOR p IN PATHS(vertices_20130301_01, edges_20130301_01, "outbound") 
    FILTER p.source._id == "vertices_20130301_01/v4" && p.destination._id == "vertices_20130301_01/v1" 
    RETURN p'; 

    $result = doAQLQuery($connection, $query); 

    return $result; 
} 

// Function that gets the paths to all descendants of v1 

function getPathToAllDescendantsOfV1($connection) 
{ 
    $query = 'FOR p IN TRAVERSAL(vertices_20130301_01, edges_20130301_01, "vertices_20130301_01/v1", "inbound", { 
    strategy: "depthfirst", 
    minDepth:1, 
    paths: true, 
    followEdges: [ { label: "child_of" } ] 

}) 
RETURN p 
'; 

    $result = doAQLQuery($connection, $query); 

    return $result; 
} 

// Function that gets the paths to all children of v1 
function getPathToChildrenOfV1($connection) 
{ 
    $query = 'FOR p IN TRAVERSAL(vertices_20130301_01, edges_20130301_01, "vertices_20130301_01/v1", "inbound", { 
    strategy: "depthfirst", 
    maxDepth: 1, 
    minDepth:1, 
    paths: true, 
    followEdges: [ { label: "child_of" } ] 

}) 
RETURN p 
'; 

    $result = doAQLQuery($connection, $query); 

    return $result; 
} 

// Function that gets the paths to all parents of v4 
function getPathToParentsOfV4($connection) 
{ 
    $query = 'FOR p IN TRAVERSAL(vertices_20130301_01, edges_20130301_01, "vertices_20130301_01/v4", "outbound", { 
    strategy: "depthfirst", 
    maxDepth: 1, 
    minDepth:1, 
    paths: true, 
    followEdges: [ { label: "child_of" } ] 

}) 
RETURN p 
'; 

    $result = doAQLQuery($connection, $query); 

    return $result; 
} 

// Function that gets the paths to all ancestor of v4 
function getPathToAllAncestorsOfV4($connection) 
{ 
    $query = 'FOR p IN TRAVERSAL(vertices_20130301_01, edges_20130301_01, "vertices_20130301_01/v4", "outbound", { 
    strategy: "depthfirst", 
    minDepth:1, 
    paths: true, 
    followEdges: [ { label: "child_of" } ] 

}) 
RETURN p 
'; 

    $result = doAQLQuery($connection, $query); 

    return $result; 
} 

// Function that drops collections given 
function dropCollections($connection, $collections) 
{ 
    // register a collection handler to work with the 'users' collection 
    $collectionHandler = new CollectionHandler($connection); 
    echo "dropping collections..."; 
    try { 
     foreach ($collections as $collection) { 
      $collectionHandler->drop($collection); 
     } 
     echo "dropped.<br>"; 
    } catch (Exception $e) { 
     die ('Could not drop collection. Exception: ' . $e . '<br>'); 
    } 
} 

// ********************************************************************************************************************* 
// Start example code 


// register the connection to ArangoDB 
$connection = new Connection(getConnectionOptions()); 


// register a collection handler to work with the 'users' collection 
$collectionHandler = new CollectionHandler($connection); 


// assign the collection names... 
$vertexCollection = 'vertices_20130301_01'; 
$edgeCollection = 'edges_20130301_01'; 

// finally drop the collections... 
// remark this line if you want to drop the collections by hand. 
dropCollections($connection, array($vertexCollection, $edgeCollection)); 


// create the vertices and edges collections... 
// remark those lines if you want to create the collection by hand. 
echo "creating the '$vertexCollection' vertex collection..."; 
try { 
    $collection = new Collection(); 
    $collection->setName($vertexCollection); 
    $collectionHandler->create($collection); 
    echo "created.<br>"; 
} catch (Exception $e) { 
    echo ('Could not create collection. Exception: ' . $e . '<br>'); 
} 


echo "creating the '$edgeCollection' edge collection..."; 
try { 
    $collection = new Collection(); 
    $collection->setName($edgeCollection); 
    $collection->setType(3); 
    $collectionHandler->create($collection); 
    echo "created.<br>"; 
} catch (Exception $e) { 
    echo ('Could not create collection. Exception: ' . $e . '<br>'); 
} 


// setup our vertices and edges.... 
echo "trying to setup our vertices and edges... <br>"; 
$result = setupVerticesAndEdges($connection, $vertexCollection, $edgeCollection); 


// AQL Examples 

// get the path from vertex v4 to v1 
$result = getPathFromV4ToV1($connection); 
echo "<br>*****************************************<br>"; 
echo "get all paths from vertex v4 to v1<br>"; 
echo "<br>*****************************************<br>"; 
var_dump($result); 


// get the paths to all descendants of v1 
$result = getPathToAllDescendantsOfV1($connection); 
echo "<br>*****************************************<br>"; 
echo "get the paths to all descendants of v1<br>"; 
echo "<br>*****************************************<br>"; 
var_dump($result); 

//get the paths to all children of v1 
$result = getPathToChildrenOfV1($connection); 
echo "<br>*****************************************<br>"; 
echo "get the paths to all children of v1<br>"; 
echo "<br>*****************************************<br>"; 
var_dump($result); 


// get the paths to all ancestors of v4 
$result = getPathToAllAncestorsOfV4($connection); 
echo "<br>*****************************************<br>"; 
echo "get the paths to all ancestors of v4<br>"; 
echo "<br>*****************************************<br>"; 
var_dump($result); 

//get all paths to all parents of v4 
$result = getPathToParentsOfV4($connection); 
echo "<br>*****************************************<br>"; 
echo "get all paths to all parents of v4<br>"; 
echo "<br>*****************************************<br>"; 
var_dump($result);