Skip to content

Instantly share code, notes, and snippets.

@wy-ei
Last active June 14, 2019 08:41
Show Gist options
  • Save wy-ei/d78177e7efe19c36f87bd4c4429193a6 to your computer and use it in GitHub Desktop.
Save wy-ei/d78177e7efe19c36f87bd4c4429193a6 to your computer and use it in GitHub Desktop.
neo4j 提供了数据导入工具,但是使用命令行输入太繁琐,多有不便。此处提供一个辅助工具帮助导入。
#coding=utf-8
import sys
import json
import os
import logging
import glob
logging.basicConfig(level=logging.DEBUG,
format="%(asctime)s - %(message)s",
datefmt='%Y-%m-%d %H:%M:%S')
def build_command_argument(config):
database = config.get('database', '')
nodes = config.get('nodes', [])
relationships = config.get('relationships', [])
delimiter = config.get('delimiter', ',')
array_delimiter = config.get('array-delimiter', ';')
quote = config.get('quote', '"')
ignore_duplicate_nodes = config.get('ignore-duplicate-nodes', False)
ignore_missing_nodes = config.get('ignore-missing-nodes', False)
multiline_field = config.get("multiline_field", False)
cmd = ''
if database:
cmd += ' --database=' + database
cmd += ' ' + build_nodes_arguments(nodes)
cmd += ' ' + build_relationships_arguments(relationships)
cmd += " --delimiter={0}{1}{0}".format('"', delimiter)
cmd += " --array-delimiter {0}{1}{0}".format('"', array_delimiter)
if quote != '"':
cmd += " --quote {0}{1}{0}".format('"', quote)
if ignore_duplicate_nodes:
cmd += " --ignore-duplicate-nodes=true"
if ignore_missing_nodes:
cmd += " --ignore-missing-nodes=true"
if multiline_field:
cmd += " --multiline-fields=true"
return cmd
def assert_file_exists(file):
matched_files = glob.glob(file)
if not matched_files:
message = 'has no matched file for pattern: ' + file
logging.error(message)
exit(-1)
def build_nodes_arguments(nodes):
if not nodes:
logging.error('Except at least one node file, but zero founded.')
arg = ''
for node in nodes:
labels = node.get('labels', [])
header = node.get('header', '')
file = node.get('file', '')
if labels:
arg += ' --nodes:{}='.format(':'.join(labels))
else:
arg += ' --nodes='
files = []
if header:
assert_file_exists(header)
files.append(header)
assert_file_exists(file)
files.append(file)
arg += '"{}"'.format(",".join(files))
return arg
def build_relationships_arguments(relationships):
arg = ''
for relation in relationships:
types = relation.get('types', [])
header = relation.get('header', '')
file = relation.get('file', '')
if types:
arg += ' --relationships:{}='.format(':'.join(types))
else:
arg += ' --relationships='
files = []
if header:
assert_file_exists(header)
files.append(header)
assert_file_exists(file)
files.append(file)
arg += '"{}"'.format(",".join(files))
return arg
def print_usage():
logging.info('usage:\n\n python import.py config.json')
if __name__ == '__main__':
if len(sys.argv) < 2:
print_usage()
sys.exit()
config_file = sys.argv[1]
with open(config_file, encoding='utf-8') as fin:
config = json.load(fin)
cmd_argument = build_command_argument(config)
neo4j_home = config['neo4j_home']
if not neo4j_home:
logging.error('neo4j_home must be specified.')
sys.exit()
os.environ['NEO4J_HOME'] = neo4j_home
cmd = neo4j_home + '/bin/neo4j-admin import ' + cmd_argument
# print(cmd)
os.system(cmd)
@wy-ei
Copy link
Author

wy-ei commented Feb 27, 2019

使用导入工具

如果需要要导入的文件很多,命令行就会很长。这里提供了一段 python 脚本,通过编写配置文件,生成相应的命令并执行,以缓解输入很长命令的麻烦。

用法如下:

$ python import.py config.json

其中 config.json 为配置文件,文件格式如下:

{   
    "neo4j_home": "/home/xx/neo4j-community",
    "database": "graph.db", // 指定数据库名,默认为 `graph.db`
    "nodes": [{ // 指定节点对应的 csv 文件
        "header": "./data/user_header.csv",
        "file": "./data/user.csv",
        "labels": ["USER"]
    },{ 
        "file": "./data/job.csv",
    }],
    "relationships": [{ // 指定关系对应的 csv 文件
        "file": "./data/browse.csv",
        "types": ['BROWSE']
    }],
    "delimiter": ",",
    "array-delimiter": ";",
    "quote": "\"",
    "ignore-duplicate-nodes": true,
    "ignore-missing-nodes": true
}

说明:

=> neo4j_home

此字段用于指定 neo4j 的主目录,便于定位可执行文件 neo4j-admin 的位置。

=> nodes / relationships

提供节点和关系的数据。

  • labels/types

在节点和关系对应的 csv 文件中,可以不添加 :LABEL 或者 :TYPE 列,而在配置文件中使用 labestypes 指出。因为一个节点可以有多种 label,相似地一个关系也可以有多个 type,因此这里使用数组。

  • header:

CSV 文件含两个部分,header 和 body,可以将 header 部分单独放在一个文件中。

=> delimiter

指定 csv 的列分隔符,默认为英文逗号 (,)。

=> array-delimiter

csv 文件中某个字段为数组时,数组元素间的分隔符。在生成 CSV 文件的时候,某个属性是数组,将其元素使用 array-delimiter 指定的字符拼接起来,在读入 neo4j 之后,该字段依然能被识别为数组。

=> quote

在 csv 文件中,某个字段的内容中出现了 delimiter,这会导致某一行列数增加,csv 格式就会出错。解决的办法是,将此字段使用 quote 括起来。括起来的内容,出现 delimiter 不会被解释为列分隔符。

因此这里的 quote 需要根据生成 CSV 时的设置来决定。

=> ignore-duplicate-nodes

是否忽略重复的节点,即 ID 重复的是否忽略,默认为 false。

=> ignore-missing-nodes

某个关系指定的节点不存在时,是否忽略该条关系。如果不忽略,就会报错。默认为 false,即不忽略。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment