All Downloads are FREE. Search and download functionalities are using the official Maven repository.

apoc.export.cypher.MultiStatementCypherSubGraphExporter Maven / Gradle / Ivy

The newest version!
package apoc.export.cypher;

import apoc.export.cypher.formatter.CypherFormatterUtils;
import apoc.export.util.*;
import apoc.export.cypher.formatter.CypherFormatter;
import apoc.util.Util;
import org.neo4j.cypher.export.SubGraph;
import org.neo4j.graphdb.Label;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.schema.IndexDefinition;
import org.neo4j.helpers.collection.Iterables;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

import static apoc.export.cypher.formatter.CypherFormatterUtils.*;

/*
 * Idea is to lookup nodes for relationships via a unique index
 * either one inherent to the original node, or a artificial one that indexes the original node-id
 * and which is removed after the import.
 * 

* Outputs indexes and constraints at the beginning as their own transactions */ public class MultiStatementCypherSubGraphExporter { private final SubGraph graph; private final Map> uniqueConstraints = new HashMap<>(); private Set indexNames = new LinkedHashSet<>(); private Set indexedProperties = new LinkedHashSet<>(); private Long artificialUniques = 0L; private ExportFormat exportFormat; private CypherFormatter cypherFormat; public MultiStatementCypherSubGraphExporter(SubGraph graph, ExportConfig config) { this.graph = graph; this.exportFormat = config.getFormat(); this.cypherFormat = config.getCypherFormat().getFormatter(); gatherUniqueConstraints(); } /** * Given a full path file name like /tmp/myexport.cypher, * when ExportConfig#separateFiles() == true, * this method will create the following files: *

    *
  • /tmp/myexport.nodes.cypher
  • *
  • /tmp/myexport.schema.cypher
  • *
  • /tmp/myexport.relationships.cypher
  • *
  • /tmp/myexport.cleanup.cypher
  • *
* Otherwise all kernelTransaction will be saved in the original file. * @param config * @param reporter * @param cypherFileManager */ public void export(ExportConfig config, Reporter reporter, FileManagerFactory.ExportCypherFileManager cypherFileManager) throws IOException { int batchSize = config.getBatchSize(); exportNodes(cypherFileManager.getPrintWriter("nodes"), reporter, batchSize); exportSchema(cypherFileManager.getPrintWriter("schema")); exportRelationships(cypherFileManager.getPrintWriter("relationships"), reporter, batchSize); exportCleanUp(cypherFileManager.getPrintWriter("cleanup"), batchSize); reporter.done(); } public void exportOnlySchema(FileManagerFactory.ExportCypherFileManager cypherFileManager) throws IOException { exportSchema(cypherFileManager.getPrintWriter("schema")); } // ---- Nodes ---- private void exportNodes(PrintWriter out, Reporter reporter, int batchSize) { if (graph.getNodes().iterator().hasNext()) { begin(out); appendNodes(out, batchSize, reporter); commit(out); out.flush(); } } private long appendNodes(PrintWriter out, int batchSize, Reporter reporter) { long count = 0; for (Node node : graph.getNodes()) { if (count > 0 && count % batchSize == 0) restart(out); count++; appendNode(out, node, reporter); } return count; } private void appendNode(PrintWriter out, Node node, Reporter reporter) { artificialUniques += countArtificialUniques(node); String cypher = this.cypherFormat.statementForNode(node, uniqueConstraints, indexedProperties, indexNames); if (Util.isNotNullOrEmpty(cypher)) { out.println(cypher); reporter.update(1, 0, Iterables.count(node.getPropertyKeys())); } } // ---- Relationships ---- private void exportRelationships(PrintWriter out, Reporter reporter, int batchSize) { if (graph.getRelationships().iterator().hasNext()) { begin(out); appendRelationships(out, batchSize, reporter); commit(out); out.flush(); } } private long appendRelationships(PrintWriter out, int batchSize, Reporter reporter) { long count = 0; for (Relationship rel : graph.getRelationships()) { if (count > 0 && count % batchSize == 0) restart(out); count++; appendRelationship(out, rel, reporter); } return count; } private void appendRelationship(PrintWriter out, Relationship rel, Reporter reporter) { String cypher = this.cypherFormat.statementForRelationship(rel, uniqueConstraints, indexedProperties); if (cypher != null && !"".equals(cypher)) { out.println(cypher); reporter.update(0, 1, Iterables.count(rel.getPropertyKeys())); } } // ---- Schema ---- private void exportSchema(PrintWriter out) { List indexes = exportIndexes(); if (indexes.isEmpty() && artificialUniques == 0) return; begin(out); for (String index : indexes) { out.println(index); } if (artificialUniques > 0) { String cypher = this.cypherFormat.statementForConstraint(UNIQUE_ID_LABEL, Collections.singleton(UNIQUE_ID_PROP)); if (cypher != null && !"".equals(cypher)) { out.println(cypher); } } commit(out); List indexesAwait = indexesAwait(); for (String indexAwait : indexesAwait) { out.print(indexAwait); } schemaAwait(out); out.flush(); } private List exportIndexes() { List result = new ArrayList<>(); for (IndexDefinition index : graph.getIndexes()) { String label = index.getLabel().name(); Iterable props = index.getPropertyKeys(); if (index.isConstraintIndex()) { String cypher = this.cypherFormat.statementForConstraint(label, props); if (cypher != null && !"".equals(cypher)) { result.add(cypher); } } else { String cypher = this.cypherFormat.statementForIndex(label, props); if (cypher != null && !"".equals(cypher)) { result.add(0, cypher); } } } return result; } private List indexesAwait() { List result = new ArrayList<>(); for (IndexDefinition index : graph.getIndexes()) { String label = index.getLabel().name(); String indexAwait = this.exportFormat.indexAwait(label, index.getPropertyKeys()); if (indexAwait != null && !"".equals(indexAwait)) result.add(indexAwait); } return result; } // ---- CleanUp ---- private void exportCleanUp(PrintWriter out, int batchSize) { if (artificialUniques > 0) { while (artificialUniques > 0) { String cypher = this.cypherFormat.statementForCleanUp(batchSize); begin(out); if (cypher != null && !"".equals(cypher)) { out.println(cypher); } commit(out); artificialUniques -= batchSize; } begin(out); String cypher = this.cypherFormat.statementForConstraint(UNIQUE_ID_LABEL, Collections.singleton(UNIQUE_ID_PROP)).replaceAll("^CREATE", "DROP"); if (cypher != null && !"".equals(cypher)) { out.println(cypher); } commit(out); } out.flush(); } // ---- Common ---- private void begin(PrintWriter out) { out.print(exportFormat.begin()); } private void schemaAwait(PrintWriter out){ out.print(exportFormat.schemaAwait()); } private void restart(PrintWriter out) { commit(out); begin(out); } private void commit(PrintWriter out){ out.print(exportFormat.commit()); } private void gatherUniqueConstraints() { for (IndexDefinition indexDefinition : graph.getIndexes()) { String label = indexDefinition.getLabel().name(); //String prop = Iterables.first(indexDefinition.getPropertyKeys()); Set props = StreamSupport.stream(indexDefinition.getPropertyKeys().spliterator(), false).collect(Collectors.toSet()); indexNames.add(label); indexedProperties.addAll(props); if (indexDefinition.isConstraintIndex()) { if (!uniqueConstraints.containsKey(label)) uniqueConstraints.put(label, props); } } } private long countArtificialUniques(Node node) { long artificialUniques = 0; Iterator




© 2015 - 2025 Weber Informatics LLC | Privacy Policy