Как оптимизировать этот зашифрованный запрос, чтобы получить быстрее Результат - PullRequest
0 голосов
/ 31 мая 2018

the-file-name.csv находится на предыдущем вопросе Как сделать запрос Cypher для обработки обоих случаев без дублирования узлов

На первомшаг, который я делаю

CREATE CONSTRAINT ON (r:Region) ASSERT r.region IS UNIQUE;
CREATE CONSTRAINT ON (c:City) ASSERT c.cityName IS UNIQUE;
CREATE CONSTRAINT ON (s:Sector) ASSERT s.sectorName IS UNIQUE;

Здесь я помещаю запрос шифра.

LOAD CSV WITH HEADERS FROM "file:///the-file-name.csv" as line 
FIELDTERMINATOR ','  
with line as line
OPTIONAL MATCH (n:Region) 
WHERE  n.region contains "BLANKEMPTYVIDE" AND n.identifier= line.CODE_TER 
WITH n, line
CALL apoc.do.when(
   n IS NULL,
  'MERGE (r:Region{region: line.TERRITOIRE}) ON CREATE SET r.description=line.TERRITOIRE ON CREATE SET r.identifier=line.CODE_TER ON CREATE SET r.id = toString(id(r)) RETURN r',
  'RETURN n AS r',
  {n: n, line: line}) YIELD value
WITH value.r AS r, line 
SET r.identifier=line.CODE_TER
SET r.description=line.TERRITOIRE
SET r.region=line.TERRITOIRE
WITH r,line
OPTIONAL MATCH (ci:City) where ci.cityName contains "BLANKEMPTYVIDE" AND ci.regionIdentifier= line.CODE_TER
CALL apoc.do.when(
   ci IS NULL,
  'MERGE (c:City {cityName:line.BRICK}) ON CREATE SET c.identifier=line.CODE_BRICK ON CREATE SET c.region=line.TERRITOIRE ON CREATE SET c.regionIdentifier=line.CODE_TER ON CREATE SET c.zip=line.CODE_BRICK ON CREATE SET c.description=line.BRICK ON CREATE SET c.id = toString(id(c)) RETURN c',
  'RETURN ci AS c',
  {ci: ci, line: line}) YIELD value
WITH value.c AS c,line,r
SET c.identifier=line.CODE_BRICK 
SET c.region=line.TERRITOIRE
SET c.regionIdentifier=line.CODE_TER
SET c.zip=line.CODE_BRICK
SET c.description=line.BRICK
SET c.cityName=line.BRICK  
WITH c,r,line
MATCH (c {identifier:line.CODE_BRICK}),(r {identifier:line.CODE_TER})
MERGE (c)-[:IS_A_City_BELONGING_TO]->(r)
WITH c,r,line
OPTIONAL MATCH (sec:Sector) 
WHERE  sec.description contains "BLANKEMPTYVIDE" AND sec.regionIdentifier=line.CODE_TER 
CALL apoc.do.when(
   sec IS NULL,
  'MERGE (s:Sector {sectorName:line.SOUSBRICK}) ON CREATE SET s.identifier=line.CODE_SBRICK ON CREATE SET s.region=line.TERRITOIRE ON CREATE SET s.regionIdentifier=line.CODE_TER ON CREATE SET s.city=line.BRICK ON CREATE SET s.cityIdentifier=line.CODE_BRICK ON CREATE SET s.description=line.SOUSBRICK ON CREATE SET s.zip=line.SOUSBRICK ON CREATE SET s.id = toString(id(s)) RETURN s',
  'RETURN sec AS s',
  {sec: sec, line: line}) YIELD value
WITH value.s AS s,line,c,r
SET s.identifier=line.CODE_SBRICK 
SET s.region=line.TERRITOIRE 
SET s.regionIdentifier=line.CODE_TER 
SET s.city=line.BRICK 
SET s.cityIdentifier=line.CODE_BRICK 
SET s.description=line.SOUSBRICK 
SET s.zip=line.SOUSBRICK 
SET s.sectorName = line.SOUSBRICK   
WITH s,c,r,line
MATCH (s {identifier:line.CODE_SBRICK}),(r{identifier:line.CODE_TER}) 
MERGE (s)-[:IS_A_SECTOR_BELONGING_TO_THAT_REGION]->(r) 
WITH s,c,r,line
MATCH (s {identifier:line.CODE_SBRICK}),(c{identifier:line.CODE_BRICK})
MERGE (s)-[:IS_A_SECTOR_BELONGING_TO_THAT_CITY]->(c)

Результат:

Установить 28271 свойства, создано 3400 отношений, завершено после34985 мс.

Потребовалось около 35 секунд, чтобы загрузить csv в neo4j db.пожалуйста, правильно ли это идеально в представлении производительности?

для CSV-файла, содержащего 1665 строк CSV, каждая строка содержит 6 полей: два первых поля для (Регион) третьего и четвертого (Город) и пятого ишестой для (Сектор).

Как оптимизировать этот запрос neo4j, чтобы он занимал всего несколько секунд, а не 3 секунды?

Здесь ниже я поместил изображение результата профилировщика.

PLAN

Здесь я сделал обновление по рекомендации InverseFalcon

LOAD CSV WITH HEADERS FROM "file:///the-file-name.csv" as line 
FIELDTERMINATOR ','  
with line as line
OPTIONAL MATCH (n:Region) 
WHERE  n.region contains "BLANKEMPTYVIDE" AND n.identifier= line.CODE_TER 
WITH n, line
CALL apoc.do.when(
   n IS NULL,
  'MERGE (r:Region{region: line.TERRITOIRE}) ON CREATE SET r.description=line.TERRITOIRE ON CREATE SET r.identifier=line.CODE_TER ON CREATE SET r.id = toString(id(r)) RETURN r',
  'SET n.identifier=line.CODE_TER  SET n.description=line.TERRITOIRE  SET n.region=line.TERRITOIRE RETURN n AS r',
  {n: n, line: line}) YIELD value
