使用python

时间:2016-11-09 19:52:29

标签: python neo4j graph-databases

我正在尝试将lastfm360K数据库导入Neo4j数据库。我首先将所有用户作为节点插入,而不会出现以下代码

的任何问题
import re
from datetime import datetime
from elasticsearch import Elasticsearch
import certifi
from neo4j.v1 import GraphDatabase, basic_auth

driver = GraphDatabase.driver("bolt://localhost", auth=basic_auth("neo4j", "pass"))
session = driver.session()

with open("/Users/inanc/Documents/Software/lastfm-dataset-360K/usersha1-profile.tsv" , 'r') as userFile:
    #first_line = userFile.readline()
    linenum = 0
    for line in userFile:
        linenum = linenum + 1
        if linenum % 1000 == 0:
            print(linenum)
        lineStrip = line.rstrip().split("\t")
        tempDict = {}
        tempDict["user_id"] = lineStrip[0]
        if len(lineStrip) > 1:
            tempDict["gender"] = lineStrip[1]
            if lineStrip[2] != "":
                tempDict["age"] = int(lineStrip[2])
            tempDict["country"] = lineStrip[3]
            tempDict["signup"] = lineStrip[4]
        session.run("CREATE (a:Person {dict})", {"dict": tempDict})


session.close()

然后我想按如下方式添加Artist节点和与用户的关系

import re
from datetime import datetime
from elasticsearch import Elasticsearch
import certifi
from neo4j.v1 import GraphDatabase, basic_auth

driver = GraphDatabase.driver("bolt://localhost", auth=basic_auth("neo4j", "pass"))
session = driver.session()

linenum = 0
with open("/Users/inanc/Documents/Software/lastfm-dataset-360K/usersha1-artmbid-artname-plays.tsv" , 'r') as songFile:
    for line in songFile:
        linenum = linenum + 1
        if linenum % 10000 == 0:
            print(linenum)
        lineStrip = line.rstrip().split("\t")
        if len(lineStrip) == 4:
            #print(line)
            user_id = lineStrip[0]
            musicbrainz_artistid = lineStrip[1]
            artist_name = lineStrip[2]
            plays = 1
            if lineStrip[3] != "":
                plays = int(lineStrip[3])

            session.run("MERGE (a:Artist {artist_name: {artist_name}})", {"artist_name": artist_name})
            session.run("MATCH (p:Person {user_id: {user_id}}), (a:Artist {artist_name: {artist_name}}) CREATE (p)-[:LIKES {times: {plays}}]->(a)", {"user_id": user_id, "artist_name": artist_name, "plays": plays})

session.close()

它开始这样做没有任何错误(顺便说一下它很慢,花了几个小时),但过了一段时间它挂在某个点(例如在几百万行之后)。即使我的python脚本挂起,我仍然可以通过浏览器查询。

我唯一的限制是

create constraint on (p:Person) assert p.user_id is unique;
create constraint on (a:Artist) assert a.artist_name is unique;

我在8GB内存的Macbook上使用neo4j 3.0.7。我也使用neo4j正式支持的python driver

任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:1)

每次拨打session.run()都会执行以下操作:

  • 开始交易。
  • 执行传递给run()
  • 的Cypher语句
  • 提交(或回滚)交易。

在您的情况下,您实际上是在每个输入行进行两次 session.run()次调用。不仅如此,第二次调用中的Cypher语句必须MATCH在第一次调用中由Cypher获得的Artist节点。

由于您的输入文件有1750万行,这意味着您正在创建/提交/关闭3500万个事务。此外,您正在执行1750万次不必要的MATCH操作。这非常非常昂贵,也可能导致司机有时绊倒。

建议:

  1. 您应该在同一个事务中批量处理多个操作。例如,如果您在每个事务中批量处理10K操作,那么1750万个输入行只需要1750个事务。

  2. 您应该将两个Cypher语句合并为一个。

  3. 例如,如果您更改了代码,则应该获得更好的结果:

    • 为每批10K元素生成一个list数组参数,(如果打印得很漂亮)将如下所示:

      {"list": 
        [
          {"id": 1, "name": 'aaa', "plays": 3},
          {"id": 2, "name": 'bbb', "plays": 2},
          {"id": 3, "name": 'ccc', "plays": 3},
          ...
          {"id": 10000, "name": 'xyz', "plays": 7}
        ]
      }
      
    • 使用以下Cypher声明:

      UNWIND {list} AS d
      MATCH (p:Person {user_id: d.id})
      MERGE (a:Artist {artist_name: d.name})
      MERGE (p)-[:LIKES {times: d.plays}]->(a)
      
    • 使用上述Cypher语句和参数调用session.run()(每10K输入行一次)。