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

com.tinkerpop.blueprints.impls.neo4j2.batch.Neo4j2BatchGraph Maven / Gradle / Ivy

The newest version!
package com.tinkerpop.blueprints.impls.neo4j2.batch;

import com.tinkerpop.blueprints.Edge;
import com.tinkerpop.blueprints.Element;
import com.tinkerpop.blueprints.Features;
import com.tinkerpop.blueprints.GraphQuery;
import com.tinkerpop.blueprints.Index;
import com.tinkerpop.blueprints.IndexableGraph;
import com.tinkerpop.blueprints.KeyIndexableGraph;
import com.tinkerpop.blueprints.MetaGraph;
import com.tinkerpop.blueprints.Parameter;
import com.tinkerpop.blueprints.Vertex;
import com.tinkerpop.blueprints.util.ExceptionFactory;
import com.tinkerpop.blueprints.util.StringFactory;
import org.neo4j.graphdb.DynamicRelationshipType;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.PropertyContainer;
import org.neo4j.graphdb.Transaction;
import org.neo4j.graphdb.factory.GraphDatabaseBuilder;
import org.neo4j.graphdb.factory.GraphDatabaseFactory;
import org.neo4j.graphdb.factory.GraphDatabaseSettings;
import org.neo4j.graphdb.index.AutoIndexer;
import org.neo4j.index.lucene.unsafe.batchinsert.LuceneBatchInserterIndexProvider;
import org.neo4j.kernel.GraphDatabaseAPI;
import org.neo4j.kernel.impl.core.NodeManager;
import org.neo4j.tooling.GlobalGraphOperations;
import org.neo4j.unsafe.batchinsert.BatchInserter;
import org.neo4j.unsafe.batchinsert.BatchInserterIndexProvider;
import org.neo4j.unsafe.batchinsert.BatchInserters;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * A Blueprints implementation of the Neo4j batch inserter for bulk loading data into a Neo4j graph.
 * This is a single threaded, non-transactional bulk loader and should not be used for any other reason than for massive initial data loads.
 * 

* Neo4j2BatchGraph is not a completely faithful Blueprints implementation. * Many methods throw UnsupportedOperationExceptions and take unique arguments. Be sure to review each method's JavaDoc. * The Neo4j "reference node" (vertex 0) is automatically created and is not removed until the database is shutdown() (do not add edges to the reference node). * Key indices are not available until after the graph has been shutdown. * * @author Marko A. Rodriguez (http://markorodriguez.com) */ public class Neo4j2BatchGraph implements KeyIndexableGraph, IndexableGraph, MetaGraph { private final BatchInserter rawGraph; private final BatchInserterIndexProvider indexProvider; private final Map> indices = new HashMap>(); private Long idCounter = 0l; protected final Set vertexIndexKeys = new HashSet(); protected final Set edgeIndexKeys = new HashSet(); private static final Features FEATURES = new Features(); private static final String INDEXED_KEYS_POSTFIX = ":indexed_keys"; static { FEATURES.supportsSerializableObjectProperty = false; FEATURES.supportsBooleanProperty = true; FEATURES.supportsDoubleProperty = true; FEATURES.supportsFloatProperty = true; FEATURES.supportsIntegerProperty = true; FEATURES.supportsPrimitiveArrayProperty = true; FEATURES.supportsUniformListProperty = true; FEATURES.supportsMixedListProperty = false; FEATURES.supportsLongProperty = true; FEATURES.supportsMapProperty = false; FEATURES.supportsStringProperty = true; FEATURES.supportsDuplicateEdges = true; FEATURES.supportsSelfLoops = true; FEATURES.isPersistent = true; FEATURES.isWrapper = false; FEATURES.supportsVertexIteration = false; FEATURES.supportsEdgeIteration = false; FEATURES.supportsVertexIndex = true; FEATURES.supportsEdgeIndex = true; FEATURES.ignoresSuppliedIds = false; FEATURES.supportsTransactions = false; FEATURES.supportsIndices = true; FEATURES.supportsKeyIndices = true; FEATURES.supportsVertexKeyIndex = true; FEATURES.supportsEdgeKeyIndex = true; FEATURES.supportsEdgeRetrieval = true; FEATURES.supportsVertexProperties = true; FEATURES.supportsEdgeProperties = true; FEATURES.supportsThreadedTransactions = false; FEATURES.supportsThreadIsolatedTransactions = false; } public Neo4j2BatchGraph(final String directory) { this.rawGraph = BatchInserters.inserter(directory); this.indexProvider = new LuceneBatchInserterIndexProvider(this.rawGraph); } public Neo4j2BatchGraph(final String directory, final Map parameters) { if (null == parameters) this.rawGraph = BatchInserters.inserter(directory); else this.rawGraph = BatchInserters.inserter(directory, parameters); this.indexProvider = new LuceneBatchInserterIndexProvider(this.rawGraph); } public Neo4j2BatchGraph(final BatchInserter rawGraph, final BatchInserterIndexProvider indexProvider) { this.rawGraph = rawGraph; this.indexProvider = indexProvider; } public void shutdown() { this.flushIndices(); this.indexProvider.shutdown(); this.rawGraph.shutdown(); removeReferenceNodeAndFinalizeKeyIndices(); } /** * This is necessary prior to using indices to ensure that indexed data is available to index queries. * This method is not part of the Blueprints Graph or IndexableGraph API. * Therefore, be sure to typecast your graph to a Neo4j2BatchGraph to use this necessary index-based method. * Note that key indices are not usable until the Neo4j2BatchGraph has been shutdown. */ public void flushIndices() { for (final Neo4j2BatchIndex index : this.indices.values()) { index.flush(); } } private void removeReferenceNodeAndFinalizeKeyIndices() { GraphDatabaseService rawGraphDB = null; try { GraphDatabaseBuilder builder = new GraphDatabaseFactory().newEmbeddedDatabaseBuilder(this.rawGraph.getStoreDir()); if (this.vertexIndexKeys.size() > 0) builder.setConfig(GraphDatabaseSettings.node_keys_indexable, vertexIndexKeys.toString().replace("[", "").replace("]", "")).setConfig(GraphDatabaseSettings.node_auto_indexing, "true"); if (this.edgeIndexKeys.size() > 0) builder.setConfig(GraphDatabaseSettings.relationship_keys_indexable, edgeIndexKeys.toString().replace("[", "").replace("]", "")).setConfig(GraphDatabaseSettings.relationship_auto_indexing, "true"); rawGraphDB = builder.newGraphDatabase(); Transaction tx = rawGraphDB.beginTx(); try { GlobalGraphOperations graphOperations = GlobalGraphOperations.at(rawGraphDB); if (this.vertexIndexKeys.size() > 0) populateKeyIndices(rawGraphDB, rawGraphDB.index().getNodeAutoIndexer(), graphOperations.getAllNodes(), Vertex.class); if (this.edgeIndexKeys.size() > 0) populateKeyIndices(rawGraphDB, rawGraphDB.index().getRelationshipAutoIndexer(), graphOperations.getAllRelationships(), Edge.class); tx.success(); } finally { tx.close(); } } catch (Exception e) { throw new RuntimeException(e.getMessage(), e); } finally { if (rawGraphDB != null) rawGraphDB.shutdown(); } } private static void populateKeyIndices(final GraphDatabaseService rawGraphDB, final AutoIndexer rawAutoIndexer, final Iterable rawElements, final Class elementClass) { if (!rawAutoIndexer.isEnabled()) return; final Set properties = rawAutoIndexer.getAutoIndexedProperties(); Transaction tx = rawGraphDB.beginTx(); final PropertyContainer kernel = ((GraphDatabaseAPI) rawGraphDB).getDependencyResolver().resolveDependency(NodeManager.class).getGraphProperties(); kernel.setProperty(elementClass.getSimpleName() + INDEXED_KEYS_POSTFIX, properties.toArray(new String[properties.size()])); int count = 0; for (final PropertyContainer pc : rawElements) { for (final String property : properties) { if (!pc.hasProperty(property)) continue; pc.setProperty(property, pc.getProperty(property)); count++; if (count >= 10000) { count = 0; tx.success(); tx.finish(); tx = rawGraphDB.beginTx(); } } } tx.success(); tx.finish(); } public String toString() { return StringFactory.graphString(this, this.rawGraph.toString()); } public BatchInserter getRawGraph() { return this.rawGraph; } /** * {@inheritDoc} *

