Reputation: 41
I am current running a comparative experiment for some algorithms running on top of a relational database (PostgreSQL) and a graph one (Neo4j). I implemented my algorithm as a user-defined procedure for Neo4j, but it doesn't look like it performs any caching out-of-box. Is there a way to configure caching for user-defined procedures in Neo4j?
Thanks
Upvotes: 1
Views: 75
Reputation: 11715
You'll have to implement the caching yourself, if it's relevant for your use case and you have something to cache: probably something not related to the transaction, so no nodes or relationships; Neo4j ids are tricky, since they can be reused, so it's probably best to only cache them for a short duration, or not at all. Application-level ids would be fine, as would beans composed of strings or scalar types.
Suppose you have this procedure defined:
public class MyProcedure {
@Context
public GraphDatabaseService db;
@Procedure
public Stream<MyBean> doSomething(@Name("uuid") String uuid) {
int count = 0;
// ...
return Stream.of(new MyBean(count));
}
public static class MyBean {
public int count;
public MyBean(int count) {
this.count = count;
}
}
}
You can add some simple caching using a ConcurrentMap
:
public class MyProcedure {
private static final ConcurrentMap<String, Collection<MyBean>> CACHE =
new ConcurrentHashMap<>();
@Context
public GraphDatabaseService db;
@Procedure
public Stream<MyBean> doSomething(@Name("uuid") String uuid) {
Collection<MyBean> result = CACHE.computeIfAbsent(uuid,
k -> doSomethingCacheable(k).collect(Collectors.toList()));
return result.stream();
}
private Stream<MyBean> doSomethingCacheable(String uuid) {
int count = 0;
// ...
return Stream.of(new MyBean(count));
}
public static class MyBean {
// ...
}
}
Note that you can't cache a Stream
as it can only be consumed once, so you have to consume it yourself by collecting into an ArrayList
(you can also move the collect
inside the method, change the return type to Collection<MyBean>
and use a method reference). If the procedure takes more than one argument, you'll need to create a proper class for the composite key (immutable if possible, with correct equals
and hashCode
implementation). The restrictions that apply to cacheable values also apply to the keys.
This is an eternal, unbounded cache. If you need more features (expiration, maximum size), I suggest you use a real cache implementation, such as Guava's Cache
(or LoadingCache
) or Ben Manes' Caffeine.
Upvotes: 1