用户自定义函数

用户自定义函数 是返回单个值且只读的简化过程形式。虽然它们的功能不如过程强大,但在许多常见任务中往往更易使用且更高效。关于用户自定义过程、函数和聚合函数的比较,请参见 Neo4j 定制代码

调用用户自定义函数

用户自定义函数的调用方式与其他 Cypher 函数相同。函数名称必须是全限定的,例如在包 org.neo4j.examples 中定义的名为 join 的函数可以这样调用:

MATCH (p: Person) WHERE p.age = 36
RETURN org.neo4j.examples.join(collect(p.names))

创建函数

用户自定义函数的创建方式与过程类似。但与过程不同的是,它们使用 @UserFunction 注解,并返回单个值而不是值流。

特别注意事项

  • 所有函数都使用 @UserFunction 注解。

  • 函数名称必须具有命名空间,且不允许使用保留的命名空间。

  • 如果在已弃用的命名空间中注册的函数名称与内置函数相同,则该内置函数会被遮蔽。

有关值和类型的详细信息,请参阅 值和类型

欲了解更多细节,请参阅 Neo4j Javadoc(针对 org.neo4j.procedure.UserFunction

在函数内部发出错误的正确方式是抛出 RuntimeException

package example;

import java.util.List;

import org.neo4j.procedure.Description;
import org.neo4j.procedure.Name;
import org.neo4j.procedure.UserFunction;

public class Join
{
    @UserFunction
    @Description("example.join(['s1','s2',...], delimiter) - join the given strings with the given delimiter.")
    public String join(
            @Name("strings") List<String> strings,
            @Name(value = "delimiter", defaultValue = ",") String delimiter) {
        if (strings == null || delimiter == null) {
            return null;
        }
        return String.join(delimiter, strings);
    }
}

集成测试

用户自定义函数的测试创建方式与过程的测试相同。

用于测试将字符串列表连接的用户自定义函数的模板。
package example;

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.neo4j.driver.Driver;
import org.neo4j.driver.GraphDatabase;
import org.neo4j.driver.Session;
import org.neo4j.harness.Neo4j;
import org.neo4j.harness.Neo4jBuilders;

import static org.assertj.core.api.Assertions.assertThat;

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class JoinTest {

    private Neo4j embeddedDatabaseServer;

    @BeforeAll
    void initializeNeo4j() {
        this.embeddedDatabaseServer = Neo4jBuilders.newInProcessBuilder()
                .withDisabledServer()
                .withFunction(Join.class)
                .build();
    }

    @AfterAll
    void closeNeo4j() {
        this.embeddedDatabaseServer.close();
    }

    @Test
    void joinsStrings() {
        // This is in a try-block, to make sure we close the driver after the test
        try(Driver driver = GraphDatabase.driver(embeddedDatabaseServer.boltURI());
            Session session = driver.session()) {

            // When
            String result = session.run( "RETURN example.join(['Hello', 'World']) AS result").single().get("result").asString();

            // Then
            assertThat( result).isEqualTo(( "Hello,World" ));
        }
    }
}

保留和已弃用的函数命名空间

请注意,已弃用的函数命名空间将在下一个主要 Cypher 版本中转为保留。有关 Neo4j 和 Cypher 版本管理的更多信息,请参阅 操作手册 → 介绍

表 1. 保留和已弃用的函数命名空间及名称概览
保留 自 Neo4j 2025.11 起在 Cypher 25 中弃用

*

abac.*

date

builtin.*

date.realtime

cdc.*

date.statement

coll.*

date.transaction

date.*

date.truncate

datetime.*

datetime

db.*

datetime.fromepoch

dbms.*

datetime.fromepochmillis

duration.*

datetime.realtime

graph.*

datetime.statement

internal.*

datetime.transaction

localdatetime.*

datetime.truncate

localtime.*

db.nameFromElementId

math.*

duration

plugin.*

duration.between

point.*

duration.inDays

stored.*

duration.inMonths

string.*

duration.inSeconds

time.*

graph.byElementId

tx.*

graph.byName

unsupported.*

graph.names

vector.*

graph.propertiesByName

localdatetime

localdatetime.realtime

localdatetime.statement

localdatetime.transaction

localdatetime.truncate

localtime

localtime.realtime

localtime.statement

localtime.transaction

localtime.truncate

point.distance

point.withinBBox

time

time.realtime

time.statement

time.transaction

time.truncate

vector.similarity.cosine

vector.similarity.euclidean