* The object id can either be null, a long id, or a Map<String,Object>. * If null, then an internal long is provided on the construction of the vertex. * If a long id is provided, then the vertex is constructed with that long id. * If a map is provided, then the map serves as the properties of the vertex. * Moreover, if the map contains an _id key, then the value is a user provided long vertex id. * * @param id a id of properties which can be null * @return the newly created vertex */ public Vertex addVertex(final Object id) { final Long finalId; Map finalProperties = new HashMap(); if (null == id) { rawGraph.createNode(++this.idCounter, finalProperties); finalId = this.idCounter; } else if (id instanceof Long) { rawGraph.createNode((Long) id, finalProperties); finalId = (Long) id; } else if (id instanceof Map) { finalProperties = makePropertyMap((Map) id); final Long providedId = (Long) ((Map) id).get(Neo4j2BatchTokens.ID); finalProperties.remove(Neo4j2BatchTokens.ID); if (providedId == null) finalId = rawGraph.createNode(finalProperties); else { rawGraph.createNode(providedId, finalProperties); finalId = providedId; } } else { try { finalId = Double.valueOf(id.toString()).longValue(); rawGraph.createNode(finalId, finalProperties); } catch (NumberFormatException e) { throw new IllegalArgumentException("The provided object must be null, a long id, an object convertible to long, or a Map"); } } return new Neo4j2BatchVertex(this, finalId); } public Vertex getVertex(final Object id) { if (null == id) throw ExceptionFactory.vertexIdCanNotBeNull(); try { final Long longId; if (id instanceof Long) longId = (Long) id; else longId = Double.valueOf(id.toString()).longValue(); if (rawGraph.nodeExists(longId)) { return new Neo4j2BatchVertex(this, longId); } else { return null; } } catch (NumberFormatException e) { return null; } } /** * @throws UnsupportedOperationException */ public Iterable getVertices() throws UnsupportedOperationException { throw new UnsupportedOperationException(); } /** * @throws UnsupportedOperationException */ public Iterable getVertices(final String key, final Object value) throws UnsupportedOperationException { throw new UnsupportedOperationException(); } /** * @throws UnsupportedOperationException */ public void removeVertex(final Vertex vertex) throws UnsupportedOperationException { throw new UnsupportedOperationException(Neo4j2BatchTokens.DELETE_OPERATION_MESSAGE); } /** * {@inheritDoc} *

* The object id must be a Map<String,Object> or null. * The id is the properties written when the vertex is created. * While it is possible to Edge.setProperty(), this method is faster. * * @param id a id of properties which can be null * @return the newly created vertex */ public Edge addEdge(final Object id, final Vertex outVertex, final Vertex inVertex, final String label) { if (label == null) throw ExceptionFactory.edgeLabelCanNotBeNull(); final Map finalProperties; if (id == null || !(id instanceof Map)) finalProperties = new HashMap(); else finalProperties = makePropertyMap((Map) id); final Long finalId = this.rawGraph.createRelationship((Long) outVertex.getId(), (Long) inVertex.getId(), DynamicRelationshipType.withName(label), finalProperties); return new Neo4j2BatchEdge(this, finalId, label); } /** * @throws UnsupportedOperationException */ public Edge getEdge(final Object id) throws UnsupportedOperationException { throw new UnsupportedOperationException(); } /** * @throws UnsupportedOperationException */ public Iterable getEdges() throws UnsupportedOperationException { throw new UnsupportedOperationException(); } /** * @throws UnsupportedOperationException */ public Iterable getEdges(final String key, final Object value) throws UnsupportedOperationException { throw new UnsupportedOperationException(); } /** * @throws UnsupportedOperationException */ public void removeEdge(final Edge edge) throws UnsupportedOperationException { throw new UnsupportedOperationException(Neo4j2BatchTokens.DELETE_OPERATION_MESSAGE); } public Index getIndex(final String indexName, final Class indexClass) { return (Index) this.indices.get(indexName); } public Index createIndex(final String indexName, final Class indexClass, final Parameter... indexParameters) { final Neo4j2BatchIndex index; final Map map = generateParameterMap(indexParameters); if (indexParameters.length == 0) { map.put(Neo4j2BatchTokens.TYPE, Neo4j2BatchTokens.EXACT); } if (Vertex.class.isAssignableFrom(indexClass)) { index = new Neo4j2BatchIndex(this, indexProvider.nodeIndex(indexName, map), indexName, indexClass); } else { index = new Neo4j2BatchIndex(this, indexProvider.relationshipIndex(indexName, map), indexName, indexClass); } this.indices.put(indexName, index); return index; } public Iterable> getIndices() { return (Iterable) this.indices.values(); } /** * @throws UnsupportedOperationException */ public void dropIndex(final String indexName) throws UnsupportedOperationException { throw new UnsupportedOperationException(Neo4j2BatchTokens.DELETE_OPERATION_MESSAGE); } private Map makePropertyMap(final Map map) { final Map properties = new HashMap(); for (final Map.Entry entry : map.entrySet()) { if (!entry.getKey().equals(Neo4j2BatchTokens.ID)) { properties.put(entry.getKey(), entry.getValue()); } } return properties; } public void dropKeyIndex(final String key, final Class elementClass) { if (Vertex.class.isAssignableFrom(elementClass)) { this.vertexIndexKeys.remove(key); } else { this.edgeIndexKeys.remove(key); } } public void createKeyIndex(final String key, final Class elementClass, final Parameter... indexParameters) { if (Vertex.class.isAssignableFrom(elementClass)) { this.vertexIndexKeys.add(key); } else { this.edgeIndexKeys.add(key); } } public Set getIndexedKeys(final Class elementClass) { if (Vertex.class.isAssignableFrom(elementClass)) { return this.vertexIndexKeys; } else { return this.edgeIndexKeys; } } private static Map generateParameterMap(final Parameter... indexParameters) { final Map map = new HashMap(); for (final Parameter parameter : indexParameters) { map.put(parameter.getKey().toString(), parameter.getValue().toString()); } return map; } public Features getFeatures() { return FEATURES; } public GraphQuery query() { throw new UnsupportedOperationException(); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy