Mendapatkan hasil pada kerangka data pandas dari kueri cypher pada database Neo4j dengan py2neo sangat mudah, seperti:

>>> from pandas import DataFrame
>>> DataFrame(graph.data("MATCH (a:Person) RETURN a.name, a.born LIMIT 4"))
   a.born              a.name
0    1964        Keanu Reeves
1    1967    Carrie-Anne Moss
2    1961  Laurence Fishburne
3    1960        Hugo Weaving

Sekarang saya mencoba untuk membuat (atau MERGE lebih baik) satu set node dan hubungan dari dataframe panda ke database Neo4j dengan py2neo. Bayangkan saya memiliki kerangka data seperti:

LABEL1 LABEL2
p1 n1
p2 n1
p3 n2
p4 n2

Di mana Label adalah tajuk kolom dan properti sebagai nilai. Saya ingin mereproduksi kueri sandi berikut (untuk baris pertama sebagai contoh), untuk setiap baris kerangka data saya:

query="""
    MATCH (a:Label1 {property:p1))
    MERGE (a)-[r:R_TYPE]->(b:Label2 {property:n1))
"""

Saya tahu saya dapat memberi tahu py2neo hanya untuk graph.run(query), atau bahkan menjalankan skrip cypher LOAD CSV dengan cara yang sama, tetapi saya ingin tahu apakah saya dapat mengulangi melalui kerangka data dan menerapkan kueri di atas baris demi baris DALAM py2neo .

10
Fabio Lamanna 17 Agustus 2017, 17:40

2 jawaban

Jawaban Terbaik

Anda dapat menggunakan DataFrame.iterrows() untuk beralih melalui DataFrame dan menjalankan kueri untuk setiap baris, meneruskan nilai dari baris sebagai parameter.

for index, row in df.iterrows():
    graph.run('''
      MATCH (a:Label1 {property:$label1})
      MERGE (a)-[r:R_TYPE]->(b:Label2 {property:$label2})
    ''', parameters = {'label1': row['label1'], 'label2': row['label2']})

Itu akan mengeksekusi satu transaksi per baris. Kami dapat mengelompokkan beberapa kueri menjadi satu transaksi untuk kinerja yang lebih baik.

tx = graph.begin()
for index, row in df.iterrows():
    tx.evaluate('''
      MATCH (a:Label1 {property:$label1})
      MERGE (a)-[r:R_TYPE]->(b:Label2 {property:$label2})
    ''', parameters = {'label1': row['label1'], 'label2': row['label2']})
tx.commit()

Biasanya kami dapat mengelompokkan ~20k operasi basis data dalam satu transaksi.

13
rafaelc 13 Oktober 2019, 13:51

Saya menemukan bahwa solusi yang diusulkan tidak bekerja untuk saya. Kode di atas membuat node baru meskipun node sudah ada. Untuk memastikan Anda tidak membuat duplikat apa pun, saya sarankan untuk mencocokkan simpul a dan b sebelum merge:

tx = graph.begin()
for index, row in df.iterrows():
    tx.evaluate('''
       MATCH (a:Label1 {property:$label1}), (b:Label2 {property:$label2})
       MERGE (a)-[r:R_TYPE]->(b)
       ''', parameters = {'label1': row['label1'], 'label2': row['label2']})
tx.commit()

Juga dalam kasus saya, saya harus menambahkan properti hubungan secara bersamaan (lihat kode di bawah). Selain itu, saya memiliki 500k+ hubungan untuk ditambahkan, jadi saya diharapkan mengalami kesalahan memori tumpukan Java. Saya memecahkan masalah dengan menempatkan begin() dan commit() di dalam loop, jadi untuk setiap hubungan baru, transaksi baru dibuat:

for index, row in df.iterrows():
    tx = graph.begin()
    tx.evaluate('''
       MATCH (a:Label1 {property:$label1}), (b:Label2 {property:$label2})
       MERGE (a)-[r:R_TYPE{property_name:$p}]->(b)
       ''', parameters = {'label1': row['label1'], 'label2': row['label2'], 'p': row['property']})
    tx.commit()
4
Anna Yashina 23 Juli 2019, 07:21