如何使用ArangoDB和PHP遍历图形

时间:2013-03-01 12:10:27

标签: arangodb arangodb-php

ArangoDB提供文档和边缘作为生成图形的低级方法。

假设我们已经设置了一些包含顶点和边的图。 该图表示顶点之间的关系。

v2是v1的孩子 v3是v2的孩子 v4是v3的孩子 v5是v1的孩子 v6是v5的孩子

我们希望能够查询:

  1. 从v4到v1的路径
  2. v1的所有后代
  3. v1的孩子
  4. v4的所有祖先
  5. v4的父母
  6. 如何在PHP中执行此操作?

1 个答案:

答案 0 :(得分:11)

执行此操作的方法是使用AQL(ArangoDB查询语言)查询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);