py2eo, neo4j: как обрабатывать большие операции ввода-вывода

У меня есть 473639 узлов и 995863 родительских и дочерних отношений в таблице mysql.

Использование как обычной, так и пакетной операции для извлечения данных, создания узла и отношения, но оба типа операций выполняются медленно. Есть ли обходной путь, чтобы ускорить этот процесс?

Код приведен ниже

import MySQLdb as my
from py2neo import neo4j, node, rel

def conn(query):
    db = my.connect(host='localhost',
                    user='root',
                    passwd='root',
                    db='localdb')
    cur = db.cursor()
    cur.execute(query)
    return db, cur

query = 'select * table1'
db, cur = conn(query)
d = dict()

graph = neo4j.GraphDatabaseService()
batch = neo4j.WriteBatch(graph)


def create_node(a):
    if a not in d:
        try:
            A = graph.create(node(name=str(a)))

            # for batch operation
            #A = batch.create(node(name=str(a)))

            d[a] = A
        except Exception, e:
            print e
    else:
        A = d[a]
    return A

cnt = 1

# create node

for row in cur.fetchall():
    a,b = get_cat(row[0]), get_cat(row[1])
    try:
        A, B = create_node(a), create_node(b)
        rels.append((A,B))
    except Exception, e:
        print e


#create relations

for item in rels:
    a = item[0]
    b = item[1]
    graph.create(rel(a,"is parent of",b))

    # for batch operation
    #batch.create(node(name=str(a)))


#res = batch.submit()
#print res

print 'end'

person Quazi Marufur Rahman    schedule 13.05.2014    source источник


Ответы (1)


Партия

Пакет будет намного быстрее, чем создание отдельных узлов. Но если вы запускаете партию, вы должны отправлять ее через каждые пару сотен элементов. Когда партия слишком большая, она становится медленнее. Попробуйте что-то вроде:

graph = neo4j.GraphDatabaseService()
batch = neo4j.WriteBatch(graph)

i = 0
results = []

for item in rels:
    a = item[0]
    b = item[1]
    batch.create(rel(a,"is parent of",b))

    # submit every 500 steps
    if i % 500 == 0:
        # collect results in list
        results.extend(batch.submit())
        # reinitialize and clear batch 
        batch = neo4j.WriteBatch(graph)

# submit last items         
results.extend(batch.submit())

Шифрование транзакций

Хорошей альтернативой являются шифрованные транзакции. У меня они работают немного быстрее, но приходится писать Cypher-запросы. Для простого создания элементов это, очевидно, сложнее, чем использование узлов/отношений py2neo. Но это может пригодиться для других операций (например, MERGE для обновления узлов). Имейте в виду, что вы также должны регулярно .execute() транзакцию, если она слишком велика, она замедляется.

session = cypher.Session("http://localhost:7474")
tx = session.create_transaction()

# send three statements to for execution but leave the transaction open
tx.append("MERGE (a:Person {name:'Alice'}) "
          "RETURN a")
tx.append("MERGE (b:Person {name:'Bob'}) "
          "RETURN b")
tx.append("MATCH (a:Person), (b:Person) "
          "WHERE a.name = 'Alice' AND b.name = 'Bob' "
          "CREATE UNIQUE (a)-[ab:KNOWS]->(b) "
          "RETURN ab")
tx.execute()

Как с транзакциями, так и с пакетами я пишу миллионы узлов/отношений за несколько минут. Вы должны попробовать разные размеры пакетов/транзакций (например, от 100 до 5000), я думаю, это зависит от объема памяти, который использует neo4j.

person Martin Preusse    schedule 20.05.2014
comment
Я уже протестировал пакетную отправку. batch.submit() не очищает пакет. Вам нужно повторно инициализировать пакет, чтобы освободить его после batch.submit(). Это не так быстро, как я думаю. Возможно, существует проблема типа утечки памяти как в пакетной, так и в обычной операции создания. Этот процесс потребляет 4 ГБ оперативной памяти после выполнения около 0,4 млн отношений. Сейчас я пытаюсь использовать пакетный импортер. - person Quazi Marufur Rahman; 20.05.2014
comment
Хорошо, вы можете легко повторно инициализировать пакет после отправки, см. редактирование. Существуют разные способы перебора списка и отправки/повторной инициализации каждые N шагов. Вы можете заранее разделить список и использовать куски и т. д. Операции создания в порядке, я делаю это много, и это работает. Python потребляет вашу память или neo4j/Java? - person Martin Preusse; 20.05.2014
comment
py2neo, пакетная.создать(), пакетная.отправить() - person Quazi Marufur Rahman; 20.05.2014
comment
Что это должно означать :) ? - person Martin Preusse; 20.05.2014
comment
Я не понял вашего последнего вопроса :) - person Quazi Marufur Rahman; 20.05.2014
comment
Вы сказали, что ваш процесс потребляет вашу память. Я спросил, какой процесс, то есть, использует ли Python вашу память (указывая на проблему в коде Python) или использует ли память neo4j/Java (указывая на огромный пакет или транзакцию, которую следует разделить на части). - person Martin Preusse; 20.05.2014