Comparing Neo4j driver, py2neo and neo4jrestclient with some basic commands using the Panama Papers Data

RHFollow
May 6, 2017

1. Before we begin

In our last thrilling post, we installed Neo4j and downloaded the Panama Papers Data. Today, before diving into the dirty world of tax evasion, we want to benchmark the performance of 3 Python based modules. Namely Neo4j Python driver, py2neo and neo4jrestclient. If you haven’t done it already, install all of the modules by the following commands.

pip3 install neo4j-driver
pip3 install py2neo
pip3 install neo4jrestclient

Or whatever way you are accustomed to.

2. Loading the database to python

The first step, before doing anything, is to start Neo4j with the Panama papers data. If you forgot how to do this, please refer to our last post or check the “Benchmark.ipynb” in the following repository. It has all the necessary codes to replicate the experiment.

The next step is to load the data so that it is queryable from Python. In py2neo this is done with the following command.

from py2neo import Graph, Node, Relationship
gdb = Graph(user=”neo4j”, password=”YOURPASS")

Similarly in neo4jrestclient.

from neo4jrestclient.client import GraphDatabase
from neo4jrestclient import client
gdb2 = GraphDatabase(“http://localhost:7474", username=”neo4j”, password=”YOURPASS")

Finally in Neo4j Python driver.

from neo4j.v1 import GraphDatabase, basic_auth
driver = GraphDatabase.driver(“bolt://localhost:7687”, auth=basic_auth(“neo4j”, “YOURPASS”))
sess = driver.session()

3. Getting node labels and label-attribute pairs

The first thing we would like to do, when we encounter any new graph database, is to see what node label and relation types are there in the database. So the first thing we would do in our experiment is to get all the distinct node labels and all the associated attributes for each node labels.

In py2neo this is performed with the following code which takes about 100 ms. I am grad to see that py2neo has an built-in object which stores the node label and its attributes.

INPUT CODE py2neo:

# Get Distinct Node Labels
NodeLabel = list(gdb.node_labels)
print(NodeLabel)
# For each node type print attributes
Node = []
Attr = []
for nl in NodeLabel:
for i in gdb.schema.get_indexes(nl):
Node.append(nl)
Attr.append(format(i))
NodeLabelAttribute = pd.DataFrame(
{‘NodeLabel’: Node,’Attribute’: Attr})
NodeLabelAttribute.head(5)

However things get a little bit more nasty with neo4jrestclient and Neo4j Python driver. For neo4jrestclient it does have a way to access the node label but not the attributes. This means that we have to query it from our graph database. Not surprisingly this querying step takes quite a lot of time resulting in about 12sec for neo4jrestclient.

INPUT CODE neo4jrestclient:

# Get Distinct Node Labels
def extract(text):
import re
matches=re.findall(r'\'(.+?)\'',text)
return(",".join(matches))
NodeLabel = [extract(str(x)) for x in list(gdb2.labels)]
print(NodeLabel)
# For each node label print attributes
Node, Attr = ([] for i in range(2))
for nl in NodeLabel:
q = "MATCH (n:" + str(nl) + ")\n" + "RETURN distinct keys(n)"
temp = list(gdb2.query(q))
temp = list(set(sum(sum(temp,[]),[])))
for i in range(len(temp)):
Node.append(nl)
Attr.extend(temp)
NodeLabelAttribute = pd.DataFrame(
{'NodeLabel': Node,'Attribute': Attr})
NodeLabelAttribute.head(5)

For the Neo4j Python driver you have to query the node labels as well resulting in 20 sec.

INPUT CODE Neo4j Python Driver:

q = “””
MATCH (n)
RETURN distinct labels(n)
“””
res = sess.run(q)
NodeLabel = []
for r in res:
temp = r[“labels(n)”]
if temp != “”:
NodeLabel.extend(temp)
NodeLabel = list(filter(None, NodeLabel))
# For each node label print attributes
Node, Attr = ([] for i in range(2))
for nl in NodeLabel:
q = “MATCH (n:” + str(nl) + “)\n” + “RETURN distinct keys(n)”
res = sess.run(q)
temp = []
for r in res:
temp.extend(r[“keys(n)”])
temp2 = list(set(temp))
Attr.extend(temp2)
for i in range(len(temp2)):
Node.append(nl)
NodeLabelAttribute = pd.DataFrame(
{‘NodeLabel’: Node,’Attribute’: Attr})
NodeLabelAttribute.head(5)

4. Relation types and length of each edge list

The next thing we would like to do is make a list of all the relation types in the database and see which relation type has the longest edge list.

In py2neo this could be performed with the following code. This takes about 4min.

# Get Distinct Relation Types
RelaType = sorted(list(gdb.relationship_types))
print("There are " + str(len(RelaType)) + " relations in total")
# Calculate lengh of edge list for each types
res = []
for i in range(len(RelaType)):
#for i in range(10):
q = "MATCH (n)-[:`" + RelaType[i] + "`]-(m)\n" + "RETURN count(n)"
res.append(gdb.data(q)[0]["count(n)"])
RelaType = pd.DataFrame({'RelaType': RelaType[:len(res)],'count(n)': res})
RelaType.head(5)

In neo4jrestclient, the same thing could be implemented by the following command. Note that again, since we do not have a built-in method to get distinct relation types in neo4jrestclient, we have to query it from our graph database first. In total this takes about 4min 21s so it’s slightly slower than py2neo.

INPUT CODE neo4jrestclient:

# Get Distinct Relations
q = “””
START r =rel(*)
RETURN distinct(type(r))
“””
RelaType = sorted(sum(list(gdb2.query(q)),[]))
print(“There are “ + str(len(RelaType)) + “ relations in total”)
res = []
for i in range(len(RelaType)):
q = “MATCH (n)-[:`” + RelaType[i] + “`]-(m)\n” + “RETURN count(n)”
res.append(gdb2.query(q)[0][0])
RelaType = pd.DataFrame({‘RelaType’: RelaType,’count(n)’: res})
RelaType

Things get even more tedious in Neo4j Python driver where we have to query the Relation Types as well. However according to the The following code it takes about 4 min 10 sec so the additional query of getting the list of relation types didn’t seem to hurt much.

INPUT CODE Neo4j Python Driver:

# Get Distinct Relations
q = “””
START r =rel(*)
RETURN distinct(type(r))
“””
RelaType = []
res = sess.run(q)
for r in res:
RelaType.append(r[“(type(r))”])
RelaType = sorted(RelaType)
print(“There are “ + str(len(RelaType)) + “ relations in total”)
res2 = []
for i in range(len(RelaType)):
#for i in range(10):
q = “MATCH (n)-[:`” + RelaType[i] + “`]-(m)\n” + “RETURN count(n)”
res = sess.run(q)
for r in res:
res2.append(r[“count(n)”])
RelaType = pd.DataFrame({‘RelaType’: RelaType[:len(res2)],’count(n)’: res2})
RelaType.head(5)

5. Calculate degree distribution of all nodes

So far so good. My first impression, before ever touching the three modules, was that py2neo is the more updated cool stuff. So it was good to see that py2neo was more user-friendly as well as well-performing. But as the following example shows, there seems to be situation where neo4jrestclient and Neo4j Python driver are much faster than py2neo.

In this experiment we would gather information concerning the degree distribution of all nodes in our graph database. In py2neo this could be performed with the following code. This take about 1min 14s.

INPUT CODE py2neo:

q = """
MATCH (n)-[r]-(m)
RETURN n.node_id,n.name, count(r)
ORDER BY count(r) desc
"""
res = gdb.data(q)
NodeDegree = pd.DataFrame(res)
NodeDegree.head(5)

OUTPUT

count(r) n.name n.node_id
0 37338 None 236724
1 36374 Portcullis TrustNet (BVI) Limited 54662
2 14902 MOSSACK FONSECA & CO. (BAHAMAS) LIMITED 23000136
3 9719 UBS TRUSTEES (BAHAMAS) LTD. 23000147
4 8302 CREDIT SUISSE TRUST LIMITED 23000330

In neo4jrestclient the same thing could be performed with the following code. Now this takes about 18 sec which is about 4 times faster than py2neo!

INPUT CODE neo4jrestclient:

q = """
MATCH (n)-[r]-(m)
RETURN n.node_id, n.name, count(r)
ORDER BY count(r) desc
"""
res = list(gdb2.query(q))
NodeDegree = pd.DataFrame(res)
NodeDegree.columns = ["n.node_id","n.name","count(r)"]
NodeDegree.head(5)

Same results holds for Neo4j Python driver which take about 25 sec.

INPUT CODE Neo4j Python Driver:

Match = “MATCH (n)-[r]-(m)\n”
Ret = [“n.node_id”,”n.name”,”count(r)”]
Opt = “ORDER BY count(r) desc”
q = Match + “RETURN “ + ‘, ‘.join(Ret) + “\n” + Opt
res = sess.run(q)
res2 = []
for r in res:
#for r in islice(res,5):
res2.append([r[x] for x in range(len(Ret))])
NodeDegree = pd.DataFrame(res2)
NodeDegree.columns = Ret
NodeDegree.head(5)

6. Conclusion

At the moment I am not sure where the difference comes from. Besides some cases where there is a built-in object which preserves some basic information, we are using exactly the same query and I think there shouldn’t be much difference in it.

For the positive side, as this post shows there aren’t much difference in the coding style among the three modules. After all we are using the same query language (i.e. Cypher) to send orders to Neo4j and it is not a pain in the ass to switch from one module to another.

My recommendation? Definitely py2no is not an option. Although it is user-friendly in many respects, it is too slow for counting queries. Neo4jrestclient is not bad, but sometimes it returns nested list structure which we have to deal with using some trick (e.g. “sum(temp,[])” which I want to avoid. So I think I would go with the Neo4j Python driver. After all it is the only official release supported by Neo4j. What is your recommendation?

 

转:对比python 链接 neo4j 驱动,py2neo 和 neo4j-driver 和 neo4jrestclient的更多相关文章

  1. 基于Spark环境对比Python和Scala语言利弊

    在数据挖掘中,Python和Scala语言都是极受欢迎的,本文总结两种语言在Spark环境各自特点. 本文翻译自  https://www.dezyre.com/article/Scala-vs-Py ...

  2. 实现Redis Cluster并实现Python链接集群

    目录 一.Redis Cluster简单介绍 二.背景 三.环境准备 3.1 主机环境 3.2 主机规划 四.部署Redis 4.1 安装Redis软件 4.2 编辑Redis配置文件 4.3 启动R ...

  3. python链接oracle数据库以及数据库的增删改查实例

    初次使用python链接oracle,所以想记录下我遇到的问题,便于向我这样初次尝试的朋友能够快速的配置好环境进入开发环节. 1.首先,python链接oracle数据库需要配置好环境. 我的相关环境 ...

  4. Python学习第二十六课——PyMySql(python 链接数据库)

    Python 链接数据库: 需要先安装pymysql 包 可以设置中安装,也可以pip install pymysql 安装 加载驱动: import pymysql # 需要先安装pymysql 包 ...

  5. python学习道路(day12note)(mysql操作,python链接mysql,redis)

    1,针对mysql操作 SET PASSWORD FOR 'root'@'localhost' = PASSWORD('newpass'); 设置密码 update user set password ...

  6. python链接MySQLdb报错:2003

    使用python链接Mysql数据库操作,遇到问题! 问题如图所示: 解决方法:将"localhost"改为"127.0.0.1" db=MySQLdb.con ...

  7. python链接mysql

    1.安装MySQLdb MySQLdb 是用于Python链接Mysql数据库的接口,它实现了 Python 数据库 API 规范 V2.0,基于 MySQL C API 上建立的. 下载地址: ht ...

  8. Python来袭,教你用Neo4j构建“复联4”人物关系图谱!

    来源商业新知网,原标题:Python来袭,教你用Neo4j构建“复联4”人物关系图谱!没有剧透! 复仇者联盟 之绝对不剧透 漫威英雄们为了不让自己剧透也是使出了浑身解数.在洛杉矶全球首映礼上记者费尽心 ...

  9. gcc 找不到 boot python 链接库的问题: /usr/bin/ld: cannot find -lboost_python

    问题: Ubuntu 14.04,gcc 4.8.4,以默认方式编译 boost 1.67 后,使用 Boost.Python 时,gcc 提示找不到 boost python 链接库. 方案: 查看 ...

随机推荐

  1. mycat分片规则之分片枚举(sharding-by-intinfile)

    mycat分片规则之分片枚举(sharding-by-intinfile) http://blog.51cto.com/goome/2058959 mycat安装及分片初体验 https://blog ...

  2. DB2 触发器使用1

    本文基于多篇博文整理而来,目的是较全面的学会使用DB2触发器,后期再整理复杂的使用场景,看完本文应该能够自己创建一个基本的触发器. 1.什么是触发器当一个指定的 SQL 操作(如 DELETE,INS ...

  3. (转)Linux系统基础网络配置老鸟精华篇

    Linux系统基础网络配置老鸟精华篇 原文:http://blog.51cto.com/oldboy/784625 对于linux高手看似简单的网络配置问题,也许要说出所以然来也并不轻松,因此仍然有太 ...

  4. mysql日常使用总结(持续更新中)

    记录一些日常的mysql常用的使用, 方便随用随查. 一.表结构 1.1 查看表结构 方式1: 可以查看建表语句,完整的表结构. show create table table_name; 方式2:可 ...

  5. PIO导出

    1..HSSFWorkbook 声明一个工作簿,创建一个excel文件 //创建HSSFWork对象(excel的文档对象) HSSFWorkbook wb=new HSSFWorkbook(); / ...

  6. kafka基础一

    基本概念: 消息系统的组成由生产者,消费者以及存储系统.消费者从存储系统中读取生产者生产的消息.Kafka作为分布式的消息系统支持多个生产者多个消费者,写消息时允许多个生产者写到同一个Partitio ...

  7. SQL语句中的having和where的区别

    --首先,两个都是用来进行筛选的: --区别在于 1.当分组筛选的时候使用having eg: 在emp中,查出最低工资小于1000的部门号 select deptno from emp group ...

  8. spring mvc 文件下载 get请求解决中文乱码问题

    方案简写,自己或有些基础的可以看懂,因为没时间写的那么详细 方案1 spring mvc解决get请求中文乱码问题, 在tamcat中server.xml文件 URIEncoding="UT ...

  9. vue使用element-ui实现按需引入

    基于Vue的Ui框架 饿了么公司基于vue开的的vue的Ui组件库 Element Ui 基于vue pc端的UI框架 MintUi 基于vue 移动端的ui框架 http://element.ele ...

  10. OSS基本概念介绍

    存储空间(Bucket): 存储空间是用于存储对象(Object)的容器,所有的对象都必须隶属于某个存储空间. 可以设置和修改存储空间属性用来控制地域.访问权限.生命周期等,这些属性设置直接作用于该存 ...