an experimental graph server
Java JavaScript Shell
Switch branches/tags
Nothing to show
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
lib
src
udfs/js
www
LICENSE
NOTES
README
THANKS
build.xml
categories.graph
client.sh
flights.graph
load-graph.sh
start-graphd.sh
start-websockets.sh

README

//
// protograph
//

------------
Introduction
------------

A lot of experiments in ranking, relevance, social network exploration, etc. I
have done in the past have required different parts of what has become
protograph.  In April I had the time and the motivation to take those parts and
put them together.

Protograph ...

* is the combination of a search engine (lucene)
* ... and a graph library (jgrapht)
* ... and a threading library (jetlang)
* is not a persistent data store!  memory-only!
* uses a simple line-at-a-time redis-like command/response protocol
* utilizes JSON for all vertex & edge data and all returned results
* provides an easy interface to many graph algorithms
* provides a simple pub/sub messaging system
* provides client-side & server-side graph traversals
* lets you define javascript UDFs for traversal & vertex/edge processes
  
Don't know what some of this stuff means?  Check out the command list and
subsequent examples.

And now from the HATERS GONNA HATE department:

-----------------------------
This is experimental software
-----------------------------

I created this from pieces and parts I scavenged from other, lesser autobots of
mine to finally get an idea what one ultimate voltron of searchable graph servers 
might look like; really though, I did it so I'd have a tool that does
exactly what I want and need, all in one place, that I know like the back of my...

I have not yet preened this code into sexy-amazing-elegant singularity-inception-
inspired meta-oblivion and am actively screwing around with the internals to test
different approaches to many problems.  You may be offended.  That's okay, 
because... 

It is going to get better!  If that doesn't placate you, check out 
neo4j http://neo4j.org/ which has pretty code, is made by smart guys and is used 
widely in real-world production settings.

Until I get this code reading like the best Crichton novel you've ever had your
head explode while reading, consider protograph just a baby.  A hungry one.

---------------------------
If you are inclined to help
---------------------------

I welcome & encourage (and recognize) contributions & collaboration.

I accept and will actively review pull requests.  I will respond to relevant email.
I'm on freenode in #riak and others regularly.

--------------
The good stuff
--------------

1. Requirements
---------------

java 1.6
ant


2. Build
--------

ant


3. Start the server
-------------------

In one console:

./start-graphd.sh


4. Load a graph
---------------

In another console:

./load-graph.sh flights.graph


5. Start a client
-----------------

Anywhere you desire:

./client.sh localhost 10101


6. Try some stuff
-----------------

If you've followed the above instructions, type this in the client console,
line by line.  You'll want to see the output of each.

    use flights
    gstat flights
    get MEX
    spath WAW SAW
    kspath WAW SAW 5 8
    get <<location:usa location:ca>>
    spath <<location:usa location:ca>> <<location:mexico>>


-----------
Coming soon
-----------

* actual java, php, ... clients
* finished websockets interface
* RESTful interface
* responsible resource management
* reworked vertex/edge process management
* blueprints interface
* gremlin integration
* jung algorithm ports

... & lots more

--------
COMMANDS
--------


CREATE      Create a named directed graph
            create <name>
            
USE         Select a named graph to use
            use <name>
            
DROP        Delete a named graph
            drop <name>
            
LISTG       List graphs
            
            listg
            1: {"value": "flights"}
            2: {"value": "categories"}
            
GSTAT       Get the status of an existing graph

            gstat flights
            {
                "edge_count": 1779,
                "vertex_count": 362
            }

BYE         End session & disconnect

CVERT       Create a vertex
            cvert <key> <json_attrs>
            
            cvert FMO {"terminal_fee":30,"name":"muenster","location":"muenster germany"}
            
CEDGE       Create an edge between two vertices
            cedge <key> <from_key> <to_key> <relation> <weight> <json_attrs>
            
            cedge FRA-AGP FRA AGP flight-to 1450 {"cost":569}
            
EXISTS      Test to see if a vertex or edge exists by key
            exists <key>

            exists SFO
            {
                "exists": true,
                "key": "SFO"
            }

