diff --git a/docs/flex/interactive/development/stored_procedure/cpp_procedure.md b/docs/flex/interactive/development/stored_procedure/cpp_procedure.md index fed500df0740..063e38a0ff25 100644 --- a/docs/flex/interactive/development/stored_procedure/cpp_procedure.md +++ b/docs/flex/interactive/development/stored_procedure/cpp_procedure.md @@ -74,7 +74,90 @@ void DeleteApp(void *app) { ### Register and Call the stored procedure -With the above `CountVertices` procedure defined, we could create a stored procedure from Interactive Python/Java SDK, or `gsctl`. +With the above `CountVertices` procedure defined, we could create a stored procedure with `gsctl` or use Interactive Python/Java SDKs. + +#### gsctl + +With Interactive deployed, you can register a C++ stored procedure similarly to [creating a Cypher stored procedure](../../stored_procedures.md). + +##### Define the YAML + +When defined, C++ stored procedures' YAML differ from Cypher procedures only in the `type` field, i.e., `cpp` versus `cypher`. Users can include the stored procedure's implementation directly in the YAML file. + + +```yaml +name: test_procedure +description: "Ths is a test procedure" +query: | + #include "flex/engines/graph_db/app/app_base.h" + #include "flex/engines/graph_db/database/graph_db_session.h" + #include "flex/utils/app_utils.h" + + namespace gs { + + // A sample app get the count of the specified vertex label, since no write + // operations are needed we inherit from ReadAppBase. Otherwise you could + // inherit from WriteAppBase. + class CountVertices : public ReadAppBase { + public: + CountVertices() {} + /** + * @brief Query function for query class. + * @param sess: GraphDBSession The interface where you can visit the graph. + * @param input: Decoder From where you could deserialize the input + * parameters. + * @param output: Encoder To where you should encode the output parameters. + */ + bool Query(const gs::GraphDBSession &sess, Decoder &input, + Encoder &output) override { + // First get the read transaction. + auto txn = sess.GetReadTransaction(); + // We expect one param of type string from decoder. + if (input.empty()) { + return false; + } + std::string label_name{input.get_string()}; + const auto &schema = txn.schema(); + if (!schema.has_vertex_label(label_name)) { + return false; // The requested label doesn't exits. + } + auto label_id = schema.get_vertex_label_id(label_name); + // The vertices are labeled internally from 0 ~ vertex_label_num, accumulate + // the count. + output.put_int(txn.GetVertexNum(label_id)); + txn.Commit(); + return true; + } + }; + } // namespace gs + + extern "C" { + + // Defines how a instance of your procedure is created. + void *CreateApp(gs::GraphDBSession &db) { + gs::CountVertices *app = new gs::CountVertices(); + return static_cast(app); + } + + // Defines how a instance of your procedure should be deleted. + void DeleteApp(void *app) { + gs::CountVertices *casted = static_cast(app); + delete casted; + } + } +type: cpp +``` + +You may find the c++ code is too long, and maybe hard to update, especially if some modifications are needed. Fortunately, we support uploading the procedure implementation from file, you just need to provide the full path of the c++ file, with `@` prepended. + + +```yaml +name: test_procedure +description: "Ths is a test procedure" +query: "@/path/to/procedure.cc" +type: cpp +``` + #### Python SDK @@ -168,11 +251,26 @@ public class CreateProcedureTest{ For more tails about Java SDK Interface, please refer to [Java SDK Procedure API](../java/ProcedureManagementApi.md). +## Create a Stored Procedure -#### gsctl +First, switch to the graph where you want to create the procedure. We will use the built-in graph as an example. For instructions on creating your own graph, please refer to [Use Custom Graph](../../custom_graph_data.md). -TODO +```bash +gsctl use GRAPH gs_interactive_default_graph +``` +Then create the procedure with `gsctl`: + +```bash +gsctl create storedproc -f ./procedure.yaml +``` + +This will initiate the compilation process to convert C++ code into a dynamic library, which may take a few seconds. After compilation, it is **necessary** to restart the service to activate the stored procedures. + + +```bash +gsctl service restart +``` ## Graph Database Engine @@ -246,7 +344,6 @@ public class CreateProcedureTest{ ```python -import os from gs_interactive.client.driver import Driver from gs_interactive.models import * from gs_interactive.client.utils import * @@ -260,6 +357,9 @@ encoder.put_string("person") # input label name encoder.put_byte(1) # procedure id 1 resp = sess.call_procedure_raw(graph_id="1", params=encoder.get_bytes()) assert resp.is_ok() +decoder = Decoder(resp.value) +num = decoder.get_int() +print(f"vertices num: {num}") ``` ## Programming Interface diff --git a/docs/flex/interactive/getting_started.md b/docs/flex/interactive/getting_started.md index 2038bc513761..c876cc6fc50a 100644 --- a/docs/flex/interactive/getting_started.md +++ b/docs/flex/interactive/getting_started.md @@ -76,6 +76,8 @@ unzip cypher-shell-4.4.19.zip && cd cypher-shell @neo4j> MATCH (n) RETURN n LIMIT 10; ``` +You could also make use of Interactive SDKs,[Java SDK](./development/java/java_sdk.md) or [Python SDK](./development/python/, to connect to the Interactive service using the python_sdk.md) to submit queries. + ## Close the connection If you want to disconnect to coordinator, just type diff --git a/docs/flex/interactive/stored_procedures.md b/docs/flex/interactive/stored_procedures.md index df32c3af051f..bd0a80d0833c 100644 --- a/docs/flex/interactive/stored_procedures.md +++ b/docs/flex/interactive/stored_procedures.md @@ -103,3 +103,7 @@ You can also call the stored procedure via neo4j-native tools, like `cypher-shel ```cypher CALL test_procedure("marko") YIELD *; ``` + + + +In addition to defining a stored procedure with a Cypher query, we also support for customizing query execution through C++ stored procedures. See [C++ Stored Procedure](./development/stored_procedure/cpp_procedure.md).