Как вернуть несколько узлов в Neo4j, используя плагин Java?
Я пытаюсь написать функцию на Java, которая находит узлы в моей графовой базе данных Neo4j с такими же именами и метками.
@UserFunction(value = "boris.example")
@Description("finds nodes with same name")
public ResourceIterator<Node> passName(@Name("nodeId") long nodeId)
{
Node nodeX = null;
Node node = db.getNodeById( nodeId ); //Find node with spcific ID
Object nameVal = node.getProperties("name"); //Get its name
Label label = Label.label("VersionableObject"); //Decl. of label
// Find nodes by label and name
ResourceIterator<Node> nodes = db.findNodes(label, "name", nameVal);
nodes.close();
return nodes;
}
Эта функция вызывает следующее исключение и отказывается запускать Neo4j:
"Довод ResourceIterator<Node>
в положении 0 в passName
с типом Label
не может быть преобразован в тип Neo4j: не знаю, как отобразить org.neo4j.graphdb.ResourceIterator
к системе типов Neo4j."
Затем я попытался преобразовать ResourceIterator в поток с помощью
Stream<Node> nodesStream = nodes.stream();
Та же ошибка - Neo4j не может отобразить поток..
ResourceIterator<Node> nodes = db.findNodes(label, "name", nameVal);
while (nodes.hasNext()) {
nodeX = nodes.next();
}
nodes.close();
return nodeX;
Вывод в Neo4j пустой, хотя он должен найти 3 узла.
Преобразование потока в массив или список также не сработало.
Работает поиск одного узла и отображение самого себя или его свойств, например:
Node node = db.getNodeById( nodeId );
Map<String, Object> propertyMap = node.getProperties("name");
РЕДАКТИРОВАТЬ
После изменения @UserFunction на @Procedure с mode.READ:
package org.neo4j.example.procedure_template;
import org.neo4j.graphdb.ResourceIterator;
import java.util.stream.Stream;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Label;
import org.neo4j.graphdb.Node;
import org.neo4j.logging.Log;
import org.neo4j.procedure.*;
import org.neo4j.procedure.Description;
import org.neo4j.procedure.Name;
public class FindNode {
@Context
public GraphDatabaseService db;
@Context
public Log log;
public FindNode() {
}
@Procedure(value = "boris.getAllNodesWithProperty", mode = Mode.READ)
@Description("boris.getAllNodesWithProperty - finds Node by ID and return defined Property")
public Stream<Node> passName(@Name("nodeId") long nodeId)
{
Node node = db.getNodeById( nodeId );
Object nameVal = node.getProperties("name");
Label label = Label.label("VersionableObject");
ResourceIterator<Node> nodes = db.findNodes(label, "name", nameVal);
Stream<Node> nodesStream = nodes.stream();
return nodesStream;
}
}
В этом случае я получаю: "Процедуры с нулевыми полями вывода должны быть объявлены как VOID".
Есть идеи? Спасибо!
1 ответ
В Neo4j вы можете расширить Cypher, создав несколько пользовательских user defined function
или же procedure
,
user defined function
это просто конвертер, он доступен только для чтения и возвращает единственный тип, который может быть: long, Long, double, Double, boolean, Boolean, String, Node, Relationship, Path, Map<String, Object, or List<T>
procedure
Может принимать аргументы, выполнять операции с базой данных и возвращать результаты (в виде потока).
В вашем коде вы определили user function
и я думаю, что вы хотите это procedure
, Вот почему у вас есть ошибка приведения ResourceIterator
к Neo4j Type System
,
Вы должны сделать эти изменения:
- замещать
@UserFunction(value = "boris.example")
от@Procedure(value = "boris.example", mode = Mode.READ)
- Измените тип возврата вашего метода на
Stream<Node>
Приветствия.
редактировать
Процедура должна вернуть pojo
или простой тип. Так что вы должны обернуть Node
в пойо вот так:
public class FindNode {
@Context
public GraphDatabaseService db;
@Context
public Log log;
@Procedure(value = "boris.getAllNodesWithProperty", mode = Mode.READ)
@Description("boris.getAllNodesWithProperty - finds Node by ID and return defined Property")
public Stream<NodeResult> passName(@Name("nodeId") long nodeId)
{
Node node = db.getNodeById( nodeId );
Object nameVal = node.getProperty("name");
Label label = Label.label("VersionableObject");
ResourceIterator<Node> nodes = db.findNodes(label, "name", nameVal);
return nodes.stream().map( item -> new NodeResult(item));
}
public class NodeResult {
public final Node node;
public NodeResult(Node node) {
this.node = node;
}
}
}