GET         Get a JSON representation of a vertex or edge by key
            get <key>
            
            get MEX
            {
                "_key": "MEX",
                "_type": "v",
                "location": "mexico city distrito federal mexico",
                "name": "juarez intl",
                "terminal_fee": "126"
            }
            
SET         Set or clear an attribute of a vertex or edge by key
            set <key> <attr> <value>

            set MEX _weight 2.5
            OK
            get MEX
            {
                "_key": "MEX",
                "_type": "v",
                "_weight": "2.5",
                "location": "mexico city distrito federal mexico",
                "name": "juarez intl",
                "terminal_fee": "126"
            }


DEL         Delete a vertex or edge by key
            del <key>
            
Q           Query attributes of vertices and edges
            q <query>
            
            q location:mexico
            {"results": [
                {
                    "_key": "MEX",
                    "_type": "v",
                    "location": "mexico city distrito federal mexico",
                    "name": "juarez intl",
                    "terminal_fee": "126"
                },
                {
                    "_key": "MTY",
                    "_type": "v",
                    "location": "monterrey nuevo leon mexico",
                    "name": "escobedo",
                    "terminal_fee": "97"
                },
                {
                    "_key": "GDL",
                    "_type": "v",
                    "location": "guadalajara jalisco mexico",
                    "name": "miguel hidalgo intl",
                    "terminal_fee": "127"
                }
            ]}

INCW        Increment the weight of an edge by key
            incw <key> <amount>

            incw ORD-MSP 12.3
            OK
            
            incw MSP-ORD -1.4
            OK
            
SPATH       Find the shortest path between two vertices (with optional maximum path length)
            http://en.wikipedia.org/wiki/Shortest_path_problem

            spath <from_key> <to_key>
            
            spath MEX SFO
            {
                "edges": [
                    "MEX-FRA",
                    "FRA-SFO"
                ],
                "end_vertex": "SFO",
                "start_vertex": "MEX",
                "weight": 3825
            }
            
KSPATH      Find the k-shortest paths between two vertices (with optional maximum path length)
            http://en.wikipedia.org/wiki/Shortest_path_problem
            
            kspath <from_key> <to_key> <k> [radius]

            kspath MEX SFO 2 6
            {
                "end_vertex": "SFO",
                "k": 2,
                "max_hops": 6,
                "paths": [
                    {
                        "path": [
                            "MEX-FRA",
                            "FRA-SFO"
                        ],
                        "weight": 3825
                    },
                    {
                        "path": [
                            "MEX-FRA",
                            "FRA-STR",
                            "STR-MUC",
                            "MUC-SFO"
                        ],
                        "weight": 4450
                    }
                ],
                "start_vertex": "MEX"
            }

HC          Find the hamiltonian cycle if it exists ("traveling salesman problem")
            http://en.wikipedia.org/wiki/Hamiltonian_path

            hc
            {"cycle": [
                {
                    "_key": "c",
                    "city": "chicago"
                },
                {
                    "_key": "b",
                    "city": "duluth"
                },
                {
                    "_key": "a",
                    "city": "minneapolis"
                }
            ]}

EC          Find the eulerian circuit if it exists
            http://en.wikipedia.org/wiki/Eulerian_path

            ec
            {"circuit": [
                {
                    "_key": "a",
                    "city": "minneapolis"
                },
                {
                    "_key": "c",
                    "city": "chicago"
                },
                {
                    "_key": "b",
                    "city": "duluth"
                },
                {
                    "_key": "a",
                    "city": "minneapolis"
                }
            ]}
            
