第 27 章 Neo4j 命令行
Neo4j shell是一个用来浏览图数据库的命令行shell,就像在Unix Shell中你可以使用像 cd, ls和 +pwd+来浏览你的本地文件系统一样。
它包括两个部分:
- 通过RMI发送命令的轻量级客户端
- 处理这些命令并返回结果的客户端
它是用于开发和调试非常好的工具。这个向导将给你展示如何使用它。
27.1. 启动 shell
当Neo4j作为一个服务器已经启动时,你只需要简单的输入下面的命令:
1 | ./bin/neo4j-shell |
要了解完整的选项,请参考:Shell 手册。
为了连接到一个正在运行的Neo4j图数据库,使用只读模式连接到本地数据库而远程数据库请参考:第 27.1.1 节 “使能Shell服务器”。
当你启动你的Neo4j实例时,你需要确保shell jar文件正类路径中。
27.1.1. 使能Shell服务器
Shell从Neo4j内核配置中设置是否启动,请参考:server-configuration,服务器配置。这儿是一个范例配置:
1 2 3 4 | # 使用默认配置 enable_remote_shell = true # ...或者指定自定义端口,而使用默认参数给其他地方 enable_remote_shell = port=1234 |
当使用Neo4j服务器时,看server-configuration,服务器配置了解如何在这种情况下新增配置设置。
有两个方法启动Shell,要么是连接到一个远端Shell服务器又或者直接指向一个Neo4j的存储路径。
27.1.2. 连接到Shell服务器
为了启动Shell并连接到一个运行的服务器,请运行:
1 | neo4j-shell |
另外还支持 -port和 -name选项,当然它们取决于远程Shell服务器如何启动的。然后你将得到一个shell提示符像下面这样:
1 | neo4j-sh (0)$ |
27.1.3. 把shell指向一个路径
通过指定到一个你运行shell jar文件的Neo4j存储路径来启动shell。 neo4j-kernel-<version>.jar 和 jta jar文件与你的neo4j-shell-<version>.jar在同一个目录,你可以用下面的命令启动它:
1 | $ neo4j-shell -path path/to/neo4j-db |
27.1.4. 只读模式
正启动一个带存储路径的shell时指定 -readonly开关,那么在会话期间就能进行任何写操作。
1 | $ neo4j-shell -readonly -path path/to/neo4j-db |
27.1.5. 运行一个命令然后退出
可以告诉shell只是启动,执行一个命令然后就退出。
这个功能用于后台任务和管理大量输出的命令,比如 ''ls',你可以通过管道将它输出到 ''less''' 或者其他你选择的阅读工具上面,或者甚至是一个文件。
下面是用法范例:
1 2 | $ neo4j-shell -c "cd -a 24 && set name Mattias" $ neo4j-shell -c "trav -r KNOWS" | less | |||
上一页 | 下一页 |
27.2. 传递选项和参数
传递选项和参数给你的命令行相比在 *nix环境下需要CLI命令行来说是非常简单的。选项带有 -前缀而且可以包括多个选项。一些选项起到有一个值。参数是没有 -前缀的字符串。让我们把 ls作为一个范例看看:
ls -r -f KNOWS:out -v 12345将生成一个带有输出关系 KNOWS的节点 12345' 关联的节点详细列表。节点, 12345+,是 +ls的一个参数,告诉它是要显示这个指定的节点而不是当前节点(默认是当前节点,使用命令: pwd查看当前节点)。然而这个也有一个简短的版本:
ls -rfv KNOWS:out 12345。这儿三个选项都写在一个单独的前缀 -后面合并在一起的。虽然 f在中间,它也知道是 KNOWS:out需要的值。这是因为 ls+命令的选项 +r或者 v并不期望任何值。因此,它能推断出正确的选项和对应的值。
27.3. 枚举选项
一些选项期望一个值是一个枚举中的一个,比如,关系类型的方向就是: INCOMING+, +OUTGOING和 BOTH。这些值都在之前已经提供了。它足够你使用并且解释器也能找出你真正的意思。比如 out+, +in+, +i设置是 +INCOMING
27.4. 过滤器
一些命令使用过滤器来达到各种目的。比如,在 ls和在 trav中的 +-f+。一个过滤器以一个http://www.json.org/[json]对象的形式提供,键和键值都能包括正则表达式来表示更复杂的匹配。
一个过滤器的范例是: .*url.*:http.*neo4j.*,name:Neo4j+。过滤器选项也可以伴随 +-i和 -l等选项,表示 忽略大小写和 宽松的匹配(即时过滤器的值只匹配一部分也认为完全匹配而不要求完整匹配)。所以如果不考虑大小写并且模糊查询的话,你可以使用 -f -i -l或者它们的简短版本: -fil。
27.5. 节点标题标签
为了能更好的浏览你的图数据库,shell可以为每一个节点显示标题。比如: +ls -r+。它将显示关系以及关系相连的其他节点。标题和每一个节点显示在一起而这个标题可以由一组属性值组合而成。
如果你站在一个有两个 KNOWS+关系指向其他节点的节点上时,你是很难知道谁是谁的朋友的。标题特性通过读取一系列属性值并且抓取这些属性存在的第一个属性值组合在一起并作为节点的标题显示。因此你可以从列表中选择需要的属性。比如:+name,title.*,caption而每个节点的标题将是在那个列表中第一个存在的值。列表通过你的使用 TITLE_KEYS环境变量来定义,默认是: +.*name.*,.*title.*+。
27.6. 如何使用私有命令
shell是在Unix Shell之后建立模型的,比如你用来浏览你本地文件系统的bash。它们有一些相同的命令,比如 cd和 ls+。当你第一次启动shell时,你将获取到所有变量命令的一个列表。使用 +man <命令>获取更多关于一些特殊命令的用法。
27.6.1. 当前节点/关系以及路径
你有一个当前节点/关系和一个 “当前路径”(像在bash中的当前工作目录一样)到此,你可以遍历查询了。你从参考节点开始,然后 cd到你想去的路径(任何时候都可以通过命令 pwd查询当前路径)。 cd可以以不同的方式使用:
- cd <node-id>将遍历一个关系到指定ID的节点。节点必须有一个直接关系连接到当前节点。
- cd -a <node-id>将做一次绝对路径切换,意味着给定的节点必须有一个直接的关系连接到当前节点。
- cd -r <relationship-id>将遍历到一个关系而不是一个节点。关系必须有当前节点作为起点或者终点。在节点上面使用命令 ls -vr查询关系的id。
- cd -ar <relationship-id>将做一次绝对路径切换,意味着给定的关系可以是图中的任意一个关系。
- cd将把你重新带回参考节点处,就是你开始的地方。
- cd ..将带你返回上一次所在的地方,如果去掉 .. 将会带你到参考节点处。
- cd start_(只适合你的当前路径是一个关系)_。遍历到关系的开始节点处。
- cd end_(只适合你的当前路径是一个关系)_。遍历到关系的结束节点处。
27.6.2. 列出一个节点/关系的内容
使用命令 ls来列举当前节点/关系的内容(当然也可以是其他节点)。请注意如果当前节点/属性每一任何属性或者关系图将返回一个空值。(比如在一个新数据库上面)。 ls使用一个节点作为参数,也可以使用过滤器,细节请参考:第 27.4 节 “过滤器”而关于如何指定方向的信息,请参考:第 27.3 节 “枚举选项”。使用 man ls获取更多帮助信息。
27.6.3. 创建节点和关系
你通过关系连接它们到当前节点来创建一个新的节点。比如 mkrel -t A_RELATIONSHIP_TYPE -d OUTGOING -c将创建一个新的节点(-c+)并通过 带有 +OUTGOING方向的 A_RELATIONSHIP_TYPE连接到当前节点。如果你已经有两个节点,你可以这样:+mkrel -t A_RELATIONSHIP_TYPE -d OUTGOING -n <other-node-id>+。它将只会创建关系而不会创建节点。
27.6.4. 设置,重命名和移除属性
属性操作通过 set+, +mv和 rm来完成。这些命令操作当前的节点/关系。 * 带 -t选项的 set <key> <value>用来设置一个属性值。属性值支持Neo4j支持的任何类型的值。比如 int类型:
1 | $ set -t int age 29 |
设置一个 double[]属性的范例:
1 | $ set -t double[] my_values [1.4,12.2,13] |
设置一个包括一个JSON字符串的 String的范例:
1 | mkrel -c -d i -t DOMAIN_OF --np "{'app':'foobar'}" |
- rm <key>移除一个属性。
- mv <key> <new-key>重命名一个已经存在的属性。
27.6.5. 移除节点和关系
删除节点和关系通过命令 rmnode和 rmrel来完成。
rmnode能删除节点,如果被删除的节点还有关系,你也可以通过附加选项 -f 来强制删除。 rmrel能删除关系,它始终保证图中的关联性,但页可以通过 -f 选项来强制删除。 rmrel也能删除正被删除关系相连的节点,当然这个关联的节点么可以任何关系,查看选项 -d 了解细节。
27.6.6. 环境变量
shell使用环境变量 a-la bash来保存会话信息,比如当前的路径等等。这个命令模仿了bash命令 export和 env+。比如,你能正任何时候执行一个 +export STACKTRACES=true+命令来设置 +STACKTRACES+环境变量为 +true+。这让一个异常或者错误发生后,堆栈可以被打印出来。使用 +env列举环境变量。
27.6.7. 执行 groovy/python 脚本
shell是支持执行脚本的,比如 Groovy和 Python(通过 Jython)。脚本(*.groovy, *.py)必须保存在服务器上,我们通过客户端调用,比如: gsh --renamePerson 1234 "Mathias" "Mattias" --doSomethingElse,脚本renamePerson.groovy和doSomethingElse.groovy必须在服务端存在于通过环境变量 GSH_PATH指定的目录(默认是在 .:src:src/script)。变量跟java类路径一样,通过 :分割,然而脚本有 .py扩展名而路径的环境名是 +JSH_PATH+。
当书写脚本时,变量 args(一个String[])是可以使用的,并包括里面支持的参数。在上面的 renamePerson的范例的情况中,数组会包括 ["1234", "Mathias", "Mattias"]+。也请你将输出结果指定给变量 +out+,比如 +out.println( "My tracing text" )会在客户端打印结果而不是在服务端。
27.6.8. 遍历查询
允许你通过使用命令 trav从当前的节点进行遍历查询。你能提供关系类型(可以使用正则匹配),方向以及属性过滤器来匹配节点。另外,你能提供一个命令行来执行每一次匹配。比如:trav -o depth -r KNOWS:both,HAS_.*:incoming -c "ls $n"+。表示查询条件是:深度优先,关系类型是 +KNOWS+但不考虑方向,有输入方向的关系 +HAS_.\*+并且为每一个匹配的节点执行命令: +ls <matching node>+。节点过滤器页支持 +-f选项,请参考:第 27.4 节 “过滤器”。了解查询顺序选项,请参考:第 27.3 节 “枚举选项”。甚至是关系类型/方向都可以通过相同的格式作为过滤器存在。
27.6.9. 通过Cypher查询
你能使用Cypher查询数据库,请使用命令: +start+。
提示 | |
Cypher查询需要一个 ;作为结尾符号。 |
- start n = (0) return n;将给你一个ID=0的节点列表
27.6.10. 索引
通过索引命令是能查询和维护索引的。比如:index -i persons name(将在索引"persons"中索引当前节点或者关系的名称)。
- -g将在索引中进行精确查询并且显示结果。你能使用 -c带一个命令为每一个结果执行一次命令。
- -q将请求一个索引,查询并且显示结果。你能使用 -c带一个命令为每一个结果执行一次命令。
- --cd将改变当前位置到查询到的位置。它只是适用于使用 -c选项。
- --ls会为每一个结果查询内容列表。它只适用于使用 -c选项。
- -i将为当前节点/关系在一个索引中创建一个key-value对。如果没有给予属性值,当前节点将作为一个值。
- -r将为当前节点/关系在一个索引中移除一个key-value对。 键和值是可选的。
- -t将设置工作的索引类型,比如:`index -t Relationship --delete friends`将删除 friends关系的索引。
27.6.11. 事务
能尝试修改,然后能提交并且在修改失败后能回滚是非常有用的。
事务是可以被嵌套的。在一个嵌套的事务里面,除了顶层事务以外,一个提交是不能写任何东西在磁盘上的。然而,一个回滚是不管事务的层级的。它将回滚所有打开的事务。
- begin transaction启动一个事务。
- commit提交一个事务。
- rollback回滚所有打开的事务。
27.7. 扩展Shell: 增加你自己的命令
shell当然是可以扩展的并且有一个没有功能的通用的核心… 只有 命令中的一些可以使用。
所以,你说你想开始一个Neo4j 图数据库,打开远程shell开关并且增加你自己的应用到里面以至于你的应用和标准Neo4j应用共同存在,这儿是一个范例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | importorg.neo4j.helpers.Service; importorg.neo4j.shell.kernel.apps.GraphDatabaseApp; @Service.Implementation( App.class) publicclassLsRelTypes extendsGraphDatabaseApp { @Override protectedString exec( AppCommandParser parser, Session session, Output out ) throwsShellException, RemoteException { GraphDatabaseService graphDb = getServer().getDb(); out.println( "Types:"); for( RelationshipType type : graphDb.getRelationshipTypes() ) { out.println( type.name() ); } returnnull; } } |
而你现在能在shell里面输入 lsreltypes(它的名字是基于类名的)来使用它们,当然要求 getName没有被重载。
如果你想正使用命令 help的时候显示一些更友好的信息,重载 getDescription方法并使用 +addValueType+方法增加你在你的应用中支持的选项的描述。
要知道应用是运行在服务端所以你你有一个正在允许的服务器而你从另外一个JVM启动的一个远程客户端的话,你是不能增加你的应用到客户端的。
27.8. 一个Shell会话范例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | # 我们在那儿? neo4j-sh (0)$ pwd 当前在:(0) (0) # 在当前节点,设置属性“name"的值为"Jon" neo4j-sh (0)$ setname "Jon" # 发送一个cypher查询 neo4j-sh (Jon,0)$ start n=node(0) returnn; +---------------------+ | n | +---------------------+ | Node[0]{name:"Jon"} | +---------------------+ 1 row 0 ms # 创建一个类型为LIKES的输入关系,并且创建关系的终点节点 neo4j-sh (Jon,0)$ mkrel -c -d i -t LIKES --np "{'app':'foobar'}" # 我们在那儿? neo4j-sh (Jon,0)$ ls *name =[Jon] (me)<-[:LIKES]-(1) # 切换到新创建的节点 neo4j-sh (Jon,0)$ cd1 # 列举关系包括关系的Id neo4j-sh (1)$ ls-avr (me)-[:LIKES,0]->(Jon,0) # 创建不止一个关系KNOWS以及它的终点节点 neo4j-sh (1)$ mkrel -c -d i -t KNOWS --np "{'name':'Bob'}" # 输出当前位置 neo4j-sh (1)$ pwd Current is (1) (Jon,0)-->(1) # 列举关系 neo4j-sh (1)$ ls-avr (me)-[:LIKES,0]->(Jon,0) (me)<-[:KNOWS,1]-(Bob,2) |
27.9. 黑客帝国范例
这个范例通过shel创建了在黑客帝国中的人物的图数据库,然后执行Cypher来查询数据:
图 27.1. 基于Shell的黑客帝国范例
Neo4j是配置成自动索引的,在Neo4j配置文件中如下:
1 2 3 4 5 | node_auto_indexing=true node_keys_indexable=name,age relationship_auto_indexing=true relationship_keys_indexable=ROOT,KNOWS,CODED_BY |
下面的范例展示了如何通过Shell会话创建黑客帝国的图数据库并从查询数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | # 创建 Thomas Andersson 节点 neo4j-sh (0)$ mkrel -t ROOT -c -v Node (1) created Relationship [:ROOT,0] created # 切换到新节点 neo4j-sh (0)$ cd1 # 设置节点属性:name neo4j-sh (1)$ setname "Thomas Andersson" # 创建 Thomas直接的朋友 neo4j-sh (Thomas Andersson,1)$ mkrel -t KNOWS -cv Node (2) created Relationship [:KNOWS,1] created # 切换到新节点 neo4j-sh (Thomas Andersson,1)$ cd2 # 设置节点属性:name neo4j-sh (2)$ setname "Trinity" # 返回上级 neo4j-sh (Trinity,2)$ cd.. # 创建Thomas直接的朋友 neo4j-sh (Thomas Andersson,1)$ mkrel -t KNOWS -cv Node (3) created Relationship [:KNOWS,2] created # 切换到新节点 neo4j-sh (Thomas Andersson,1)$ cd3 # 设置节点属性:name neo4j-sh (3)$ setname "Morpheus" # 创建到Trinity的关系 neo4j-sh (Morpheus,3)$ mkrel -t KNOWS 2 # 列出节点3的关系 neo4j-sh (Morpheus,3)$ ls-rv (me)-[:KNOWS,3]->(Trinity,2) (me)<-[:KNOWS,2]-(Thomas Andersson,1) # 切换当前位置到关系#2 neo4j-sh (Morpheus,3)$ cd-r 2 # 设置关系的属性:age neo4j-sh [:KNOWS,2]$ set-t int age 3 # 回到Morpheus neo4j-sh [:KNOWS,2]$ cd.. # 回到下一个关系 neo4j-sh (Morpheus,3)$ cd-r 3 # 设置关系的属性:age neo4j-sh [:KNOWS,3]$ set-t int age 90 # 切换当前位置到当前关系的开始节点处 neo4j-sh [:KNOWS,3]$ cdstart # 创建新节点 neo4j-sh (Morpheus,3)$ mkrel -t KNOWS -c # 列出当前节点的所有关系 neo4j-sh (Morpheus,3)$ ls-r (me)-[:KNOWS]->(Trinity,2) (me)-[:KNOWS]->(4) (me)<-[:KNOWS]-(Thomas Andersson,1) # 切换到Cypher neo4j-sh (Morpheus,3)$ cd4 # 设置属性:name neo4j-sh (4)$ setname Cypher # 从Cypher处创建新节点 neo4j-sh (Cypher,4)$ mkrel -ct KNOWS # 列出关系 neo4j-sh (Cypher,4)$ ls-r (me)-[:KNOWS]->(5) (me)<-[:KNOWS]-(Morpheus,3) # 切换到Agent Smith节点 neo4j-sh (Cypher,4)$ cd5 # 设置节点属性:name neo4j-sh (5)$ setname "Agent Smith" # 创建输出关系和新节点 neo4j-sh (Agent Smith,5)$ mkrel -cvt CODED_BY Node (6) created Relationship [:CODED_BY,6] created # 跳到这 neo4j-sh (Agent Smith,5)$ cd6 # 设置节点属性:name neo4j-sh (6)$ setname "The Architect" # 跳回第一个节点处 neo4j-sh (The Architect,6)$ cd Morpheus的朋友, 通过Neo4j自动生成的索引name查询Morpheus neo4j-sh (0)$ start morpheus = node:node_auto_index(name='Morpheus') match morpheus-[:KNOWS]-zionist returnzionist.name; +--------------------+ | zionist.name | +--------------------+ | "Trinity"| | "Cypher"| | "Thomas Andersson"| +--------------------+ 3 rows 19 ms # Morpheus的朋友, 通过Neo4j自动生成的索引name查询Morpheus neo4j-sh (0)$ cypher 1.6 start morpheus = node:node_auto_index(name='Morpheus') match morpheus-[:KNOWS]-zionist returnzionist.name; +--------------------+ | zionist.name | +--------------------+ | "Trinity"| | "Cypher"| | "Thomas Andersson"| +--------------------+ 3 rows 1 ms |
部分 VI. 社区
Neo4j项目有一个非常强大的社区。阅读下面的信息了解如何从社区获取帮助和如何为社区做贡献。