最近在处理一些图的数据,主要是有向图,如果图的节点不是特别大可以直接加载到内存里来处理,但是当图的节点个数特别大时,内存就放不下了;我 们牵涉到的图的节点数最大可以达到数亿个节点,已经超出的机器内存的大小,所以必须把这些图的数据放到外存上,所以我们就选择了图数据库。

   尝试了2种图数据库,IBM System G 和 neo4j, 这两个数据库都可以处理上亿个节点的图,起始使用的是System G,但是存在一些问题,当图的节点数在300多万个,边数为1000多万个时,在创建图时就特别麻烦,程序老是创建不成功。后来就选择了 neo4j,neo4j是一个开源的图数据库,使用起来也比较方便,在创建比较大的图时速度远远超过System G;接下来把neo4j入门的知识记录下来,主要介绍neo4j嵌入在java开发中。

1、创建图(把图的数据存入neo4j)

  创建图由两种方法,一种是直接通过读取文件,在程序中显式的创建节点和边,另一种是通过加载CSV文件来创建。

1.1 程序中显示的创建图

  存放图的文件的格式如下图,以'v'开图的是顶点,后面的数字是它的id,id用从0开始顺序存放,在后面是label; 以'e'开头的行是边,后面第一个数字是边的起始点的id,第二个数字是边的终点的id,后面的字符串是边的label。

  

  创建图的方法如下:

  

 public static void create_graph(GraphDatabaseService graph, File f) throws FileNotFoundException{
Scanner scanner = new Scanner(f); while (scanner.hasNextLine()){
String line = scanner.nextLine().trim(); if (line.equals("") | line.startsWith("t")){
continue;
} else if (line.startsWith("v")) {
String nodeLabel = line.split(" ")[2]; //得到顶点的label
Label label = DynamicLabel.label(nodeLabel); //通过顶点的label,创建一个neo4j的Label类型,作为顶点的label, 这样就不用把label作为属性
try (Transaction tx = graph.beginTx()){
graph.createNode(label); //创建顶点
tx.success();
}
} else if (line.startsWith("e")) {
String[] lineSplit = line.split(" ");
int sourceId = Integer.parseInt(lineSplit[1]); //得到变得起始顶点id和终止顶点id
int targetId = Integer.parseInt(lineSplit[2]);
String edgeLabel = lineSplit[3]; //得到边的label
try (Transaction tx = graph.beginTx()){
Relationship edge = graph.getNodeById(sourceId).createRelationshipTo(graph.getNodeById(targetId), R.DIRECTED); //创建边
edge.setProperty("label", edgeLabel); //给边设置属性
tx.success();
}
}
} scanner.close();
}

1.2 通过加载CSV文件来创建图

  如果使用CSV文件的话,需要通过URL来访问文件,我们使用两个URL,一个是顶点的URL,一个是边的URL,它们的文件格式要符合csv文件的格式.

  可以创建一个本地的apache服务器来存放这些文件,我们使用的顶点和边的url分别是:

  顶点url: http://127.0.0.1/nodes

  边url:  http://127.0.0.1/edges

然后存取顶点的代码如下:

 String create_node = "USING PERIODIC COMMIT "
+ "LOAD CSV WITH HEADERS FROM 'http://127.0.0.1/nodes' AS line "
  + "CREATE (:node {label: line.label});";      //这样创建时,不能像上一种方法那样通过变量来指定label, 所以把label作为了顶点的属性了,第一个冒号前面可以指定顶点的名字,也可以不指定,冒号后面是该顶点的label.
graph.execute(create_node);    //执行cypher语言来创建结点

其中"USING PERIODIC COMMIT"的作用是分段式的创建顶点,可以认为指定读取多少行后就写入数据库,默认是读取1000行后写入数据库,例如"USING PERIODIC COMMIT 500",就是读取500行后就存入数据库.

存放边的代码如下:

 String create_edge = "USING PERIODIC COMMIT "
+ "LOAD CSV WITH HEADERS FROM 'http://127.0.0.1/edges' AS line "
+ "MATCH (p1), (p2) "    //找到边的两个顶点
+ "WHERE id(p1)=toInt(line.source) and id(p2)=toInt(line.target) "
+ "CREATE (p1)-[:DIRECTED {label: line.label}]->(p2);"; //创建边
graph.execute(create_edge);

其中,需要注意的是带有"USING PERIODIC COMMIT "的语句不能放在Transaction中执行,否则会出现如下的错误

“org.neo4j.cypher.PeriodicCommitInOpenTransactionException: Executing queries that use periodic commit in an open transaction is not possible.”