EKMF        Calculate Edmonds Karp maximum flow between two vertices
            http://en.wikipedia.org/wiki/Edmonds%E2%80%93Karp_algorithm
            http://en.wikipedia.org/wiki/Maximum_flow_problem

            ekmf <source_vertex_key> <target_vertex_key>
            
            ekmf MEX SFO
            {
                "flow": {
                    "DFW-FRA": 825,
                    "DFW-IAD": 1000,
                    "FRA-LAX": 1400,
                    "FRA-MUC": 475,
                    "FRA-ORD": 175,
                    "FRA-SFO": 1300,
                    "IAD-MUC": 1000,
                    "LAX-SFO": 1575,
                    "MEX-DFW": 1825,
                    "MEX-FRA": 2525,
                    "MUC-SFO": 1475,
                    "ORD-LAX": 175
                },
                "maximum_flow_value": 4350
            }
            
CN          Compute the chromatic number ("graph coloring")
            http://en.wikipedia.org/wiki/Graph_coloring

            cn
            {"chromatic_number": 8}

KMST        Compute Kruskal's minimum spanning tree
            http://en.wikipedia.org/wiki/Kruskal%27s_algorithm
            http://en.wikipedia.org/wiki/Minimum_spanning_tree
            
            kmst
            {
                "edge_set": [
                    "PVG-PEK",
                    "VCP-EZE",
                    "GRU-FLN",
                    "ASR-FRA",
                    [...]
                ],
                "spanning_tree_cost": 563160
            }

VCG         Compute vertex cover set (greedy method)
            http://en.wikipedia.org/wiki/Vertex_cover
            
            vcg
            {"cover_set": [
                "YYC",
                "MAD",
                "HKG",
                "ABV",
                "RUH",
                [...]
            ]}

VC2A        Compute vertex cover set (2-approximation method)
            http://en.wikipedia.org/wiki/Vertex_cover

            vc2a
            {"cover_set": [
                "PEE",
                "LNZ",
                "LHE",
                "BOD",
                "BAH",
                [...]
            ]}

CSETV       Compute the maximally connected set for a vertex
            http://en.wikipedia.org/wiki/Glossary_of_graph_theory#Strongly_connected_component
            http://en.wikipedia.org/wiki/Glossary_of_graph_theory#Connectivity
            
            csetv <key>
            
            csetv MST
            {"connected_set": [
                "PEK",
                "AGP",
                "HEL",
                [...]
            ]}

CSETS       Compute all maximally connected sets
            http://en.wikipedia.org/wiki/Glossary_of_graph_theory#Strongly_connected_component
            http://en.wikipedia.org/wiki/Glossary_of_graph_theory#Connectivity
            
            csets
            {"connected_sets": [[
                "VLC",
                "SZF",
                "TLL",
                "ZJF",
                "KUF",
                "MOB",
                "SHJ",
                "GDL",
                [...]],
            [   "ABC",
                "DEF",
                "GHI",
                "LUL",
                "ZLO",
                "LSL"
            ]]}

ISCON       Returns "true" if graph connected
            http://en.wikipedia.org/wiki/Connected_graph

            iscon
            {"value": "true"}

UPATHEX     Returns "true" if there exists any UNDIRECTED path between the two vertices specified
            upathex <vertex_0> <vertex_1>

            upathex MEX SFO
            {"value": "true"}

FAMC        Find ALL maximal cliques using "Bron Kerbosch Clique Finder"
            http://en.wikipedia.org/wiki/Bron%E2%80%93Kerbosch_algorithm
            http://en.wikipedia.org/wiki/Glossary_of_graph_theory#Cliques
            
            FAMC
            {"cliques": [
            
                ...
            
                [
                    "VCP",
                    "POA"
                ],
                [
                    "GIG",
                    "VCP"
                ],
                [
                    "CNF",
                    "VCP"
                ],
                [
                    "SCL",
                    "VCP"
                ],
                ["CNF"],
                ["NVT"],
                
                ...
                
            ]}

