Чтение/запись объекта NetworkX Graph

Я пытаюсь иметь дело со сверхмассивным объектом NetworkX Graph с сотнями миллионов узлов. Я хотел бы иметь возможность записать его в файл, чтобы не потреблять всю память моего компьютера. Однако мне нужно постоянно искать существующие узлы, обновлять ребра и т. д.

Есть ли хорошее решение для этого? Я не уверен, как это будет работать с любым из форматов файлов, представленных на http://networkx.lanl.gov/reference/readwrite.html

Единственное решение, которое я могу придумать, - это хранить каждый узел в виде отдельного файла со ссылками на другие узлы в файловой системе - таким образом, открытие одного узла для проверки не перегружает память. Существует ли существующая файловая система для больших объемов данных (например, PyTables), чтобы сделать это без написания собственного шаблонного кода?


person ejang    schedule 14.06.2012    source источник


Ответы (3)


Если вы построили это как график NetworkX, то он уже будет в памяти. Я предполагаю, что для этого большого графика вам придется сделать что-то похожее на то, что вы предложили, с отдельными файлами. Но вместо использования отдельных файлов я бы использовал базу данных для хранения каждого узла с соединениями «многие ко многим» между узлами. Другими словами, у вас будет таблица узлов и таблица ребер, а затем, чтобы запросить соседей определенного узла, вы можете просто запросить любые ребра, у которых есть этот конкретный узел на любом конце. Это должно быть быстро, хотя я не уверен, сможете ли вы воспользоваться функциями анализа NetworkX без предварительного построения всей сети в памяти.

person LuisZaman    schedule 06.08.2012
comment
Спасибо Луис. По сути, я храню в базе данных. Однако запрашивать узлы для получения соседей чрезвычайно дорого. Я могу только представить, на что похожи серверы Google... - person ejang; 07.08.2012
comment
Если граф уже находится в оперативной памяти, то почему его сериализация может быть проблемой? (дисковое пространство дешевле, чем ОЗУ) Или у NetworkX есть какой-то внутренний метод, который сжимает представление и будет раздуваться во время сериализации? Мне интересно. - person user; 28.05.2013
comment
Я думаю, что вопрос сосредоточен не столько на сериализации, сколько на сохранении в структуре, которая позволит эффективно выполнять запросы. Вот откуда пришло мое предложение для базы данных. - person LuisZaman; 25.06.2013

Сначала попробуйте pickle; он предназначен для сериализации произвольных объектов.

Пример создания DiGraph и сериализации в файл:

import pickle
import networkx as nx

dg = nx.DiGraph()
dg.add_edge('a','b')
dg.add_edge('a','c')
pickle.dump(dg, open('/tmp/graph.txt', 'w'))

Пример загрузки DiGraph из файла:

import pickle
import networkx as nx

dg = pickle.load(open('/tmp/graph.txt'))
print dg.edges()

Выход:

[('a', 'c'), ('a', 'b')]

Если это недостаточно эффективно, я бы написал вашу собственную процедуру для сериализации:

  1. края и
  2. узлы (в случае, если узел не инцидентен ни одному ребру).

Обратите внимание, что использование спискового понимания, когда это возможно, может быть намного более эффективным (вместо стандартных циклов for).

Если это недостаточно эффективно, я бы вызвал подпрограмму C++ из Python: http://docs.python.org/extending/extending.html

person user    schedule 06.07.2012
comment
+1 огурец отличная штука, никогда о таком не слышал, спасибо! - person Eduardo; 05.02.2013
comment
Pickle генерирует ОГРОМНЫЕ файлы для объектов, и если это уже большая сеть, то pickle почти наверняка не сработает. Это отличный и малоиспользуемый пакет по многим другим причинам! - person LuisZaman; 25.06.2013
comment
@LuisZaman Я знаю, что ты имеешь в виду. В этом случае я бы вручную сериализовал ребра и узлы (как описано). Но если граф уже в ОЗУ, я бы очень удивился, если бы pickle раздулся настолько, что не поместился бы на диск. - person user; 08.11.2013
comment
Во-первых, используйте cPickle, это намного быстрее, во-вторых, используйте HIGHEST_PROTOCOL. Это сохранит его в более эффективном двоичном формате. - person Maarten; 14.11.2013
comment
При повторной загрузке маринованного графика тип графика остается прежним? В приведенном примере это был DiGraph, но график по умолчанию, созданный в NetworkX, является Graph, поэтому мне интересно, воссоздается ли объект DiGraph при загрузке из txt. - person ericmjl; 13.01.2014
comment
@ericmjl хороший вопрос: будет. Одна из строк в сериализованном файле определяет тип объекта (для приведенного примера в строке указано (cnetworkx.classes.digraph). - person user; 14.01.2014
comment
Я тоже только вчера это понял. Спасибо, Оливер! - person ericmjl; 14.01.2014
comment
Чтобы добавить к ответу, у самой NetworkX есть метод рассола. Вы можете сделать следующее: nx.write_gpickle(G,'graph.gpickle') Чтобы прочитать, вы можете сделать G = nx.read_gpickle('graph.gpickle') ; - person Dileep Kumar Patchigolla; 14.08.2018

Я забыл, какую проблему изначально решил решить в StackOverflow, но я наткнулся на этот вопрос и (с опозданием почти на десять лет!) могу порекомендовать Grand, networkx-подобная библиотека, которую мы написали именно для решения этой проблемы:

До

import networkx as nx

g = nx.DiGraph()
g.add_edge("A", "B")
print(len(g.edges()))

После

import grand
from grand.backends import SQLBackend # or choose another!

g = grand.Graph(backend=SQLBackend())
g.nx.add_edge("A", "B")
print(len(g.nx.edges()))

API такой же, как у NetworkX, но данные хранятся в SQL, DynamoDB и т. д.

person j6m8    schedule 20.11.2020