All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
dev.langchain4j.store.graph.neo4j.Neo4jGraph Maven / Gradle / Ivy
package dev.langchain4j.store.graph.neo4j;
import lombok.Builder;
import lombok.Getter;
import org.neo4j.driver.Driver;
import org.neo4j.driver.Query;
import org.neo4j.driver.Record;
import org.neo4j.driver.Result;
import org.neo4j.driver.Session;
import org.neo4j.driver.Value;
import org.neo4j.driver.exceptions.ClientException;
import org.neo4j.driver.summary.ResultSummary;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static dev.langchain4j.internal.ValidationUtils.ensureNotNull;
public class Neo4jGraph implements AutoCloseable {
private static final String NODE_PROPERTIES_QUERY = """
CALL apoc.meta.data()
YIELD label, other, elementType, type, property
WHERE NOT type = "RELATIONSHIP" AND elementType = "node"
WITH label AS nodeLabels, collect({property:property, type:type}) AS properties
RETURN {labels: nodeLabels, properties: properties} AS output
""";
private static final String REL_PROPERTIES_QUERY = """
CALL apoc.meta.data()
YIELD label, other, elementType, type, property
WHERE NOT type = "RELATIONSHIP" AND elementType = "relationship"
WITH label AS nodeLabels, collect({property:property, type:type}) AS properties
RETURN {type: nodeLabels, properties: properties} AS output
""";
private static final String RELATIONSHIPS_QUERY = """
CALL apoc.meta.data()
YIELD label, other, elementType, type, property
WHERE type = "RELATIONSHIP" AND elementType = "node"
UNWIND other AS other_node
RETURN {start: label, type: property, end: toString(other_node)} AS output
""";
private final Driver driver;
@Getter
private String schema;
@Builder
public Neo4jGraph(final Driver driver) {
this.driver = ensureNotNull(driver, "driver");
this.driver.verifyConnectivity();
try {
refreshSchema();
} catch (ClientException e) {
if ("Neo.ClientError.Procedure.ProcedureNotFound".equals(e.code())) {
throw new Neo4jException("Please ensure the APOC plugin is installed in Neo4j", e);
}
throw e;
}
}
public ResultSummary executeWrite(String queryString) {
try (Session session = this.driver.session()) {
return session.executeWrite(tx -> tx.run(queryString).consume());
} catch (ClientException e) {
throw new Neo4jException("Error executing query: " + queryString, e);
}
}
public List executeRead(String queryString) {
try (Session session = this.driver.session()) {
return session.executeRead(tx -> {
Query query = new Query(queryString);
Result result = tx.run(query);
return result.list();
});
} catch (ClientException e) {
throw new Neo4jException("Error executing query: " + queryString, e);
}
}
public void refreshSchema() {
List nodeProperties = formatNodeProperties(executeRead(NODE_PROPERTIES_QUERY));
List relationshipProperties = formatRelationshipProperties(executeRead(REL_PROPERTIES_QUERY));
List relationships = formatRelationships(executeRead(RELATIONSHIPS_QUERY));
this.schema = "Node properties are the following:\n" +
String.join("\n", nodeProperties) + "\n\n" +
"Relationship properties are the following:\n" +
String.join("\n", relationshipProperties) + "\n\n" +
"The relationships are the following:\n" +
String.join("\n", relationships);
}
private List formatNodeProperties(List records) {
return records.stream()
.map(this::getOutput)
.map(r -> String.format("%s %s", r.asMap().get("labels"), formatMap(r.get("properties").asList(Value::asMap))))
.toList();
}
private List formatRelationshipProperties(List records) {
return records.stream()
.map(this::getOutput)
.map(r -> String.format("%s %s", r.get("type"), formatMap(r.get("properties").asList(Value::asMap))))
.toList();
}
private List formatRelationships(List records) {
return records.stream()
.map(r -> getOutput(r).asMap())
.map(r -> String.format("(:%s)-[:%s]->(:%s)", r.get("start"), r.get("type"), r.get("end")))
.toList();
}
private Value getOutput(Record record) {
return record.get("output");
}
private String formatMap(List> properties) {
return properties.stream()
.map(prop -> prop.get("property") + ":" + prop.get("type"))
.collect(Collectors.joining(", ", "{", "}"));
}
@Override
public void close() {
this.driver.close();
}
}