FBMC        Find biggest maximal cliques using "Bron-Kerbosch Clique Finder"
            http://en.wikipedia.org/wiki/Bron%E2%80%93Kerbosch_algorithm
            http://en.wikipedia.org/wiki/Glossary_of_graph_theory#Cliques
            
            FBMC
            {"cliques": [
                [
                    "LEJ",
                    "VIE",
                    "HAM",
                    "AYT",
                    "AMS",
                    "DUS",
                    "MUC",
                    "FRA"
                ],
                [
                    "LEJ",
                    "VIE",
                    "HAM",
                    "AYT",
                    "DUS",
                    "MUC",
                    "STR",
                    "FRA"
                ],
                [
                    "VIE",
                    "HAM",
                    "DUS",
                    "LHR",
                    "MUC",
                    "STR",
                    "FRA",
                    "MXP"
                ]
            ]}
            
ASPV        All shortest paths from <key> (Floyd Warshall) 
            http://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm
            
            aspv <key>
            
            aspv SCL
            1: {
                "diameter": 25150,
                "paths": [
                    {
                        "edges": [
                            "WAW-FRA",
                            "FRA-SCL"
                        ],
                        "end_vertex": "SCL",
                        "start_vertex": "WAW",
                        "weight": 2
                    },
                    {
                        "edges": [
                            "MAA-FRA",
                            "FRA-SCL"
                        ],
                        "end_vertex": "SCL",
                        "start_vertex": "MAA",
                        "weight": 2
                    },
                    
                    ...
                    
                ],
                    "shortest_path_count": 110575,
                    "source_vertex": "SCL"
                }

GCYC        Get all graph cycles
            http://en.wikipedia.org/wiki/Graph_cycle

            gcyc
            1: {"cycles": [
                "KWI",
                "MAN",
                "LAX",
                "AMM",
                "OSL",
                "POA",
                ...
            ]}

VCYC        Get all cycles containing <key>
            http://en.wikipedia.org/wiki/Graph_cycle
            
            vcyc <key>

            vcyc MLX
            1: {
                "cycles": [
                    "KWI",
                    "MAN",
                    "LAX",
                    "AMM",
                    
                    ...
                    
                    "IAS",
                    "PRG",
                    "TRN",
                    "MLX"
                ],
                "vertex": "MLX"
            }

CCHAN       Create a "message channel" to receive messages from traversals, etc.
            cchan <channel_name>
            
            cchan tr1
            {"value": "bda2fe8e-f731-4139-8b86-50a4c2e81172"}

SUBSCRIBE   Subscribe the current client to the named channel
            subscribe <channel_name>

            subscribe tr1
            OK

UNSUBSCRIBE Unsubscribe the current client to the named channel
            unsubscribe <channel_name>

            unsubscribe tr1
            OK

PUBLISH     Publish a message to a channel.
            publish <channel> <json_message>
            
            PUBLISH tr1 {"message": "hi"}
            OK
            
            * If you are subscribed to the channel "tr1" in this case, the client will receive it:
            
            New I/O client worker #1-1  INFO EchoEventHandler - onGenericEvent: tr1 {"message":"hi"}

