User-defined aggregation functions
User-defined aggregation functions are functions that aggregate data and return a single result. For a comparison between user-defined procedures, functions, and aggregation functions, see Neo4j customized code.
Call an aggregation function
User-defined aggregation functions are called in the same way as any other Cypher aggregation function.
The function name must be fully qualified, so a function named longestString defined in the package org.neo4j.examples could be called using:
MATCH (p: Person) WHERE p.age = 36
RETURN org.neo4j.examples.longestString(p.name)
Writing a user-defined aggregation function
User-defined aggregation functions are annotated with @UserAggregationFunction.
The annotated function must return an instance of an aggregator class.
An aggregator class contains one method annotated with @UserAggregationUpdate and one method annotated with @UserAggregationResult.
The method annotated with @UserAggregationUpdate will be called multiple times and enables the class to aggregate data.
When the aggregation is done, the method annotated with @UserAggregationResult will be called once and the result of the aggregation will be returned.
Particular things to note:
-
All functions are annotated with
@UserAggregationFunction. -
The aggregation function name must be namespaced and is not allowed in reserved namespaces.
-
If a user-defined aggregation function is registered with the same name as a built-in function in a deprecated namespace, the built-in function is shadowed.
See Values and types for details on values and types.
For more details, see the Neo4j Javadocs for org.neo4j.procedure.UserAggregationFunction.
|
The correct way to signal an error from within an aggregation function is to throw |
package example;
import org.neo4j.procedure.Description;
import org.neo4j.procedure.Name;
import org.neo4j.procedure.UserAggregationFunction;
import org.neo4j.procedure.UserAggregationResult;
import org.neo4j.procedure.UserAggregationUpdate;
public class LongestString
{
@UserAggregationFunction
@Description( "org.neo4j.function.example.longestString(string) - aggregates the longest string found" )
public LongStringAggregator longestString()
{
return new LongStringAggregator();
}
public static class LongStringAggregator
{
private int longest;
private String longestString;
@UserAggregationUpdate
public void findLongest(
@Name( "string" ) String string )
{
if ( string != null && string.length() > longest)
{
longest = string.length();
longestString = string;
}
}
@UserAggregationResult
public String result()
{
return longestString;
}
}
}
Integration tests
Tests for user-defined aggregation functions are created in the same way as those for normal user-defined functions.
package example;
import org.junit.Rule;
import org.junit.Test;
import org.neo4j.driver.v1.*;
import org.neo4j.harness.junit.Neo4jRule;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.assertThat;
public class LongestStringTest
{
// This rule starts a Neo4j instance
@Rule
public Neo4jRule neo4j = new Neo4jRule()
// This is the function to test
.withAggregationFunction( LongestString.class );
@Test
public void shouldAllowIndexingAndFindingANode() throws Throwable
{
// This is in a try-block, to make sure you close the driver after the test
try( Driver driver = GraphDatabase.driver( neo4j.boltURI() , Config.build().withEncryptionLevel( Config.EncryptionLevel.NONE ).toConfig() ) )
{
// Given
Session session = driver.session();
// When
String result = session.run( "UNWIND ["abc", "abcd", "ab"] AS string RETURN example.longestString(string) AS result").single().get("result").asString();
// Then
assertThat( result, equalTo( "abcd" ) );
}
}
}
Reserved and deprecated function namespaces
Note that deprecated function namespaces will be moved to reserved in the next major Cypher version. For more information about Neo4j and Cypher versioning, see Operations manual → Introduction.
| Reserved | Deprecated in Cypher 25 since Neo4j 2025.11 |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|