Package: gdsclient
gdsclientgdsclientis a Python wrapper API for operating and working with theNeo4j Graph Data Science (GDS) library.
It enables users to write pure Python code to project graphs, run algorithms, and define and use machine learning pipelines in GDS.The API is designed to mimic the GDS Cypher procedure API in Python code.
It abstracts the necessary operations of theNeo4j Python driverto offer a simpler surface.Please leave any feedback as issues onthe source repository.
Happy coding!NOTEThis is a work in progress and some GDS features are known to be missing or not working properly (seeKnown limitationsbelow).
Further, this library targets GDS versions 2.0+ (not yet released) and as such may not work with older versions.InstallationTo install the latest deployed version ofgdsclient, simply run:pipinstallgdsclientUsageWhat follows is a high level description of some of the operations supported bygdsclient.
For extensive documentation of all operations supported by GDS, please refer to theGDS Manual.Extensive end-to-end examples in Jupyter ready-to-run notebooks can be found in theexamplessource directory:Computing similarities with kNN based on FastRP embeddingsImports and setupThe library wraps theNeo4j Python driverwith aGraphDataScienceobject through which most calls to GDS will be made.fromneo4jimportGraphDatabasefromgdsclientimportNeo4jQueryRunner,GraphDataScience# Replace Neo4j Python driver settings according to your setupURI="bolt://localhost:7687"driver=GraphDatabase.driver(URI)gds=GraphDataScience(Neo4jQueryRunner(driver))gds.set_database("my-db")# (Optional) Use a specific Neo4j databaseProjecting a graphSupposing that we have some graph data in our Neo4j database, we canproject the graph into memory.# Optionally we can estimate memory of the operation firstres=gds.graph.project.estimate("*","*")assertres[0]["requiredMemory"]<1e12G=gds.graph.project("graph","*","*")TheGthat is returned here is aGraphwhich on the client side represents the projection on the server side.The analogous callsgds.graph.project.cypher{,.estimate}forCypher based projectionare also supported.Running algorithmsWe can take a projected graph, represented to us by aGraphobject namedG, and runalgorithmson it.# Optionally we can estimate memory of the operation first (if the algo supports it)res=gds.pageRank.mutate.estimate(G,tolerance=0.5,writeProperty="pagerank")assertres[0]["requiredMemory"]<1e12res=gds.pageRank.mutate(G,tolerance=0.5,writeProperty="pagerank")assertres[0]["nodePropertiesWritten"]==G.node_count()These calls take one positional argument and a number of keyword arguments depending on the algorithm.
The first (positional) argument is aGraph, and the keyword arguments map directly to the algorithm'sconfiguration map.
The calls return a list of dictionaries (with contents depending on the algorithm of course) as is also the case when using the Neo4j Python driver directly.The otheralgorithm execution modes- stats, stream and write - are also supported via analogous calls.Topological link predictionThe methods for doingtopological link predictionare a bit different.
Just like in the GDS procedure API they do not take a graph as an argument, but rather two node references as positional arguments.
And they simply return the similarity score of the prediction just made as a float - not a list of dictionaries.The Graph objectIn this library, graphs projected onto server-side memory are represented byGraphobjects.
There are convenience methods on theGraphobject that let us extract information about our projected graph.
Some examples are (whereGis aGraph):# Get the graph's node countn=G.node_count()# Get a list of all relationship properties present on# relationships of the type "myRelType"rel_props=G.relationship_properties("myRelType")# Drop the projection represented by GG.drop()Machine learning modelsIn GDS, you can train machine learning models.
When doing this using thegdsclient, you can get a model object returned directly in the client.
The model object allows for convenient access to details about the model via Python methods.
It also offers the ability to directly compute predictions using the appropriate GDS procedure for that model.
This includes support for models trained using pipelines (for Link Prediction and Node Classification) as well as GraphSAGE models.PipelinesThere's native support forLink prediction pipelinesandNode classification pipelines.
Apart from the call to create a pipeline, the GDS native pipelines calls are represented by methods on pipeline Python objects.
Additionally to the standard GDS calls, there are several methods to query the pipeline for information about it.Below is a minimal example for node classification (supposing we have a graphGwith a property "myClass"):pipe=gds.alpha.ml.pipeline.nodeClassification.create("myPipe")assertpipe.type()=="Node classification training pipeline"pipe.addNodeProperty("degree",mutateProperty="rank")pipe.selectFeatures("rank")steps=pipe.feature_properties()assertlen(steps)==1assertsteps[0]["feature"]=="rank"trained_pipe=pipe.train(G,modelName="myModel",targetProperty="myClass",metrics=["ACCURACY"])asserttrained_pipe.metrics()["ACCURACY"]["test"]>0res=trained_pipe.predict_stream(G)assertlen(res)==G.node_count()Link prediction works the same way, just with different method names for calls specific to that pipeline.
Please see the GDS documentation for more on the pipelines' procedure APIs.GraphSAGEAssuming we have a graphGwith node propertyx, we can do the following:model=gds.beta.graphSage.train(G,modelName="myModel",featureProperties=["x"])assertlen(model.metrics()["epochLosses"])==model.metrics()["ranEpochs"]res=model.predict_stream(G)assertlen(res)==G.node_count()Note that with GraphSAGE we call thetrainmethod directly and supply all training configuration.Graph catalog utilsAll procedures from theGDS Graph catalogare supported withgdsclient.
Some examples are (whereGis aGraph):res=gds.graph.list()assertlen(res)==1# Exactly one graph is projectedres=gds.graph.streamNodeProperties(G,"rank")assertlen(res)==G.node_count()Further, there's a new call namedgds.graph.get(gdsclientonly) which takes a name as input and returns aGraphobject if a graph projection of that name exists in the user's graph catalog.
The idea is to have a way of creatingGraphs for already projected graphs, without having to do a new projection.Model catalog utilsAll procedures from theGDS Model catalogare supported withgdsclient.
Some examples are (wheremodelis a machine learning model object):res=gds.beta.model.list()assertlen(res)==1# Exactly one model is loadedres=gds.beta.model.drop(model)assertres[0]["modelInfo"]["modelName"]==model.name()Further, there's a new call namedgds.model.get(gdsclientonly) which takes a model name as input and returns a model object if a model of that name exists in the user's model catalog.
The idea is to have a way of creating model objects for already loaded models, without having to create them again.Node matching without CypherWhen calling path finding or topological link prediction algorithms one has to provide specific nodes as input arguments.
When using the GDS procedure API directly to call such algorithms, typically CypherMATCHstatements are used in order to find valid representations of input nodes of interest, see eg.this example in the GDS docs.
To simplify this,gdsclientprovides a utility function,gds.find_node_id, for letting one find nodes without using Cypher.Below is an example of how this can be done (supposingGis a projectedGraphwithCitynodes havingnameproperties):# gds.find_node_id takes a list of labels and a dictionary of# property key-value pairssource_id=gds.find_node_id(["City"],{"name":"New York"})target_id=gds.find_node_id(["City"],{"name":"Philadelphia"})res=gds.shortestPath.dijkstra.stream(G,sourceNode=source_id,targetNode=target_id)assertres[0]["totalCost"]==100The nodes found bygds.find_node_idare those that have all labels specified and fully match all property key-value pairs given.
Note that exactly one node per method call must be matched.For more advanced filtering we recommend users do matching via Cypher'sMATCH.Known limitationsOperations known to not yet work withgdsclient:Some utility functionsLicensegdsclientis licensed under the Apache Software License version 2.0.
All content is copyright © Neo4j Sweden AB.AcknowledgementsThis work has been inspired by the great work done in the following libraries:pygdsby stellasiagds-pythonby moxious