TRAV        Execute a client-side evented traversal (via a channel) or a server-side
            traversal (via a UDF):

            TRAV <source_vertex> <traversal_type[:radius]> <udf|"-"> [channel_name]
            
            * <traversal_type> values:
                * breadth_first - http://en.wikipedia.org/wiki/Breadth-first_traversal
                * depth_first - http://en.wikipedia.org/wiki/Depth-first_search
                * closest_first 
                * topological
            
            * the following <traversal_type> may be specified with a suffix
              denoting a maximum radius from <start_vertex>:
              * closest_first[:radius]
            
            * if parameter 3 is "-", events will be sent to argument 4 [channel]
            * if parameter 3 is not "-", it will be interpreted as a server-side udf
              that implements TraversalEvent functions
            
            NOTE: topological <traversal_type> ignores the value of <start_vertex>
                  but some value must be specified
                  
            EXAMPLES:
            

            * traverse, starting from WAW, via closest_first of maximum radius 5;
              publish each traversal event to the channel "tr1":

            
                trav WAW closest_first:5 - tr1
                New I/O client worker #1-1  INFO EchoEventHandler - onGenericEvent: tr1 {"source":"org.jgrapht.traverse.ClosestFirstIterator@318e136f","event":"ConnectedComponentTraversal","eventType":"ConnectedComponentStarted"}
                New I/O client worker #1-1  INFO EchoEventHandler - onGenericEvent: tr1 {"_key":"WAW","event":"VertexTraversal","eventType":"VertexTraversed"}
                New I/O client worker #1-1  INFO EchoEventHandler - onGenericEvent: tr1 {"_key":"WAW-FRA","event":"EdgeTraversal","eventType":"EdgeTraversed"}
                New I/O client worker #1-1  INFO EchoEventHandler - onGenericEvent: tr1 {"_key":"WAW-MUC","event":"EdgeTraversal","eventType":"EdgeTraversed"}
                New I/O client worker #1-1  INFO EchoEventHandler - onGenericEvent: tr1 {"_key":"WAW-DUS","event":"EdgeTraversal","eventType":"EdgeTraversed"}
                New I/O client worker #1-1  INFO EchoEventHandler - onGenericEvent: tr1 {"_key":"WAW-MXP","event":"EdgeTraversal","eventType":"EdgeTraversed"}
                New I/O client worker #1-1  INFO EchoEventHandler - onGenericEvent: tr1 {"_key":"WAW-VIE","event":"EdgeTraversal","eventType":"EdgeTraversed"}
                New I/O client worker #1-1  INFO EchoEventHandler - onGenericEvent: tr1 {"_key":"WAW-KTW","event":"EdgeTraversal","eventType":"EdgeTraversed"}
                New I/O client worker #1-1  INFO EchoEventHandler - onGenericEvent: tr1 {"_key":"WAW-KRK","event":"EdgeTraversal","eventType":"EdgeTraversed"}
                New I/O client worker #1-1  INFO EchoEventHandler - onGenericEvent: tr1 {"_key":"WAW-POZ","event":"EdgeTraversal","eventType":"EdgeTraversed"}
                New I/O client worker #1-1  INFO EchoEventHandler - onGenericEvent: tr1 {"_key":"WAW-LEJ","event":"EdgeTraversal","eventType":"EdgeTraversed"}
                New I/O client worker #1-1  INFO EchoEventHandler - onGenericEvent: tr1 {"source":"org.jgrapht.traverse.ClosestFirstIterator@318e136f","event":"ConnectedComponentTraversal","eventType":"ConnectedComponentFinished"}


            * topological traversal published to "traverse1" channel:

            
                trav VIE topological - traversal1
                New I/O client worker #1-1  INFO EchoEventHandler - onGenericEvent: traversal1 {"source":"org.jgrapht.traverse.TopologicalOrderIterator@3a97b29a","event":"ConnectedComponentTraversal","eventType":"ConnectedComponentStarted"}
                New I/O client worker #1-1  INFO EchoEventHandler - onGenericEvent: traversal1 {"_key":"ANR","event":"VertexTraversal","eventType":"VertexTraversed"}
                OK
                New I/O client worker #1-1  INFO EchoEventHandler - onGenericEvent: traversal1 {"_key":"ANR-BRU","event":"EdgeTraversal","eventType":"EdgeTraversed"}
                New I/O client worker #1-1  INFO EchoEventHandler - onGenericEvent: traversal1 {"_key":"PEN","event":"VertexTraversal","eventType":"VertexTraversed"}
                New I/O client worker #1-1  INFO EchoEventHandler - onGenericEvent: traversal1 {"_key":"PEN-SIN","event":"EdgeTraversal","eventType":"EdgeTraversed"}
    
                [...]
    
                New I/O client worker #1-1  INFO EchoEventHandler - onGenericEvent: traversal1 {"_key":"HAU","event":"VertexTraversal","eventType":"VertexTraversed"}
                New I/O client worker #1-1  INFO EchoEventHandler - onGenericEvent: traversal1 {"_key":"HAU-OSL","event":"EdgeTraversal","eventType":"EdgeTraversed"}
                New I/O client worker #1-1  INFO EchoEventHandler - onGenericEvent: traversal1 {"source":"org.jgrapht.traverse.TopologicalOrderIterator@3a97b29a","event":"ConnectedComponentTraversal","eventType":"ConnectedComponentFinished"}
            
            * closest_first traversal starting at every location:usa 
              AND location:ca to a radius of 5, publishing to traversal1

                trav <<location:usa location:ca>> closest_first:5 - traversal1
                New I/O client worker #1-1  INFO EchoEventHandler - onGenericEvent: traversal1 {"source":"org.jgrapht.traverse.ClosestFirstIterator@16119cb","event":"ConnectedComponentTraversal","eventType":"ConnectedComponentStarted"}
                New I/O client worker #1-1  INFO EchoEventHandler - onGenericEvent: traversal1 {"_key":"LAX","event":"VertexTraversal","eventType":"VertexTraversed"}
                New I/O client worker #1-1  INFO EchoEventHandler - onGenericEvent: traversal1 {"_key":"LAX-MUC","event":"EdgeTraversal","eventType":"EdgeTraversed"}
    
                [...]
    
                New I/O client worker #1-1  INFO EchoEventHandler - onGenericEvent: traversal1 {"source":"org.jgrapht.traverse.ClosestFirstIterator@79cb0f1a","event":"ConnectedComponentTraversal","eventType":"ConnectedComponentFinished"}
                New I/O client worker #1-1  INFO EchoEventHandler - onGenericEvent: traversal1 {"source":"org.jgrapht.traverse.ClosestFirstIterator@24cb26e","event":"ConnectedComponentTraversal","eventType":"ConnectedComponentStarted"}
                New I/O client worker #1-1  INFO EchoEventHandler - onGenericEvent: traversal1 {"_key":"SMF","event":"VertexTraversal","eventType":"VertexTraversed"}
                New I/O client worker #1-1  INFO EchoEventHandler - onGenericEvent: traversal1 {"source":"org.jgrapht.traverse.ClosestFirstIterator@24cb26e","event":"ConnectedComponentTraversal","eventType":"ConnectedComponentFinished"}
                New I/O client worker #1-1  INFO EchoEventHandler - onGenericEvent: traversal1 {"source":"org.jgrapht.traverse.ClosestFirstIterator@4943f9d2","event":"ConnectedComponentTraversal","eventType":"ConnectedComponentStarted"}
                New I/O client worker #1-1  INFO EchoEventHandler - onGenericEvent: traversal1 {"_key":"SAN","event":"VertexTraversal","eventType":"VertexTraversed"}
                New I/O client worker #1-1  INFO EchoEventHandler - onGenericEvent: traversal1 {"source":"org.jgrapht.traverse.ClosestFirstIterator@4943f9d2","event":"ConnectedComponentTraversal","eventType":"ConnectedComponentFinished"}


            * traverse using a user-defined server-side traversal event handler:
            
            
                define_udf TestJSTraversal js udfs/js/TestJSTraversal.js
                OK
                trav <<_key:beauty*>> closest_first:5 TestJSTraversal
                OK

            [*] in the server console you will see something like:
            
                [...]
                
                edgeTraversed: {"_key":"parking-services-parking-consultants","event":"EdgeTraversal","eventType":"EdgeTraversed"}
                edgeTraversed: {"_key":"parking-services-automotive-sales-services","event":"EdgeTraversal","eventType":"EdgeTraversed"}
                vertexTraversed: {"_key":"aviation","event":"VertexTraversal","eventType":"VertexTraversed"}
                edgeTraversed: {"_key":"aviation-aircraft-rental","event":"EdgeTraversal","eventType":"EdgeTraversed"}
                edgeTraversed: {"_key":"aviation-aircraft-dealers","event":"EdgeTraversal","eventType":"EdgeTraversed"}
                edgeTraversed: {"_key":"aviation-automotive-sales-services","event":"EdgeTraversal","eventType":"EdgeTraversed"}
                connectedComponentFinished: {"event":"ConnectedComponentTraversal","eventType":"ConnectedComponentFinished"}
                
            [*] see below for specs for JS UDF-driven traversals

