Как оптимизировать запросы Neo4j Cypher с несколькими совпадениями узлов (декартово произведение)

В настоящее время я пытаюсь объединить три набора данных для целей анализа. Я использую определенные общие поля для установления связей между наборами данных. Чтобы создать соединения, я попытался использовать следующий тип запроса:

MATCH (p1:Person),(p2:Person)
WHERE p1.email = p2.email AND p1.name = p2.name AND p1 <> p2 
CREATE UNIQUE (p1)-[IS]-(p2);

Который может быть так же написан как:

MATCH (p1:Person),(p2:Person {name:p1.name, email:p1.email})
WHERE p1 <> p2 
CREATE UNIQUE (p1)-[IS]-(p2);

Излишне говорить, что это очень медленный запрос к базе данных с около 100000 узлов Person, особенно учитывая, что Neo4j не обрабатывает отдельные запросы параллельно.

Теперь мой вопрос: есть ли лучший способ выполнить такие запросы в Neo4j? У меня есть как минимум восемь процессорных ядер для Neo4j, если отдельные потоки не связаны, блокируя необходимые ресурсы друг друга.

Проблема в том, что я не знаю, как Neo4j строит свои планы выполнения Cypher. Например, допустим, я запустил следующий тестовый запрос:

MATCH (p1:Person),(p2:Person {name:p1.name, email:p1.email})
WHERE p1 <> p2 
RETURN p1, p2
LIMIT 100;

Несмотря на предложение LIMIT, Neo4j по-прежнему требуется значительное количество времени для получения результатов, что заставляет меня задуматься, даже если для такого ограниченного запроса Neo4j выдает всю таблицу декартовых произведений, прежде чем рассматривать оператор LIMIT.

Я ценю любую помощь, независимо от того, решает ли она эту конкретную проблему или просто дает мне понимание того, как Neo4j обычно строит планы выполнения Cypher (и, следовательно, как оптимизировать запросы в целом). Могут ли здесь помочь какие-то устаревшие индексы Lucene?

1 ответ

Решение

Вы можете сделать комбинацию сканирования этикетки для p1 а затем поиск по индексу + сравнение для p2:

посмотреть здесь:

cypher 2.1 
foreach (i in range(1,100000) | 
  create (:Person {name:"John Doe"+str(i % 10000),
                   email:"john"+str(i % 10000)+"@doe.com"}));
+-------------------+
| No data returned. |
+-------------------+
Nodes created: 100000
Properties set: 200000
Labels added: 100000
6543 ms
neo4j-sh (?)$ CREATE INDEX ON :Person(name);
+-------------------+
| No data returned. |
+-------------------+
Indexes added: 1
28 ms

neo4j-sh (?)$ schema
Indexes
  ON :Person(name)  ONLINE

neo4j-sh (?)$ 
match (p1:Person) with p1 
match (p2:Person {name:p1.name}) using index p2:Person(name) 
where p1<>p2 AND p2.email = p1.email 
return count(*);
+----------+
| count(*) |
+----------+
| 900000   |
+----------+
1 row
8206 ms

neo4j-sh (?)$ 
match (p1:Person) with p1 
match (p2:Person {name:p1.name}) using index p2:Person(name) 
where p1<>p2 AND p2.email = p1.email
merge (p1)-[:IS]-(p2) 
return count(*);

+----------+
| count(*) |
+----------+
| 900000   |
+----------+
1 row
Relationships created: 450000
40256 ms
Другие вопросы по тегам