16.8 User-Defined Functions (UDFs) in PGX
User-defined functions (UDFs) allow users of PGX to add custom logic to their PGQL queries or custom graph algorithms, to complement built-in functions with custom requirements.
Caution:
UDFs enable running arbitrary code in the PGX server, possibly accessing sensitive data. Additionally, any PGX session can invoke any of the UDFs that are enabled on the PGX server. The application administrator who enables UDFs is responsible for checking the following:
- All the UDF code can be trusted.
- The UDFs are stored in a secure location that cannot be tampered with.
Furthermore, PGX assumes UDFs to be state-less and side-effect free.
PGX supports two types of UDFs:
- Java UDFs
- JavaScript UDFs
How to Use Java UDFs
The following simple example shows how to register a Java UDF at the PGX server and invoke it.
- Create a class with a public static method. For example:
package my.udfs; public class MyUdfs { public static String concat(String a, String b) { return a + b; } }
- Compile the class and compress into a JAR file. For example:
mkdir ./target javac -d ./target *.java cd target jar cvf MyUdfs.jar *
- Copy the JAR file into
/opt/oracle/graph/pgx/server/lib
. - Create a UDF JSON configuration file. For example, assume that
/path/to/my/udfs/dir/my_udfs.json
contains the following:{ "user_defined_functions": [ { "namespace": "my", "language": "java", "implementation_reference": "my.udfs.MyUdfs", "function_name": "concat", "return_type": "string", "arguments": [ { "name": "a", "type": "string" }, { "name": "b", "type": "string" } ] } ] }
- Point to the directory containing the UDF configuration file in
/etc/oracle/graph/pgx.conf
. For example:"udf_config_directory": "/path/to/my/udfs/dir/"
- Restart the PGX server. For example:
sudo systemctl restart pgx
- Try to invoke the UDF from within a PGQL query. For example:
graph.queryPgql("SELECT my.concat(my.concat(n.firstName, ' '), n.lastName) FROM MATCH (n:Person)")
- Try to invoke the UDF from within a PGX algorithm. For example:
Note:
For each UDF you want to use, you need to create an abstract method with the same schema that gets annotated with the@Udf
annotation.import oracle.pgx.algorithm.annotations.Udf; .... @GraphAlgorithm public class MyAlogrithm { public void bomAlgorithm(PgxGraph g, VertexProperty<String> firstName, VertexProperty<String> lastName, @Out VertexProperty<String> fullName) { ... fullName.set(v, concat(firstName.get(v), lastName.get(v))); ... } @Udf(namespace = "my") abstract String concat(String a, String b); }
JavaScript UDFs
The requirements for a JavaScript UDF is as follows:
- The JavaScript source must contain all dependencies.
- The source must contain at least one valid export.
- The
language
parameter must be set tojavascript
in the UDF configuration file.
For example, consider a JavaScript source file format.js
as shown:
//format.js
const fun = function(name, country) {
if (country == null) return name;
else return name + " (" + country + ")";
}
module.exports = {stringFormat: fun};
In order to load the UDF from format.js
, the UDF configuration file will
appear as follows:
{
"namespace": "my",
"function_name": "format",
"language": "javascript",
"source_location": "format.js",
"source_function_name": "stringFormat",
"return_type": "string",
"arguments": [
{
"name": "name",
"type": "string"
},
{
"name": "country",
"type": "string"
}
]
}
Note:
In this case, since the name of the UDF and the implementing method differ, you need to set the name of the UDF in thesource_function_name
field. Also, you can
provide the path of the source code file in the source_location
field.
UDF Configuration File Information
A UDF configuration file is a JSON file containing an array of
user_defined_functions
. (An example of such a file is in the step to
"Create a UDF JSON configuration file" in the preceding How to Use Java UDFs subsection.)
Each user-defined function supports the fields shown in the following table.
Table 16-13 Fields for Each UDF
Field | Data Type | Description | Required? |
---|---|---|---|
function_name | string | Name of the function used as identifier in PGX | Required |
language | enum[java, javascript] | Source language for he function (java or javascript )
|
Required |
return_type | enum[boolean, integer, long, float, double, string] | Return type of the function | Required |
arguments | array of object | Array of arguments. For each argument: type, argument name, required? | [] |
implementation_reference | string | Reference to the function name on the classpath | null |
namespace | string | Namespace of the function in PGX | null |
source_code | string | Source code of the function provided inline | null |
source_function_name | string | Name of the function in the source language | null |
source_location | string | Local file path to the function's source code | null |
All configured UDFs must be unique with regard to the combination of the following fields:
- namespace
- function_name
- arguments
Parent topic: Developing Applications with Graph Analytics