Skip to content

Commit

Permalink
Merge pull request #7954 from srbaker/3.1-move-csv-import-to-admin-tool
Browse files Browse the repository at this point in the history
3.1 move csv import to admin tool
  • Loading branch information
srbaker committed Sep 16, 2016
2 parents 62e5692 + f89010c commit 30b42e9
Show file tree
Hide file tree
Showing 16 changed files with 475 additions and 177 deletions.
3 changes: 3 additions & 0 deletions community/dbms/LICENSES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@ libraries. For an overview of the licenses see the NOTICE.txt file.
------------------------------------------------------------------------------
Apache Software License, Version 2.0
Apache Commons Compress
Lucene codecs
Lucene Common Analyzers
Lucene Core
Lucene Memory
Lucene QueryParsers
------------------------------------------------------------------------------

Apache License
Expand Down
3 changes: 3 additions & 0 deletions community/dbms/NOTICE.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ Third-party licenses

Apache Software License, Version 2.0
Apache Commons Compress
Lucene codecs
Lucene Common Analyzers
Lucene Core
Lucene Memory
Lucene QueryParsers

5 changes: 5 additions & 0 deletions community/dbms/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@
<artifactId>neo4j-io</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-import-tool</artifactId>
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>org.apache.commons</groupId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Copyright (c) 2002-2016 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.commandline.dbms;

import java.io.IOException;
import java.util.Arrays;

import org.neo4j.kernel.configuration.Config;
import org.neo4j.tooling.ImportTool;

import static org.neo4j.dbms.DatabaseManagementSystemSettings.database_path;

