【问题标题】:Importing a large xml file to Neo4j with Py2neo使用 Py2neo 将大型 xml 文件导入 Neo4j
【发布时间】:2016-06-30 10:53:42
【问题描述】:

我在导入具有 36196662 行的非常大的 XML 文件时遇到问题。我正在尝试使用 Py2neo 创建此 XML 文件的 Neo4j 图形数据库 我的 xml 文件如下所示:

http://imgur.com/pLylHeG

我将 xml 数据导入 Neo4j 的 python 代码是这样的:

from xml.dom import minidom
from py2neo import Graph, Node, Relationship, authenticate
from py2neo.packages.httpstream import http
http.socket_timeout = 9999
import codecs

authenticate("localhost:7474", "neo4j", "******")

graph = Graph("http://localhost:7474/db/data/")

xml_file = codecs.open("User_profilesL2T1.xml","r", encoding="latin-1")

xml_doc = minidom.parseString (codecs.encode (xml_file.read(), "utf-8"))

#xml_doc = minidom.parse(xml_file)
persons = xml_doc.getElementsByTagName('user')
label1 = "USER"

# Adding Nodes
for person in persons:


    if person.getElementsByTagName("id")[0].firstChild:
       Id_User=person.getElementsByTagName("id")[0].firstChild.data
    else: 
       Name="NO ID"
    print ("******************************USER***************************************")
    print(Id_User)



    print ("*************************")
    if person.getElementsByTagName("name")[0].firstChild:
       Name=person.getElementsByTagName("name")[0].firstChild.data
    else: 
       Name="NO NAME"   
   # print("Name :",Name)


    print ("*************************")
    if person.getElementsByTagName("screen_name")[0].firstChild:
       Screen_name=person.getElementsByTagName("screen_name")[0].firstChild.data
    else: 
       Screen_name="NO SCREEN_NAME" 
  #   print("Screen Name :",Screen_name)

    print ("*************************") 
    if person.getElementsByTagName("location")[0].firstChild:
       Location=person.getElementsByTagName("location")[0].firstChild.data
    else: 
       Location="NO Location"   
 #    print("Location :",Location)


    print ("*************************")
    if person.getElementsByTagName("description")[0].firstChild:
       Description=person.getElementsByTagName("description")[0].firstChild.data
    else: 
       Description="NO description" 
  #   print("Description :",Description)


    print ("*************************") 
    if person.getElementsByTagName("profile_image_url")[0].firstChild:
       Profile_image_url=person.getElementsByTagName("profile_image_url")[0].firstChild.data
    else: 
       Profile_image_url="NO profile_image_url" 
   # print("Profile_image_url :",Profile_image_url)

    print ("*************************")
    if person.getElementsByTagName("friends_count")[0].firstChild:
       Friends_count=person.getElementsByTagName("friends_count")[0].firstChild.data
    else: 
       Friends_count="NO friends_count" 
 #    print("Friends_count :",Friends_count)


    print ("*************************")
    if person.getElementsByTagName("url")[0].firstChild:
       URL=person.getElementsByTagName("url")[0].firstChild.data
    else: 
       URL="NO URL" 
  #   print("URL :",URL)






    node1 = Node(label1,ID_USER=Id_User,NAME=Name,SCREEN_NAME=Screen_name,LOCATION=Location,DESCRIPTION=Description,Profile_Image_Url=Profile_image_url,Friends_Count=Friends_count,URL=URL)
    graph.merge(node1)  

我的问题是当我运行代码时,导入这个文件需要很长时间才能做到这一点,所以如果有人能帮助我更快地导入数据,我将非常感激。

注意:我的笔记本电脑配置是:4Gb RAM、500Gb 硬盘、i5

【问题讨论】:

    标签: python xml neo4j xml-parsing py2neo


    【解决方案1】:

    如果您要将数据导入新数据库,您可能需要尝试导入工具:https://neo4j.com/docs/operations-manual/current/#import-tool

    在这种情况下,您应该像以前一样解析 XML 文件,但不要使用 py2neo 将数据插入 Neo4j,只需编写一个 CSV 文件,然后调用导入工具。

    请参阅下面的一种可能的方法:

    import csv
    from xml.dom import minidom
    
    def getAttribute(node,attribute,default=None):
        attr = node.getElementsByTagName(attribute)[0]
        return attr.firstChild.data if attr.firstChild else default
    
    xml_doc = minidom.parse(open("users.xml"))
    persons = xml_doc.getElementsByTagName('user')
    
    users = []
    attrs = ['name','screen_name','location','description','profile_image_url','friends_count','url']
    
    mapping = {'user_id': 'user_id:ID(User)',
               'name': 'name:string',
               'screen_name': 'screen_name:string',
               'location': 'location:string',
               'description': 'description:string',
               'profile_image_url': 'profile_image_url:string',
               'friends_count': 'friends_count:int',
               'url': 'url:string'}
    
    with open('users.csv','w') as csvfile:
        writer = csv.DictWriter(csvfile, fieldnames=mapping.values())
        writer.writeheader()
        for person in persons:
            user = {mapping[attr]: getAttribute(person, attr) for attr in attrs}
            user[mapping['user_id']] = getAttribute(person, 'id')
    
            writer.writerow(user)
    

    将 xml 转换为 csv 文件后,运行导入工具:

    $ neo4j-import --into neo4j-community-3.0.3/data/databases/users.db --nodes:User users.csv
    

    我猜您还想在节点之间创建关系 (?)。您应该阅读导入工具文档并使用 csv 文件调用导入工具以获取节点和关系

    【讨论】:

    • 谢谢桑乔的回复,但我不知道该怎么做,如果你能建议我一个代码来做,那就太好了。
    • 我刚刚用一个例子编辑了我之前的回复。我希望它有所帮助。
    • 非常感谢桑乔的帮助
    • 您好 Sancho,当我测试您的解决方案时,每次从 xml 转换为 csv 和我的笔记本电脑错误都需要很长时间!
    • 我不知道“我的笔记本电脑每次出现错误”是什么意思...它是否内存不足?我没有太多解析大型 xml 文件的经验,但您似乎应该尝试一些替代方法来避免将整个 xml 文件加载到内存中:stackoverflow.com/questions/9856163/…boscoh.com/programming/reading-xml-serially.htmlgithub.com/martinblech/xmltodict
    【解决方案2】:

    我认为你应该使用流式解析器,否则你甚至可能在 python 端溢出内存。

    我还建议在 Neo4j 中进行交易,每笔交易批量更新 10k 到 100k。

    不要存储 "NO xxxx" 字段,不要存储它们,这只是浪费空间和精力。

    我不知道合并(节点)是如何工作的。我建议在 :User(userId) 上创建一个唯一约束并使用这样的密码查询:

    UNWIND {data} as row
    MERGE (u:User {userId: row.userId}) ON CREATE SET u += {row}
    

    其中{data} 参数是具有属性的字典列表(例如 10k 个条目)。

    【讨论】:

    • 感谢迈克尔的回复。关于您的建议,我如何使用 py2neo 做到这一点,如果您能帮助我提供代码,我将不胜感激。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-08
    • 2015-09-08
    相关资源
    最近更新 更多