NOSQL——Neo4j
近几年互联网大数据的不断发展导致了各种DBMS的发展,除了传统的RDBMS(关系型DBMS),NOSQL发展也较迅速,最著名的是文本型数据库Mongodb,今天介绍的是一种基于图的NOSQL——Neo4j。适合一些图型数据(如下图)的存储,比如社交关系网络等。
从官网上可以获得更详细的介绍和下载,下载分三个版本——社区版(Community)、高级版(Advanced)和企业版(Enterprise),一般个人使用Community Edition就可以了,或者可以使用Advanced Edition,不过常用的功能都是一样的。建议选择1.9M02版本以后的,因为对数据查询进行了优化。执行效率更好点。
下载后解压缩到某目录下,配置系统的环境变量。类似Java,添加
之后在命令行里安装服务,将Neo4j作为系统的一个服务部署。一般安装的同时也会启动数据库。如下所示:
运行成功后即可进行各项操作。如果失败,一般是系统权限问题,可以尝试用管理员权限运行。
Neo4j的存储主要分为两种,一种是内嵌在项目中的。还有一种是服务器端配置的。项目内嵌偏重小型个人项目,而服务端的则是可以构建稍大规模的项目甚至生产级的项目。
至于逻辑存储方式,neo4j采用文件存储,整个数据库是由多个文件组成,包括数据、索引等。值得一提的是Neo4j采用lucene作为索引引擎,在索引效率上还算不错。
不过需要补充的是,不大清楚Neo4j在分布式存储方面的可用性如何,这方面我还没怎么深入,如果可以部署到分布式存储环境的话,那更好了。
类似于RDBMS的SQL语言,Neo4j也有独立的数据库查询语言——Cypher,其实看过黑客帝国的人应该熟悉,这里各个术语基本都和黑客帝国里的角色相关,或许这也是设计者的初衷。计算机网络其实就是一张巨大的拓扑图结构。
在配置Neo4j服务成功后,可以通过命令行打开Cypher查询界面,命令行中输入命令 Neo4jShell即可,如下所示:
具体到相关的语言特征,和传统的SQL类似,但是增加了不少图的元素。可以输入help查看相关信息,或者访问官方文档,有几个典型的查询:
一般以start命令开始,例如,查看当前Node数:
这里有几个典型的cypher句法,START 关键字用于表征从某个指定点开始,好比在一张网中确定入口点。 node(*) 表示从所有点,如果指定了点的ID的话需要改成node(0)等,事实上,在Neo4j中新建点的时候的都会自动设置一个独特的Id作为其唯一标识符。RETURN 返回结果,COUNT 则是Cypher的内置函数,还有SUM等。这些都可以在官方主页上查到。
返回的结果以列数据的形式展示,第一行是Column的名字,即return 语句后的指定值。接下来是结果,这里是COUNT函数,所以返回的是计数值,如果是点的话,就会返回具体每个点的信息,如下:
在Neo4j中,每个节点或关系的信息以key-value键值对来保存。这算是比较流行的一种方式,在分布式环境或一些NoSql中都会采用这种方式。
遍历是Neo4j一个重要的功能,也是图数据库所具有的优势之一。传统的RDBMS或者一些文档型NoSql中,遍历往往就是简单的join操作后再加上不断的select等操作
或类似操作,但是在图数据库中遍历操作比较形象,因为可以想象在图,包括有向图和无向图中的遍历,这其实和数据结构中图操作类似,而且Cypher语言中,将
遍历也展示很形象。例如:
这是有向图的遍历,再如:
这又是无向图的遍历。
PS:开始先创建了这个简单的图关系:如下:
可以看出,首先,Cypher语言的易于理解性,包括match,where等关键字的使用。一般都可以看懂遍历的意思,不像其他的SQL遍历语句。
其次,遍历返回的结果展示也是类似图的展示,包括开始节点,中间结点和节点与节点之间的关系。比较形象。
更令人兴奋的是,在Neo4j中可以运用那些经典的图算法,最短路径算法,如Dijkstra算法,Ford算法等。这些都是Neo4j内置的算法。利用这些算法,可以在较大
规模的图中快速高效得到指定点的最短路径,这些在社交网络数据的分析中比较有用。
之前介绍的主要是针对Neo4j本省的操作,事实上,如果需要在应用中使用Neo4j的话,我们就需要其提供的接口,Neo4j主要提供了两种接口,一种是内嵌式
(Embeded)数据库接口,这个主要用于小型个人的应用,利用Java操作。还有一种是比较共用的,利用REST API接口,作为主要的Web服务接口之一,
REST API的更多介绍可以点击这里
Neo4j采用REST API,其默认端口是7474,我们可以在浏览器里输入 http://localhost:7474,得到界面是Neo4j控制台,当然,这个和下面用到的REST API没太大关系,
就是让Neo4j看起来比较人机交互点。
Neo4j 有很多版本的REST API实现,基本覆盖主流语言,常用的有Java,Python等。具体可以参考这里。
下面就以Java为例,看一下具体的一些使用。
这是连接方法:
private final static String ROOT_URI="http://localhost:7474/db/data";
private static WebResource resource;
private static ClientResponse response;
private static void Connection(){
resource=Client.create().resource(ROOT_URI);
response=resource.get(ClientResponse.class);
System.out.println(response.toString());
if(response.getStatus()==200){
System.out.println("Connected Now...");
}else{
System.out.println("Not Connected!!");
}
}
然后是一些应用,例如,获得所有Node数据:
public static boolean IsConnected(){
resource=Client.create().resource(ROOT_URI);
response=resource.get(ClientResponse.class);
if(response.getStatus()==200){
response.close();
return true;
}else{
response.close();
return false;
}
}
public static void GetAllNodes(){
if(IsConnected()){
String post_uri=ROOT_URI+"cypher";
String CypherQuery="START n=node(*) return n";
String queryJson="{\"query\":\""+CypherQuery+"\","+
"\"param\":{}}"; //这里比较难看,就是简单的Json拼凑,可以提出到单独的方法中
resource=Client.create().resource(post_uri);
response=resource.accept(MediaType.APPLICATION_JSON)
.type(MediaType.APPLICATION_JSON)
.entity(queryJson)
.post(ClientResponse.class);
if(response.getStatus()==200){
System.out.println("Status OK");
System.out.println(response.getEntity(String.class));
}else{
System.out.println("ERROR "+response.getStatus()+"\n"+response.getEntity(String.class));
}
}else{
System.out.println("Connection Refused...");
System.exit(0);
}
}
返回的节点数据是Json格式,具体怎么解析Json想必大家都有办法,这是返回的部分数据,可以看一下:
[ {
"outgoing_relationships" : "http://localhost:7474/db/data/node/1/relationships/out",
"data" : {
"name" : "text"
},
"traverse" : "http://localhost:7474/db/data/node/1/traverse/{returnType}",
"all_typed_relationships" : "http://localhost:7474/db/data/node/1/relationships/all/{-list|&|types}",
"property" : "http://localhost:7474/db/data/node/1/properties/{key}",
"self" : "http://localhost:7474/db/data/node/1",
"properties" : "http://localhost:7474/db/data/node/1/properties",
"outgoing_typed_relationships" : "http://localhost:7474/db/data/node/1/relationships/out/{-list|&|types}",
"incoming_relationships" : "http://localhost:7474/db/data/node/1/relationships/in",
"extensions" : {
},
"create_relationship" : "http://localhost:7474/db/data/node/1/relationships",
"paged_traverse" : "http://localhost:7474/db/data/node/1/paged/traverse/{returnType}{?pageSize,leaseTime}",
"all_relationships" : "http://localhost:7474/db/data/node/1/relationships/all",
"incoming_typed_relationships" : "http://localhost:7474/db/data/node/1/relationships/in/{-list|&|types}"
} ]