DEFINE_UDF  Install a user-defined function
            define_udf <udf_name> <udf_type> <udf_def_filename>
            
            e.g.,

            define_udf TestJSGraphProcess js udfs/js/TestJSGraphProcess.js
            OK
            
SPROC       Start a vertex or edge (UDF-defined) process
            sproc <key> <udf_name>
            
            e.g.,

            sproc <<_key:MEX OR _key:FRA OR _key:DFW>> TestJSGraphProcess
            OK
            
EMIT        Emit a JSON message to a vertex or edge (UDF-defined) process
            emit <key> <process_name> <json_message>
            
            e.g.,

            emit MSP MSP-TestJSGraphProcess {"message": "emitted message!"}

QSIM        Query the simulation process index

            qsim _type:udf
            1: {"results": [{
                "_key": "TestJSGraphProcess",
                "_type": "udf",
                "udf_fn": "udfs/js/TestJSGraphProcess.js",
                "udf_type": "js"
            }]}


-----------------
COMMAND MODIFIERS
-----------------

MODIFIER: QUERY EXPANSIONS
==========================

Enclosing lucene syntax in << >> for any vertex or edge attribute query
will issue the command with the query results replaced.  Multiple
expansions can be used; if multiple expansions are used, the command
is executed for the cross-join equivalent of all results returned.

