web-dev-qa-db-fra.com

Neo4j: faire correspondre plusieurs étiquettes (2 ou plus)

Je voudrais faire une recherche, et je voudrais commencer à parcourir à partir de 2 étiquettes (condition OR). Par exemple, j'ai besoin de trouver tous les nœuds qui ont des étiquettes 'Male' ou 'Female' et dont la propriété, name = ~ '.ail.'.

42
gaurav.singharoy

Vous pouvez mettre cela dans la clause WHERE:

MATCH n
WHERE n:Male OR n:Female
RETURN n

[~ # ~] modifier [~ # ~]

Comme le souligne @tbaum, cela effectue un AllNodesScan. J'ai écrit la réponse lorsque les étiquettes étaient assez nouvelles et je m'attendais à ce que le planificateur de requêtes l'implémente finalement avec un NodeByLabelScan pour chaque étiquette, comme il le fait pour le cas d'une seule étiquette

MATCH n
WHERE n:Male
RETURN n

Je pense toujours que c'est une expression raisonnable de la requête et qu'il est raisonnable de s'attendre à ce que le planificateur de requêtes l'implémente avec des analyses d'étiquettes, mais à partir de Neo4j 2.2.3, la requête est toujours implémentée avec un AllNodesScan et un filtre d'étiquette. Voici donc une alternative plus verbeuse. Étant donné que la disjonction d'étiquettes signifie une union définie et que cette union peut être exprimée de différentes manières, nous pouvons l'exprimer d'une manière que le planificateur de requêtes implémente sans analyser tous les nœuds, et commence à la place par un NodeByLabelScan par étiquette.

MATCH (n:Male)
WHERE n.name =~ '.ail.'
RETURN n
UNION MATCH (n:Female)
WHERE n.name =~ '.ail.'
RETURN n

Cela signifie exprimer la requête une fois pour chaque étiquette et les joindre avec un UNION explicite. Ce n'est pas déraisonnable, du moins pour un plus petit nombre d'étiquettes, mais je ne comprends pas pourquoi les planificateurs de requêtes ne devraient pas pouvoir déduire la même implémentation à partir de la requête plus simple, j'ai donc ouvert un problème de github ici .

46
jjaderberg
MATCH n WHERE n:Label1 OR n:Label2

... se traduira par un AllNodesScan c'est une mauvaise idée!

peut-être une meilleure solution:

OPTIONAL MATCH (n1:Label1)
WITH collect(distinct n1) as c1

OPTIONAL MATCH (n2:Label2) 
WITH collect(distinct n2) + c1 as c2

OPTIONAL MATCH (n3:Label3) 
WITH collect(distinct n3) + c2 as c3

UNWIND c3 as nodes
RETURN count(nodes),labels(nodes) 
14
tbaum

Avec Neo4j 3.4.7, le planificateur de requêtes effectue un UNION puis un DISTINCT de 2 NodeByLabelScans lorsque vous lui passez une requête WHERE avec 2 filtres d'étiquette OR. Essayer la Sandbox Offshore Leaks Database avec EXPLAIN MATCH (o) WHERE o:Officer OR o:Entity RETURN o donne cette planification:

Neo4j query planning

2
Markus Döring