<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Neo4j入門(二)批量插入節(jié)點(diǎn)、關(guān)系

          共 9801字,需瀏覽 20分鐘

           ·

          2021-07-16 10:08

          ??本文將介紹如何在Neo4j中批量插入節(jié)點(diǎn)、關(guān)系,提升圖譜構(gòu)建的效率。
          ??在講解批量插入節(jié)點(diǎn)、關(guān)系前,我們需要了解下節(jié)點(diǎn)重復(fù)創(chuàng)建問題。

          節(jié)點(diǎn)重復(fù)創(chuàng)建

          ??在Neo4j中,我們?nèi)绻麑?duì)同一個(gè)節(jié)點(diǎn)進(jìn)行重復(fù)插入,則圖譜中會(huì)存在多個(gè)重復(fù)節(jié)點(diǎn),這是因?yàn)镹eo4j本身自帶一個(gè)自增id造成的。
          ??我們來創(chuàng)建name為Google、address為U.S.的節(jié)點(diǎn)。使用CQL語句如下:

          create (company: Company{name: "Google", address: "U.S."});
          create (company: Company{name: "Google", address: "U.S."});

          可以看到,圖譜中存在兩個(gè)貌似一模一樣的節(jié)點(diǎn),如下圖:

          兩個(gè)一模一樣的節(jié)點(diǎn)?

          實(shí)際上,這兩個(gè)節(jié)點(diǎn)只有id不同,這個(gè)id是Neo4j自帶的id,由系統(tǒng)生成。
          只有id不同的兩個(gè)節(jié)點(diǎn)

          ??避免重復(fù)創(chuàng)建節(jié)點(diǎn)的辦法如下:
          • 使用MERGE命令代替

          • 在創(chuàng)建節(jié)點(diǎn)前,先查詢下圖譜中該節(jié)點(diǎn)是否存在

          數(shù)據(jù)集

          ??我們選用OpenKG中的行政區(qū)相鄰數(shù)據(jù)集(數(shù)據(jù)有點(diǎn)兒小問題,需要自己改動(dòng)下),訪問網(wǎng)址為:http://www.openkg.cn/dataset/xzqh,我們想要構(gòu)建的示例圖譜(局部)如下:

          示例圖譜(浙江省)

          ??該圖譜中一共有個(gè)2834個(gè)節(jié)點(diǎn)(其中城市節(jié)點(diǎn)2801個(gè),省份節(jié)點(diǎn)33個(gè)),18807條關(guān)系。

          單個(gè)節(jié)點(diǎn)、關(guān)系創(chuàng)建

          ??首先我們采用單個(gè)節(jié)點(diǎn)、關(guān)系依次創(chuàng)建,觀察其圖譜構(gòu)建的耗時(shí)。示例Python代碼如下:

          # -*- coding: utf-8 -*-
          import json
          import time

          from py2neo import Graph, Node, Relationship
          from py2neo import NodeMatcher, RelationshipMatcher

          # 連接Neo4j
          url = "http://localhost:7474"
          username = "neo4j"
          password = "password"
          graph = Graph(url, auth=(username, password))
          print("neo4j info: {}".format(str(graph)))

          # 讀取數(shù)據(jù)
          with open("data.json""r", encoding="utf-8"as f:
              data_dict = json.loads(f.read())
          nodes = data_dict["nodes"]
          relations = data_dict["relations"]

          # 創(chuàng)建節(jié)點(diǎn)
          s_time = time.time()
          create_node_cnt = 0
          node_matcer = NodeMatcher(graph)
          for node in nodes:
              label = node["label"]
              name = node["name"]
              find_node = node_matcer.match(label, name=name).first()
              if find_node is None:
                  attrs = {k: v for k, v in node.items() if k != "label"}
                  node = Node(label, **attrs)
                  graph.create(node)
                  create_node_cnt += 1
                  print(f"create {create_node_cnt} nodes.")

          # 創(chuàng)建關(guān)系
          create_rel_cnt = 0
          relation_matcher = RelationshipMatcher(graph)
          for relation in relations:
              s_node, s_label = relation["subject"], relation["subject_type"]
              e_node, e_label = relation["object"], relation["object_type"]
              rel = relation["predicate"]
              start_node = node_matcer.match(s_label, name=s_node).first()
              end_node = node_matcer.match(e_label, name=e_node).first()
              if start_node is not None and end_node is not None:
                  r_type = relation_matcher.match([start_node, end_node], r_type=rel).first()
                  if r_type is None:
                      graph.create(Relationship(start_node, rel, end_node))
                      create_rel_cnt += 1
                      print(f"create {create_rel_cnt} relations.")

          # 輸出信息
          e_time = time.time()
          print(f"create {create_node_cnt} nodes, create {create_rel_cnt} relations.")
          print(f"cost time: {round((e_time-s_time)*10004)}ms")

          上述創(chuàng)建圖譜腳本共耗時(shí)802.1秒。
          ??無疑上述操作過程是非常耗時(shí)的,在創(chuàng)建節(jié)點(diǎn)時(shí),需要先查詢每個(gè)節(jié)點(diǎn)在圖譜中是否存在,不存在則創(chuàng)建該節(jié)點(diǎn);在創(chuàng)建關(guān)系時(shí),需要先查詢兩個(gè)節(jié)點(diǎn)是否存在,如節(jié)點(diǎn)存在,而關(guān)系不存在,則創(chuàng)建該關(guān)系。在整個(gè)操作過程中,需要頻繁地查詢圖譜、創(chuàng)建節(jié)點(diǎn)、創(chuàng)建關(guān)系,這無疑是該腳本耗時(shí)的地方所在。

          批量節(jié)點(diǎn)、關(guān)系創(chuàng)建

          ??通過創(chuàng)建子圖(Subgraph),我們可以實(shí)現(xiàn)批量創(chuàng)建節(jié)點(diǎn)、關(guān)系,這樣可以提升圖譜構(gòu)建的效率。批量節(jié)點(diǎn)、關(guān)系創(chuàng)建的Python代碼如下:

          # -*- coding: utf-8 -*-
          import json
          import time

          from py2neo import Graph, Node, Relationship, Subgraph
          from py2neo import RelationshipMatcher

          # 連接Neo4j
          url = "http://localhost:7474"
          username = "neo4j"
          password = "password"
          graph = Graph(url, auth=(username, password))
          print("neo4j info: {}".format(str(graph)))

          # 讀取數(shù)據(jù)
          with open("data.json""r", encoding="utf-8"as f:
              data_dict = json.loads(f.read())
          nodes = data_dict["nodes"]
          relations = data_dict["relations"]

          # 查詢city和province節(jié)點(diǎn)是否在圖譜中
          cql = "match (n:province) return (n.name);"
          province_names = [_["(n.name)"for _ in graph.run(cql).data()]
          cql = "match (n:city) return (n.name);"
          city_names = [_["(n.name)"for _ in graph.run(cql).data()]

          # 創(chuàng)建節(jié)點(diǎn)
          s_time = time.time()
          create_node_cnt = 0
          create_nodes = []
          for node in nodes:
              label = node["label"]
              name = node["name"]
              if label == "city" and name not in city_names:
                  attrs = {k: v for k, v in node.items() if k != "label"}
                  create_nodes.append(Node(label, **attrs))
                  create_node_cnt += 1
              elif label == "province" and name not in province_names:
                  attrs = {k: v for k, v in node.items() if k != "label"}
                  create_nodes.append(Node(label, **attrs))
                  create_node_cnt += 1

          # 批量創(chuàng)建節(jié)點(diǎn)
          batch_size = 50
          if create_nodes:
              for i in range(len(create_nodes)//50 + 1):
                  subgraph = Subgraph(create_nodes[i*batch_size: (i+1)*batch_size])
                  graph.create(subgraph)
                  print(f"create {(i+1)*batch_size} nodes")

          # 創(chuàng)建關(guān)系
          cql = "match (n:province) return (n);"
          province_nodes = [_["n"for _ in graph.run(cql).data()]
          cql = "match (n:city) return (n);"
          city_nodes = [_["n"for _ in graph.run(cql).data()]
          city_dict = {_["name"]: _ for _ in city_nodes}
          province_dict = {_["name"]: _ for _ in province_nodes}
          create_rel_cnt = 0
          create_relations = []
          rel_matcher = RelationshipMatcher(graph)
          for relation in relations:
              s_node, s_label = relation["subject"], relation["subject_type"]
              e_node, e_label = relation["object"], relation["object_type"]
              rel = relation["predicate"]
              start_node, end_node = NoneNone
              if s_label == "city":
                  start_node = city_dict.get(s_node, None)
              if e_label == "city":
                  end_node = city_dict.get(e_node, None)
              elif e_label == "province":
                  end_node = province_dict.get(e_node, None)
              if start_node is not None and end_node is not None:
                  r_type = rel_matcher.match([start_node, end_node], r_type=rel).first()
                  if r_type is None:
                      create_relations.append(Relationship(start_node, rel, end_node))
                      create_rel_cnt += 1

          # 批量創(chuàng)建關(guān)系
          batch_size = 50
          if create_relations:
              for i in range(len(create_relations)//50 + 1):
                  subgraph = Subgraph(relationships=create_relations[i*batch_size: (i+1)*batch_size])
                  graph.create(subgraph)
                  print(f"create {(i+1)*batch_size} relations")

          # 輸出信息
          e_time = time.time()
          print(f"create {create_node_cnt} nodes, create {create_rel_cnt} relations.")
          print(f"cost time: {round((e_time-s_time)*10004)}ms")
          1. 初次運(yùn)行該腳本時(shí),創(chuàng)建整個(gè)圖譜(創(chuàng)建2834個(gè)節(jié)點(diǎn),18807條關(guān)系)需要95.1秒。

          2. 再次運(yùn)行該腳本時(shí),創(chuàng)建整個(gè)圖譜(創(chuàng)建0個(gè)節(jié)點(diǎn),0條關(guān)系)需要522.5秒。

          ??注意,上述腳本的耗時(shí)需要體現(xiàn)在查詢所有city和province節(jié)點(diǎn),并返回這些節(jié)點(diǎn)的查詢過程中,構(gòu)建節(jié)點(diǎn)、關(guān)系是很快的,但為了避免重復(fù)插入節(jié)點(diǎn)和關(guān)系,這一步查詢所有city和province節(jié)點(diǎn)是很有必要的。當(dāng)然,如果節(jié)點(diǎn)數(shù)量過大時(shí),應(yīng)考慮其他方案,因?yàn)椴樵兯泄?jié)點(diǎn)也是很耗時(shí)并且消耗內(nèi)存的。

          總結(jié)

          ??本文主要介紹了如何在Neo4j中批量創(chuàng)建節(jié)點(diǎn)、關(guān)系,從而提升圖譜構(gòu)建效率。
          ??2021年7月15日于上海浦東,此日上海酷暑逼人~


          瀏覽 159
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产乱╳╳╳╳AⅤ视频 | 天堂在线观看av 亚洲无码视频播放 | 久久五月丁香 | 亚洲最新中文字幕在线 | 五十路激情 |