2015-09-01 1 views
1

J'ai une base de données neo4j et j'utilise le mode embarqué. Il y a des millions de nœuds avec plusieurs étiquettes avec chaque nœud. Je peux obtenir tous les nœuds avec une seule étiquette commeComment obtenir des nœuds dans Neo4j embarqué avec plusieurs étiquettes?


    GlobalGraphOperations gb = GlobalGraphOperations.at(graphDb); 
    ResourceIterable iterable = gb.getAllNodesWithLabel(DynamicLabel.label("LABEL1")); 
 

C'est très bien. Maintenant, je veux faire la même chose mais avec plusieurs étiquettes. Je veux tous les nœuds qui ont "LABEL1" et "LABEL2" et "LABEL3" et ainsi de suite.

Répondre

2

En interne Neo4j maintient un labelcanstore qui vous donne rapidement un itérateur pour tous les nœuds avec une étiquette donnée - mais il n'y a pas de banque d'analyse pour la combinaison d'étiquettes. Si vous voulez trouver tous les nœuds partageant plusieurs étiquettes, la stratégie consiste à parcourir tous les nœuds pour l'étiquette «moins cher» - c'est-à-dire celui qui a le moins de nœuds - et à filtrer pour les autres étiquettes.

L'extrait de code ci-dessous utilise un essai avec-ressources et un JDK 8 lambda (n cas de < JDK8 il suffit de créer une classe implémentant Predicate Je suppose LABEL1 est l'étiquette avec le plus petit nombre nœuds.

import org.neo4j.graphdb.*; 
import org.neo4j.helpers.Predicate; 
import org.neo4j.helpers.collection.FilteringIterator; 

... 

try (ResourceIterator<Node> nodes = 
    graphDatabaseService.findNodes(DynamicLabel.label("LABEL1"))) { 

    Iterator<Node> nodeWithAllLabels = new FilteringIterator<>(nodes, 
      node -> node.hasLabel(DynamicLabel.label("LABEL2")) && 
        node.hasLabel(DynamicLabel.label("LABEL3")) 
    ); 

    // do stuff with nodeWithAllLabels 
} 
.
+0

Permettez-moi vérifier cela avec Predicate. Cela ressemble à une sorte de callbacks. – Rajan

+0

Comment implémenter mon propre prédicat? J'ai le sentiment que le prédicat devrait parcourir à chaque fois le reste des nœuds. Y a-t-il une traversée que je puisse faire à partir d'un nœud de référence connu? Le graphe est tel que les étiquettes sont les arêtes du graphe pondéré non orienté. – Rajan

+0

Mise à jour: J'ai utilisé le filtre avec prédicat, et trouvé qu'il a fallu environ 300 ms pour parcourir plus de 5 millions de nœuds. Avez-vous des suggestions sur la façon de réduire cela à moins de 10 ms? La mise en cache est-elle nécessaire pour l'obtenir ou peu importe? – Rajan

2

Vous pourriez execute a Cypher query Voici un extrait de code:

Map<String, Object> params = new HashMap<String, Object>(); 
params.put("required", Arrays.asList("LABEL1", "LABEL2", "LABEL3")); 
String query = "MATCH (n) WHERE ALL(x IN {required} WHERE x IN LABELS(n)) RETURN n"; 
Result result = db.execute(query, params); 

[UPDATE]

Cependant, la requête ci-dessus parcourrait tous les nœuds, ce qui n'est pas performant.

Merci à la suggestion de @ StefanArmbruster, nous pouvons faire la requête ci-dessus plus efficace en spécifiant le moins l'étiquette probable dans la clause MATCH (pour tirer profit de l'indice d'étiquette de nœud interne):

Map<String, Object> params = new HashMap<String, Object>(); 
params.put("otherLabels", Arrays.asList("LABEL2", "LABEL3")); 
String query = "MATCH (n:LABEL1) WHERE ALL(x IN {otherLabels} WHERE x IN LABELS(n)) RETURN n"; 
Result result = db.execute(query, params); 
+0

Cela semble moche. Je préfère jouer avec l'API. Je ne fais pas une seule requête, tout devrait être intégré. – Rajan

+0

Ce code * est * pour interroger un DB incorporé. – cybersam

+1

l'instruction de chiffrement ci-dessus va en fait parcourir tous les nœuds et ensuite appliquer le filtre. Vous pouvez être plus efficace en faisant la correspondance sur le label "le moins cher" et appliquer le filtre sur ce petit ensemble: 'MATCH (n: LABEL1) OERE ALL (x dans [" LABEL2 "," LABEL3 "] WHERE x dans les libellés (n)) RETURN n' –