class CsvImporter implements Importer
{
public static String description()
{
return "--mode=csv Import a database from a collection of CSV files.\n" +
"--nodes[:Label1:Label2]=\"<file1>,<file2>,...\"\n" +
" Node CSV header and data. Multiple files will be logically seen as\n" +
" one big file from the perspective of the importer. The first line\n" +
" must contain the header. Multiple data sources like these can be\n" +
" specified in one import, where each data source has its own header.\n" +
" Note that file groups must be enclosed in quotation marks.\n" +
"--relationships[:RELATIONSHIP_TYPE] \"<file1>,<file2>,...\"\n" +
" Relationship CSV header and data. Multiple files will be logically\n" +
" seen as one big file from the perspective of the importer. The first\n" +
" line must contain the header. Multiple data sources like these can be\n" +
" specified in one import, where each data source has its own header.\n" +
" Note that file groups must be enclosed in quotation marks.\n" +
"--id-type <id-type>\n" +
" Each node must provide a unique id. This is used to find the correct\n" +
" nodes when creating relationships. Must be one of:\n" +
" STRING: (default) arbitrary strings for identifying nodes.\n" +
" INTEGER: arbitrary integer values for identifying nodes.\n" +
" ACTUAL: (advanced) actual node ids. The default option is STRING.\n" +
" For more information on id handling, please see the Neo4j Manual:\n" +
" http://neo4j.com/docs/operations-manual/current/deployment/#import-tool\n" +
"--input-encoding <character-set>\n" +
" Character set that input data is encoded in. Defaults to UTF-8.\n" +
"--page-size <page-size>\n" +
" Page size to use for import in bytes. (e. g. 4M or 8k)\n";
}

public static String arguments()
{
return "[--nodes[:Label1:Label2]=\"<file1>,<file2>,...\"] " +
"[--relationships[:RELATIONSHIP_TYPE]=\"<file1>,<file2>,...\"] " +
"[--input-encoding=<character-set>] " +
"[--id-type=<id-type>] ";
}

private String[] args;

CsvImporter( String[] args, Config config )
{
this.args = Arrays.copyOf( args, args.length + 1 );
this.args[args.length] = String.format( "--into=%s", config.get( database_path ) );
}

@Override
public void doImport() throws IOException
{
ImportTool.main( args );
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* Copyright (c) 2002-2016 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.commandline.dbms;

import java.io.File;
import java.io.IOException;

import org.neo4j.commandline.admin.IncorrectUsage;
import org.neo4j.helpers.Args;
import org.neo4j.io.fs.FileUtils;
import org.neo4j.kernel.configuration.Config;
import org.neo4j.kernel.impl.util.Converters;
import org.neo4j.kernel.impl.util.Validators;

import static org.neo4j.dbms.DatabaseManagementSystemSettings.database_path;

class DatabaseImporter implements Importer
{
public static String arguments()
{
return "[--from=<source-directory>]";
}

public static String description()
{
return "--mode=database" +
" Import a database from a pre-3.0 Neo4j installation. \n" +
" <source-directory> is the database location\n" +
" (e.g. <neo4j-root>/data/graph.db).\n";
}

private final File from;
private final Config config;

DatabaseImporter( String[] args, Config config ) throws IncorrectUsage
{
this.config = config;
Args parsedArgs = Args.parse( args );

try
{
this.from = parsedArgs.interpretOption( "from", Converters.mandatory(), Converters.toFile(),
Validators.CONTAINS_EXISTING_DATABASE );
}
catch ( IllegalArgumentException e )
{
throw new IncorrectUsage( e.getMessage() );
}
}

@Override
public void doImport() throws IOException
{
copyDatabase( from, config );
removeMessagesLog( config );
}

private void copyDatabase( File from, Config config ) throws IOException
{
FileUtils.copyRecursively( from, config.get( database_path ) );
}

private void removeMessagesLog( Config config )
{
FileUtils.deleteFile( new File( config.get( database_path ), "messages.log" ) );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import org.neo4j.commandline.admin.AdminCommand;
Expand All @@ -33,17 +35,16 @@
import org.neo4j.dbms.DatabaseManagementSystemSettings;
import org.neo4j.graphdb.factory.GraphDatabaseSettings;
import org.neo4j.helpers.Args;
import org.neo4j.io.fs.FileUtils;
import org.neo4j.helpers.collection.MapUtil;
import org.neo4j.kernel.configuration.Config;
import org.neo4j.kernel.impl.util.Converters;
import org.neo4j.kernel.impl.util.Validators;
import org.neo4j.server.configuration.ConfigLoader;

import static org.neo4j.dbms.DatabaseManagementSystemSettings.database_path;
import static org.neo4j.helpers.collection.MapUtil.stringMap;

public class ImportCommand implements AdminCommand
{
private String database;

public static class Provider extends AdminCommand.Provider
{
public Provider()
Expand All @@ -54,14 +55,20 @@ public Provider()
@Override
public Optional<String> arguments()
{
return Optional.of( "--mode=<mode> --database=<database-name> --from=<source-directory>" );
return Optional.of(
"--mode={database|csv} --database=<database-name> [--additional-config=<config-file-path>] " +
DatabaseImporter.arguments() + " " + CsvImporter.arguments() );
}

@Override
public String description()
{
return "Import a database from a pre-3.0 Neo4j installation. <source-directory> " +
"is the database location (e.g. <neo4j-root>/data/graph.db).";
return "Import a collection of CSV files with --mode=csv, or a database from a\n" +
"pre-3.0 installation with --mode=database." +
"\n" +
DatabaseImporter.description() +
"\n\n" +
CsvImporter.description();
}

@Override
Expand All @@ -73,8 +80,9 @@ public AdminCommand create( Path homeDir, Path configDir, OutsideWorld outsideWo

private final Path homeDir;
private final Path configDir;
private final String[] allowedModes = {"database", "csv"};

public ImportCommand( Path homeDir, Path configDir )
ImportCommand( Path homeDir, Path configDir )
{
this.homeDir = homeDir;
this.configDir = configDir;
Expand All @@ -83,17 +91,17 @@ public ImportCommand( Path homeDir, Path configDir )
@Override
public void execute( String[] args ) throws IncorrectUsage, CommandFailed
{
File from;
String database;

Args parsedArgs = Args.parse( args );
String mode;
File additionalConfigFile;

try
{
parsedArgs.interpretOption( "mode", Converters.<String>mandatory(), s -> s,
Validators.inList( new String[]{"database"} ) );
database = parsedArgs.interpretOption( "database", Converters.<String>mandatory(), s -> s );
from = parsedArgs.interpretOption( "from", Converters.<File>mandatory(), Converters.toFile(),
Validators.CONTAINS_EXISTING_DATABASE );
mode = parsedArgs
.interpretOption( "mode", Converters.mandatory(), s -> s, Validators.inList( allowedModes ) );
this.database = parsedArgs.interpretOption( "database", Converters.mandatory(), s -> s );
additionalConfigFile =
parsedArgs.interpretOption( "additional-config", Converters.optional(), Converters.toFile() );
}
catch ( IllegalArgumentException e )
{
Expand All @@ -102,41 +110,60 @@ public void execute( String[] args ) throws IncorrectUsage, CommandFailed

try
{
Config config = loadNeo4jConfig( homeDir, configDir, database );
copyDatabase( from, config );
removeMessagesLog( config );
Config config =
loadNeo4jConfig( homeDir, configDir, this.database, loadAdditionalConfig( additionalConfigFile ) );
Importer importer;

switch ( mode )
{
case "database":
importer = new DatabaseImporter( args, config );
break;
case "csv":
importer = new CsvImporter( args, config );
break;
default:
throw new CommandFailed( "Invalid mode specified." ); // This won't happen because mode is mandatory.
}

importer.doImport();
}
catch ( IOException e )
{
throw new RuntimeException( e );
}

}

private void copyDatabase( File from, Config config ) throws IOException
private Map<String,String> loadAdditionalConfig( File additionalConfigFile )
{
FileUtils.copyRecursively( from, config.get( database_path ) );
}
if ( additionalConfigFile == null )
{
return new HashMap<>();
}

private void removeMessagesLog( Config config )
{
FileUtils.deleteFile( new File( config.get( database_path ), "messages.log" ) );
try
{
return MapUtil.load( additionalConfigFile );
}
catch ( IOException e )
{
throw new IllegalArgumentException(
String.format( "Could not read configuration file [%s]", additionalConfigFile ), e );
}
}

private static Config loadNeo4jConfig( Path homeDir, Path configDir, String databaseName )
private static Config loadNeo4jConfig( Path homeDir, Path configDir, String databaseName,
Map<String,String> additionalConfig )
{
ConfigLoader configLoader = new ConfigLoader( settings() );
Config config = configLoader.loadConfig( Optional.of( homeDir.toFile() ),
Optional.of( configDir.resolve( "neo4j.conf" ).toFile() ) );

return config.with( stringMap( DatabaseManagementSystemSettings.active_database.name(), databaseName ) );
additionalConfig.put( DatabaseManagementSystemSettings.active_database.name(), databaseName );
return config.with( additionalConfig );
}

private static List<Class<?>> settings()
{
List<Class<?>> settings = new ArrayList<>();
settings.add( GraphDatabaseSettings.class );
settings.add( DatabaseManagementSystemSettings.class );
return settings;
return Arrays.asList( GraphDatabaseSettings.class, DatabaseManagementSystemSettings.class );
}
}

0 comments on commit 30b42e9

Please sign in to comment.