完整的创建顶点和边的方法如下:

 public static void create_nodes(GraphDatabaseService graph, String node_url) {        //创建顶点
String create_node = "USING PERIODIC COMMIT "
+ "LOAD CSV WITH HEADERS FROM " + node_url + "AS line "
+ "CREATE (:node {label: line.label});";
graph.execute(create_node);
System.out.println("nodes create successfully!");
}
//创建边
public static void create_edges(GraphDatabaseService graph, String edge_url){ String create_edge = "USING PERIODIC COMMIT "
+ "LOAD CSV WITH HEADERS FROM " + edge_url + " AS line "
+ "MATCH (p1), (p2) "
+ "WHERE id(p1)=toInt(line.source) and id(p2)=toInt(line.target) "
+ "CREATE (p1)-[:DIRECTED {label: line.label}]->(p2);";
graph.execute(create_edge); System.out.println("edges create successfully!");
}

2.得到一个顶点的所有出边的终点的id

 public static ArrayList<Long> get_out_nodes(GraphDatabaseService graph, Node node){
ArrayList<Long> out = new ArrayList<Long>();
try (Transaction tx = graph.beginTx()){
Traverser tr;
TraversalDescription td = graph.traversalDescription()
.breadthFirst()
.relationships(R.DIRECTED, Direction.OUTGOING)
.evaluator(Evaluators.excludeStartPosition());
tr = td.traverse(node);
for (Path path : tr){
if (path.length() == 1){
out.add(path.endNode().getId());
}
}
tx.success();
}
return out;
}

3.得到一个顶点的所有入边的起始点的id

  

  public static ArrayList<Long> get_in_nodes(GraphDatabaseService graph, Node node){
ArrayList<Long> in = new ArrayList<Long>();
try (Transaction tx = graph.beginTx()){
Traverser tr;
TraversalDescription td = graph.traversalDescription()
.breadthFirst()
.relationships(R.DIRECTED, Direction.INCOMING)
.evaluator(Evaluators.excludeStartPosition());
tr = td.traverse(node);
for (Path path : tr){
if (path.length() == 1){
in.add(path.endNode().getId());
}
}
tx.success();
}
return in;
}

4.得到图中所有顶点的个数

 public static int getSize(GraphDatabaseService graph){
int size = 0;
try (Transaction tx = graph.beginTx()){
Iterator<Node> it = graph.getAllNodes().iterator();
while(it.hasNext()){
size++;
it.next();
}
tx.success();
}
return size;
}

5.根据顶点的属性label的值,得到具有相同label值的顶点的个数

  public static int getSizeByLabel(GraphDatabaseService graph, String label){
try(Transaction tx = graph.beginTx()){
Label node = DynamicLabel.label("node"); //在创建顶点时,指定了顶点的label为"node",注意这个label是Label类型的,与顶点属性的label不一样
ResourceIterator<Node> result = graph.findNodes(node, "label", label);
ArrayList<Node> nodes = new ArrayList<>();
while (result.hasNext()){
nodes.add(result.next());
}
tx.success();
return nodes.size();
}
}

6. 给出顶点的id,得到该顶点某个属性的值,如label属性的值

 public static String getNodeLabel(GraphDatabaseService graph, int id){
try(Transaction tx = graph.beginTx()){
String nodeLabel = graph.getNodeById(id).getProperties("label").toString();    //返回的值的样式如下:{label=AND2X1}
String label = nodeLabel.substring(7, nodeLabel.length()-1);      //对上一步的返回值进行取子串
tx.success();
return label;
}
}

就先介绍这些基本的操作吧,以后用到新的操作了在做补充!

参考链接入下:

neo4j官方教程 