* inline query expansions, e.g.

    get <<cost:[299 TO 300]>>
    1: {
        "_key": "MUC-IST",
        "_rel": "flight-to",
        "_source": "MUC",
        "_target": "IST",
        "_type": "e",
        "_weight": "1875.0",
        "cost": "299"
    }
    2: {
        "_key": "RLG-MUC",
        "_rel": "flight-to",
        "_source": "RLG",
        "_target": "MUC",
        "_type": "e",
        "_weight": "825.0",
        "cost": "299"
    }
    3: {
        "_key": "MXP-BCN",
        "_rel": "flight-to",
        "_source": "MXP",
        "_target": "BCN",
        "_type": "e",
        "_weight": "625.0",
        "cost": "299"
    }
    4: {
        "_key": "GIG-VCP",
        "_rel": "flight-to",
        "_source": "GIG",
        "_target": "VCP",
        "_type": "e",
        "_weight": "5500.0",
        "cost": "300"
    }
    
* another example:

    get <<location:mexico>>
    1: {
        "_key": "MTY",
        "_type": "v",
        "location": "monterrey nuevo leon mexico",
        "name": "escobedo",
        "terminal_fee": "97"
    }
    2: {
        "_key": "GDL",
        "_type": "v",
        "location": "guadalajara jalisco mexico",
        "name": "miguel hidalgo intl",
        "terminal_fee": "127"
    }
    3: {
        "_key": "MEX",
        "_type": "v",
        "_weight": "2.5",
        "location": "mexico city distrito federal mexico",
        "name": "juarez intl",
        "terminal_fee": "126"
    }

* "stacking" inline query expansions:

    spath <<location:mn>> <<location:ca>>
    1: {
        "edges": [
            "MSP-ORD",
            "ORD-LAX"
        ],
        "end_vertex": "LAX",
        "start_vertex": "MSP",
        "weight": 7850
    }
    2: {
        "edges": [
            "MSP-ORD",
            "ORD-LAX",
            "LAX-MUC",
            "MUC-SFO"
        ],
        "end_vertex": "SFO",
        "start_vertex": "MSP",
        "weight": 11225
    }
    3: {
        "edges": [
            "MSP-ORD",
            "ORD-LAX",
            "LAX-SMF"
        ],
        "end_vertex": "SMF",
        "start_vertex": "MSP",
        "weight": 12850
    }
    4: {
        "edges": [
            "MSP-ORD",
            "ORD-LAX",
            "LAX-SAN"
        ],
        "end_vertex": "SAN",
        "start_vertex": "MSP",
        "weight": 14350
    }

MODIFIER: ASYNC OVERRIDE
========================

