J'utilise Neo4j pour représenter notre entrepôt de données. Nous avons environ 100 000 noeuds de divers types (~ 10) dont certains ont plusieurs étiquettes. Un sous-ensemble des types de nœuds typiques sont:Stratégie d'index Neo4j optimale pour les nœuds multi-étiquettes
(:User)
(:Tableau:Workbook)
(:Tableau:Dashboard)
Ici Tableau
représente le logiciel de visualisation de données et Workbook
et Dashboard
sont différentes entités de tableau. La raison pour laquelle nous sommes allés avec plusieurs étiquettes plutôt qu'une seule étiquette définie de manière unique était que l'on peut vouloir faire correspondre tous les nœuds (:Tableau)
ou tous les nœuds (:Dashboard)
(nous avons plusieurs sources de tableau de bord).
J'utilise également la bibliothèque UAID GraphAware Neo4j (https://github.com/graphaware/neo4j-uuid) pour m'assurer que chaque noeud (quel que soit son type) est identifié de manière unique via la propriété de noeud uuid
.
J'ai créé un index (et contrainte d'unicité) pour chaque étiquette de noeud pour améliorer les performances, à savoir
CREATE INDEX ON:User(uuid)
CREATE INDEX ON:Tableau(uuid)
CREATE INDEX ON:Workbook(uuid)
CREATE INDEX ON:Dashboard(uuid)
étant donné que CREATE INDEX
doit prendre exactement une étiquette.
J'ai rencontré quelques problèmes de performances lors de la mise en correspondance de noeuds en utilisant Cypher étant donné cette structure d'indexation. Même si la cardinalité de (:Tableau:Dashboard)
< < (:Tableau)
la requête suivante est suboptimale
MATCH (n:Tableau:Dashboard) WHERE n.uuid = <UUID>
par rapport à une ou l'autre
MATCH (n:Tableau) WHERE n.uuid = <UUID>
MATCH (n:Dashboard) WHERE n.uuid = <UUID>
étant donné que l'ancien ne tirent parti de ne tout indice que le faire plus tard. Ce problème est aggravé si l'on veut trouver un nœud globalement basé uniquement sur l'UUID (qui est unique) ce qui est souvent le cas lorsqu'on utilise une API Flask pour trouver des nœuds, ce qui se traduit par la logique Cypher suivante:
MATCH(n) WHERE n.uuid = <UUID>
fil suivant suggère la création d'une étiquette de noeud global global Entity
et la création d'un index sur cette (Neo4j: Create index for nodes with same property),
CREATE INDEX ON:Entity(uuid)
si les noeuds maintenant être étiquetés avec comme suit,
(:Entity:User)
(:Entity:Tableau:Workbook)
(:Entity:Tableau:Dashboard)
Est-ce la meilleure approche? Une autre solution consisterait à choisir simplement la première étiquette si plusieurs étiquettes sont définies, étant donné qu'elle est garantie d'être indexée, mais cela ne résout pas le problème de trouver un nœud basé uniquement sur l'UUID. Si j'utilise l'approche de libellé Entity
, est-il toujours logique de conserver tous les index définis précédemment, c'est-à-dire que je prévois des améliorations significatives des performances si je ne recherche qu'un petit sous-ensemble de nœuds? Par exemple, si je savais que n
était un noeud (:User)
dois-je attendre à voir des performances similaires avec,
MATCH (n:Entity) WHERE n.uuid = <UUID>
MATCH (n:User) WHERE n.uuid = <UUID>
Ne pas avoir la capacité d'index sur aucun ou plusieurs index est une honte, étant donné que les requêtes optimales Cypher peuvent être plus abstraites , c'est à diredisons qu'un (:Tableau:Workbook)
Remplit (:Tableau:Dashboard)
alors de trouver les tableaux de bord que le classeur Remplit une interrogerait,
MATCH (s:Tabeau:Workbook)-[:POPULATES]->(t:Tableau:Dashboard)
WHERE s.uuid = <UUID>
RETURN t
qui est assez transparente, mais ce qui suit serait plus optimale du point de vue de la performance, quoique moins transparente étant donné que il est pas évident à l'utilisateur quel type de noeud s
est,
MATCH (s:Entity)-[:POPULATES]->(t:Tableau:Dashboard)
WHERE s.uuid = <UUID>
RETURN t
Merci. Je ne savais pas que l'on pouvait appliquer l'utilisation de l'index. Je me rends compte que j'ai des index qui se chevauchent, mais est-ce une mauvaise chose? De cette façon, je peux toujours tirer parti d'un index en faisant correspondre n'importe quel type de nœud, c'est-à-dire 'MATCH (n: Dashboard) UTILISATION INDEX n: Dashboard (uuid)' sauf lorsque je ne suis pas certain du type. – John
np. Compte tenu de la petite taille de votre base de données, le fait de conserver des index qui se chevauchent ne va certainement pas poser de problème. Si vous avez une analyse de rentabilisation pour cela et que cela l'emporte sur la surcharge supplémentaire de maintenir un index sur un attribut particulier deux fois alors je dis aller le chercher. –