WITH value.r AS r, line 

OPTIONAL MATCH (ci:City) where ci.cityName contains "BLANKEMPTYVIDE" AND ci.regionIdentifier= line.CODE_TER
CALL apoc.do.when(
   ci IS NULL,
  'MERGE (c:City {cityName:line.BRICK}) ON CREATE SET c.identifier=line.CODE_BRICK ON CREATE SET c.region=line.TERRITOIRE ON CREATE SET c.regionIdentifier=line.CODE_TER ON CREATE SET c.zip=line.CODE_BRICK ON CREATE SET c.description=line.BRICK ON CREATE SET c.id = toString(id(c)) RETURN c',
  'SET ci.identifier=line.CODE_BRICK SET ci.region=line.TERRITOIRE SET ci.regionIdentifier=line.CODE_TER SET ci.zip=line.CODE_BRICK SET ci.description=line.BRICK SET ci.cityName=line.BRICK  RETURN ci AS c',
  {ci: ci, line: line}) YIELD value
WITH value.c AS c,line,r
MERGE (c)-[:IS_A_City_BELONGING_TO]->(r)
WITH c,r,line
OPTIONAL MATCH (sec:Sector) 
WHERE  sec.description contains "BLANKEMPTYVIDE" AND sec.regionIdentifier=line.CODE_TER 
CALL apoc.do.when(
   sec IS NULL,
  'MERGE (s:Sector {sectorName:line.SOUSBRICK}) ON CREATE SET s.identifier=line.CODE_SBRICK ON CREATE SET s.region=line.TERRITOIRE ON CREATE SET s.regionIdentifier=line.CODE_TER ON CREATE SET s.city=line.BRICK ON CREATE SET s.cityIdentifier=line.CODE_BRICK ON CREATE SET s.description=line.SOUSBRICK ON CREATE SET s.zip=line.SOUSBRICK ON CREATE SET s.id = toString(id(s)) RETURN s',
  'SET sec.identifier=line.CODE_SBRICK SET sec.region=line.TERRITOIRE SET sec.regionIdentifier=line.CODE_TER SET sec.city=line.BRICK SET sec.cityIdentifier=line.CODE_BRICK SET sec.description=line.SOUSBRICK SET sec.zip=line.SOUSBRICK SET sec.sectorName = line.SOUSBRICK   RETURN sec AS s',
  {sec: sec, line: line}) YIELD value
WITH value.s AS s,line,c,r
MERGE (s)-[:IS_A_SECTOR_BELONGING_TO_THAT_REGION]->(r) 
WITH s,c,r,line
MERGE (s)-[:IS_A_SECTOR_BELONGING_TO_THAT_CITY]->(c)

добавлен индекс описания для сектора ограничения становятся

CREATE CONSTRAINT ON (r:Region) ASSERT r.region IS UNIQUE;
CREATE CONSTRAINT ON (c:City) ASSERT c.cityName IS UNIQUE;
CREATE CONSTRAINT ON (s:Sector) ASSERT s.sectorName IS UNIQUE;
CREATE CONSTRAINT ON (s:Sector) ASSERT s.description IS UNIQUE;

Планирование от профилировщика

PLAN Версия шифра: CYPHER 3.4, планировщик: COST, время выполнения: INTERPRETED.Всего 175350 ударов в дБ за 14321 мс ****

Прямо без профилировщика Создано 3403 отношения, завершено через 12702 мс.

Хорошее улучшение с 36 с до 12 с, новсе еще нужна оптимизация.

1 Ответ

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

Операции с наибольшим количеством обращений к БД ссылаются на NodeByLabelScan, за которым следует фильтр, что дает только 1663 строки или результаты из начальных 1,3 миллиона или около того узлов метки.Это выглядит как возможность добавить индекс, если это возможно.

Вы не расширили узлы в плане запроса, поэтому мы не видим никакой информации о том, с какой частью запроса связаны эти обращения к базе данных.с, но если бы я догадался, это будет отсюда:

OPTIONAL MATCH (sec:Sector) 
WHERE  sec.description contains "BLANKEMPTYVIDE" AND sec.regionIdentifier=line.CODE_TER 

Я не вижу никаких доказательств того, что вы создали ограничение или индекс для: Sector (description) или: Sector (regionIdentifier)так что это, вероятно, где планировщик был вынужден использовать NodeByLabelScan, который, как вы можете видеть, стоит дорого.Вам понадобится индекс для одного из них или уникальное ограничение (в зависимости от того, является ли какое-либо из этих свойств уникальным для: Sector).

Отдельно, вы делаете любопытную вещь в нескольких местах вашего запроса, которая выглядит следующим образом:

MATCH (s {identifier:line.CODE_SBRICK}),(r{identifier:line.CODE_TER}) 

Переменные, которые вы используете в своем MATCH, уже связаны, поэтому япредложил бы вместо них использовать предложение WHERE, чтобы прояснить, что это должен быть этап фильтрации:

WITH s,c,r,line
WHERE s.identifier = line.CODE_SBRICK AND r.identifier = line.CODE_TER

Тем не менее, во всех этих случаях вы уже явно задали эти свойства длясвойства строки, о которых идет речь, поэтому в любом случае нет необходимости выполнять этот вид фильтрации, это не нужно.Я бы предложил удалить эти совпадения и просто ОБЪЕДИНИТЬ отношения.

...