Other than being a cool name, because graph operations are executed in a single-threaded
context in the order they are received, if there is a huge queue of operations executing
and you need to access something in the graph you feel comfortable is not predicated
on whatever commands are supposed to execute first, and those same queued commands
are not going to be screwed up as a result of a command to wish to execute "out of
order" and "without guarantee", you can prepend a "&" character to any command
protograph accepts and it will be executed immediately against the current
graph.

This is in general a terrible idea and I recommend you do not use it unless you are
feeling god-like and/or obscenely lucky.

e.g.,

    &get MEX
    1: {
        "_key": "MEX",
        "_type": "v",
        "location": "mexico city distrito federal mexico",
        "name": "juarez intl",
        "terminal_fee": "126"
    }


----------------------------
GRAPH OBJECT STANDARD FIELDS
----------------------------

VERTICES:

    * _key      vertex key
    * _type     always "v"

EDGES:

    * _key          edge key
    * _source       source vertex key
    * _target       target vertex key
    * _type         always "e"
    * _rel          edge-relation

Examples using these standard fields:

* get all edges emanating from ORD:


    q <<_type:e _source:ORD>>
    1: {"results": [{
        "_key": "ORD-FRA",
        "_rel": "flight-to",
        "_source": "ORD",
        "_target": "FRA",
        "_type": "e",
        "_weight": "4450.0",
        "cost": "474"
    }]}
    2: {"results": [{
        "_key": "ORD-MUC",
        "_rel": "flight-to",
        "_source": "ORD",
        "_target": "MUC",
        "_type": "e",
        "_weight": "4100.0",
        "cost": "307"
    }]}
     
    ....
    
    20: {"results": [{
        "_key": "ORD-AMS",
        "_rel": "flight-to",
        "_source": "ORD",
        "_target": "AMS",
        "_type": "e",
        "_weight": "4650.0",
        "cost": "769"
    }]}


* get all "flight-to" relation edges going to MSP:


    get <<_rel:"flight-to" _target:MSP>>
    1: {
        "_key": "ORD-MSP",
        "_rel": "flight-to",
        "_source": "ORD",
        "_target": "MSP",
        "_type": "e",
        "_weight": "2500.0",
        "cost": "672"
    }


---------------------
JAVASCRIPT TRAVERSALS
---------------------

* see: udfs/js/TestJSTraversal.js for full code

e.g.,

    TestJSTraversal = function(startingState) {
        this.startingState = startingState;
        
        /* 
         * constructor logic, executed once per
         * UDF registration
        */
        log("TestJSTraversal: constructor");
        log("TestJSTraversal: startingState = " + 
            this.startingState);
        
        this.connectedComponentStarted = function(msg) {
        };
        
        this.connectedComponentFinished = function(msg) {
        };
        
        this.edgeTraversed = function(msg) {
        };
        
        this.vertexFinished = function(msg) {
        };
        
        this.vertexTraversed = function(msg) {
        };
    
        return this;
    };

// post registration logic here, executed once
// per UDF registration


---------------------------
JAVASCRIPT VERTEX PROCESSES
---------------------------

* see: udfs/js/TestJSGraphProcess.js for full code

e.g.,

    TestJSGraphProcess = function(_process) {
        
        // handle to the owning process harness
        // (to self-reference your "pid" from js)
        this._process = _process;
        
        // before this process is killed, clean up
        
        this.beforeKill = function() {
        };
        
        // vertex removal
        
        this.beforeRemoveVertex = function(vertex) {
        };
                
        // edge removal
        
        this.beforeRemoveEdge = function(edge) {
        };
                
        this.afterRemoveEdge = function(edge) {
        };
    
        // this is called when a mesage is "emit"ted to this
        //  process            
        this.message = function(msg) {
        };
        
        return this;
    };


--------------------
WEBSOCKETS INTERFACE
--------------------

Not fully functioning and under current development.


--------------------------------
FLIGHTS.GRAPH & CATEGORIES.GRAPH
--------------------------------

These are simple scripts that are replayed.  They are readable
and represent typical use of protograph commands.  For now this
is a good way to generate graphs you want to use with protograph.