Neo4j图数据库使用的更多相关文章

  1. Neo4j图数据库管理系统开发笔记之一:Neo4j Java 工具包

    1 应用开发概述 基于数据传输效率以及接口自定义等特殊性需求,我们暂时放弃使用Neo4j服务器版本,而是在Neo4j嵌入式版本的基础上进行一些封装性的开发.封装的重点,是解决Neo4j嵌入式版本Emb ...

  2. Neo4j资料 Neo4j教程 Neo4j视频教程 Neo4j 图数据库视频教程

    课程发布地址 地址: 腾讯课堂<Neo4j 图数据库视频教程> https://ke.qq.com/course/327374?tuin=442d3e14 作者 庞国明,<Neo4j ...

  3. Neo4j视频教程 Neo4j 图数据库视频教程

    课程名称 课程发布地址 地址: 腾讯课堂<Neo4j 图数据库视频教程> https://ke.qq.com/course/327374?tuin=442d3e14 作者 庞国明,< ...

  4. Ubuntu16.04下Neo4j图数据库官网安装部署步骤(图文详解)(博主推荐)

    不多说,直接上干货! 说在前面的话  首先,查看下你的操作系统的版本. root@zhouls-virtual-machine:~# cat /etc/issue Ubuntu LTS \n \l r ...

  5. Ubuntu14.04下Neo4j图数据库官网安装部署步骤(图文详解)(博主推荐)

    不多说,直接上干货! 说在前面的话  首先,查看下你的操作系统的版本. root@zhouls-virtual-machine:~# cat /etc/issue Ubuntu 14.04.4 LTS ...

  6. Neo4j教程 Neo4j视频教程 Neo4j 图数据库视频教程

    课程发布地址 地址: 腾讯课堂<Neo4j 图数据库视频教程> https://ke.qq.com/course/327374?tuin=442d3e14 作者 庞国明,<Neo4j ...

  7. Neo4j图数据库从入门到精通

    目录 第一章:介绍 Neo4j是什么 Neo4j的特点 Neo4j的优点 第二章:安装 1.环境 2.下载 3.开启远程访问 4.启动 第三章:CQL 1.CQL简介 2.Neo4j CQL命令/条款 ...

  8. Neo4j图数据库从入门到精通(转)

    add by zhj: 转载时,目录没整理好,还会跳转到原文 其实RDB也可以存储多对多的关系,使用的是中间表,GDB使用的是边,RDB中的实体存储在数据表,而GDB存储在节点.两者使用的底层技术不同 ...

  9. 使用neo4j图数据库的import工具导入数据 -方法和注意事项

    背景 最近我在尝试存储知识图谱的过程中,接触到了Neo4j图数据库,这里我摘取了一段Neo4j的简介: Neo4j是一个高性能的,NOSQL图形数据库,它将结构化数据存储在网络上而不是表中.它是一个嵌 ...

  10. NEO4J 图数据库使用APOC数据导入

       Neo4j 数据导入 一.安装与部署 直接在官网下载安装包安装,解压即可. 二.下载相应的jar包 apoc 包下载链接: https://github.com/neo4j-contrib/ne ...

随机推荐

  1. [Luogu]A%BProblem——线性筛素数与前缀和

    题目描述 题目背景 题目名称是吸引你点进来的[你怎么知道的] 实际上该题还是很水的[有种不祥的预感..] 题目描述 区间质数个数 输入输出格式 输入格式: 一行两个整数 询问次数n,范围m接下来n行, ...

  2. Flask最强攻略 - 跟DragonFire学Flask - 第十四篇 Flask-SQLAlchemy

    前不久刚刚认识过了SQLAlchemy,点击这里复习一下 当 Flask 与 SQLAlchemy 发生火花会怎么样呢? Flask-SQLAlchemy就这么诞生了 首先要先安装一下Flask-SQ ...

  3. Android项目开发第二天,关于GitHub

    一. 今天在网上学习了如何使用GitHub,了解了GitHub是干什么的. 作为开源代码库以及版本控制系统,Github拥有超过900万开发者用户.随着越来越多的应用程序转移到了云上,Github已经 ...

  4. Eclipse中Tomcat v8.0 Server at localhost右键选择Properties详情页中Server Locations变灰无法编辑

    Eclipse中Tomcat v8.0 Server at localhost右键选择Properties详情页中Server Locations变灰无法编辑解决办法:1.首先将Servers中部署的 ...

  5. java 43 接口

  6. BIOS备忘录之x86硬件编程(寄存器与IO)

    SOC固件(BIOS)开发: 1.熟悉硬件原理图:要弄清楚pin脚的功能: 2.配置GPIO引脚,配置成Native功能还是GPIO功能(如果是配置成GPIO,需要在code里面显式的使用): 3.硬 ...

  7. Docker Swarm 创建overlay网络

    Docker Swarm 创建overlay网络 环境: 系统:Centos 7.4 x64 应用版本:Docker 18.09.0 管理节点:192.168.1.79 工作节点:192.168.1. ...

  8. ABAP 中的搜索帮助

    ABAP 中的搜索帮助 https://blog.csdn.net/u011576750/article/details/50999078 一.简介:在abap中,用到的搜索帮助个人遇到的情况如下,进 ...

  9. 掌握闭包closure (含义及优缺点)

    个人认为闭包其实非常好理解,我们一起去认识什么是闭包. 在javascript脚本语言中,变量的作用域只有两种,一种是全局变量,一种是局部变量. 全局变量的函数可以在整个javascript脚本语言中 ...

  10. 廖雪峰JavaScript学习笔记(基础及数据类型、变量)

    先睹为快 alert('我要学JavaScript!'); Run: 基本语法: 1.每个语句以;结束,不强制 2.语句块用{...} 3.//单行注释,/*...*/ 多行注释 数据类型: 1.不区 ...