Использование apoc.periodic.commit или других подходов для пакетной обработки большого последовательного запроса. - PullRequest
0 голосов
/ 04 мая 2018

Мне посоветовали использовать apoc.periodic.commit для пакетирования большого запроса, который я выполняю в neo4j. Мой код ниже, кажется, не группируется и не фиксируется, хотя после каждого шага. Серверу не хватает памяти, чего, я думаю, не должно быть, если после каждого отдельного элемента происходит фиксация.

Я вычисляю индексы jaccard для набора узлов (здесь я называю свойство paradig для «парадигматического отношения», так как это набор отношений следующего слова в тексте).

Вычисление этого для каждого узла - довольно большая работа. Я рассчитываю на 53 узла, но все население составляет около 60 тыс., И это операция n ^ 2. Если я запускаю его в одной транзакции, мне не хватает памяти. Поэтому я хочу запускать его партиями, фиксируя после расчета каждого индекса. Я пометил узлы, которые мне нужно обработать, свойством toProcess, и я запускаю приведенный ниже код для вычисления индексов jaccard

1) Я просто использую apoc неправильно?

2) есть лучший, более neo4j-ориентированный способ сделать это. Я всегда работал с SQL.

call apoc.periodic.commit("
MATCH (s:Word{toProcess: True})
MATCH (w:Word)-[:NEXT_WORD]->(s)
WITH collect(DISTINCT w.name) as left1, s
MATCH (w:Word)<-[:NEXT_WORD]-(s)
WITH left1, s, collect(DISTINCT w.name) as right1
// Match every other word
MATCH (o:Word) WHERE NOT s = o
WITH left1, right1, s, o
// Get other right, other left1
MATCH (w:Word)-[:NEXT_WORD]->(o)
WITH collect(DISTINCT w.name) as left1_o, s, o, right1, left1
MATCH (w:Word)<-[:NEXT_WORD]-(o)
WITH left1_o, s, o, right1, left1, collect(DISTINCT w.name) as right1_o
// compute right1 union, intersect
WITH FILTER(x IN right1 WHERE x IN right1_o) as r1_intersect,
  (right1 + right1_o) AS r1_union, s, o, right1, left1, right1_o, left1_o
// compute left1 union, intersect
WITH FILTER(x IN left1 WHERE x IN left1_o) as l1_intersect,
  (left1 + left1_o) AS l1_union, r1_intersect, r1_union, s, o
WITH DISTINCT r1_union as r1_union, l1_union as l1_union, r1_intersect, l1_intersect, s, o
WITH 1.0*size(r1_intersect) / size(r1_union) as r1_jaccard,
  1.0*size(l1_intersect) / size(l1_union) as l1_jaccard,
  s, o
WITH s, o, r1_jaccard, l1_jaccard, r1_jaccard + l1_jaccard as sim
MERGE (s)-[r:RELATED_TO]->(o) SET r.paradig = sim
set s.toProcess = false
",{batchSize:1, parallel:false})

Обоснование:

batchSize:1: я хочу, чтобы он фиксировался после установки каждого индекса jaccard

parallel:false: я хочу последовательную операцию, чтобы у меня не хватило памяти

1 Ответ

0 голосов
/ 04 мая 2018

У меня это работает, используя apoc.periodic.iterate вместо apoc.periodic.commit, как показано ниже

Хотя это решает мою собственную проблему, я пока не буду отмечать это как ответ, так как думаю, что для других, кто придет к этому, будет полезно получить более четкий ответ на этот вопрос от кого-то, кто знает, что они делают , Мне было трудно найти лучшую практику для пакетирования обновлений, подобных этому, в neo4j, и я сам не достаточно эксперта, чтобы знать, является ли это лучшей (или даже наполовину приличной) практикой

call apoc.periodic.iterate("

MATCH (s:Word) where s.toProcess=true
return s", 
"MATCH (w:Word)-[:NEXT_WORD]->(s)
WITH collect(DISTINCT w.name) as left1, s
MATCH (w:Word)<-[:NEXT_WORD]-(s)
WITH left1, s, collect(DISTINCT w.name) as right1
// Match every other word
MATCH (o:Word) WHERE NOT s = o
WITH left1, right1, s, o
// Get other right, other left1
MATCH (w:Word)-[:NEXT_WORD]->(o)
WITH collect(DISTINCT w.name) as left1_o, s, o, right1, left1
MATCH (w:Word)<-[:NEXT_WORD]-(o)
WITH left1_o, s, o, right1, left1, collect(DISTINCT w.name) as right1_o
// compute right1 union, intersect
WITH FILTER(x IN right1 WHERE x IN right1_o) as r1_intersect,
  (right1 + right1_o) AS r1_union, s, o, right1, left1, right1_o, left1_o
// compute left1 union, intersect
WITH FILTER(x IN left1 WHERE x IN left1_o) as l1_intersect,
  (left1 + left1_o) AS l1_union, r1_intersect, r1_union, s, o
WITH DISTINCT r1_union as r1_union, l1_union as l1_union, r1_intersect, l1_intersect, s, o
WITH 1.0*size(r1_intersect) / size(r1_union) as r1_jaccard,
  1.0*size(l1_intersect) / size(l1_union) as l1_jaccard,
  s, o
WITH s, o, r1_jaccard, l1_jaccard, r1_jaccard + l1_jaccard as sim
MERGE (s)-[r:RELATED_TO]->(o) SET r.paradig = sim
set s.toProcess = false",
{batchSize:1})
yield batches, total return batches, total
...