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.
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" ) );
}
}
}