2016-07-28 3 views
2

Je cherche à importer beaucoup de noms de fichiers dans une base de données graphique, en utilisant Neo4j. Les données proviennent d'une source externe et sont disponibles dans un fichier CSV. Je voudrais créer une structure arborescente à partir des données, afin que je puisse facilement «naviguer» dans la structure dans les requêtes plus tard (c'est-à-dire trouver tous les fichiers sous un certain répertoire, tous les fichiers se trouvant dans plusieurs répertoires etc.Quelle est la bonne façon d'importer une structure de répertoire/fichier dans Neo4j à partir du fichier CSV?

Ainsi, compte tenu de l'entrée exemple:

/foo/bar/example.txt 
/bar/baz/another.csv 
/example.txt 
/foo/bar/onemore.txt 

J'aimerais le créer le graphique suivant:

(/) <-[:in]- (foo) <-[:in]- (bar) <-[:in]- (example.txt) 
             <-[:in]- (onemore.txt) 
     <-[:in]- (bar) <-[:in]- (baz) <-[:in]- (another.csv) 
     <-[:in]- (example.txt) 

(où chaque étiquette de noeud est en fait un attribut, par exemple chemin :).

J'ai réussi à obtenir l'effet désiré en utilisant un nombre fixe de niveaux de répertoires; par exemple lorsque chaque fichier est à trois niveaux de profondeur, je pourrais créer un fichier CSV avec 4 colonnes:

dir_a,dir_b,dir_c,file 
foo,bar,baz,example.txt 
foo,bar,ban,example.csv 
foo,bar,baz,another.txt 

et l'importer en utilisant une requête Cypher:

LOAD CSV WITH HEADERS FROM "file:///sample.csv" AS row 
    MERGE (dir_a:Path {name: row.dir_a}) 
    MERGE (dir_b:Path {name: row.dir_b}) <-[:in]- (dir_a) 
    MERGE (dir_c:Path {name: row.dir_c}) <-[:in]- (dir_b) 
    MERGE  (:Path {name: row.file}) <-[:in]- (dir_c) 

Mais je voudrais avoir une solution générale qui fonctionne pour n'importe quel niveau de sous-répertoires (et combinaisons de niveaux dans un ensemble de données). Notez que je suis en mesure de pré-traiter mon entrée si nécessaire, afin que je puisse créer une structure souhaitable dans le fichier CSV d'entrée.

J'ai regardé des gists ou des plugins, mais je n'arrive pas à trouver quelque chose qui fonctionne. Je pense/espère que je devrais être capable de faire quelque chose avec la fonction split(), à savoir utiliser split ('/', row.path) pour obtenir une liste d'éléments de chemin, mais je ne sais pas comment traiter cette liste en une chaîne d'opérations MERGE.

Répondre

1

Voici une première coupe à quelque chose de plus généralisé. La prémisse est que vous pouvez diviser le chemin d'accès complet en composants, puis utiliser chaque composant pour diviser le chemin afin que vous puissiez structurer le chemin qualifié complet pour chaque composant du chemin le plus grand. Utilisez-le comme clé pour fusionner des éléments et définir le composant individuel après leur fusion. Dans le cas où quelque chose n'est pas le niveau racine, recherchez le parent d'un composant individuel et créez-lui la relation. Cela se décomposera s'il y a des noms de composants en double dans un chemin qualifié complet.

Tout d'abord, j'ai commencé en créant une contrainte d'unicité sur fq_path

create constraint on (c:Component) assert c.fq_path is unique; 

Voici la déclaration de charge.

load csv from 'file:///path.csv' as line 
with line[0] as line, split(line[0],'/') as path_components 
unwind range(0, size(path_components)-1) as idx 
with case 
     when idx = 0 then '/' 
    else 
     path_components[idx] 
    end as component 
    , case 
     when idx = 0 then '/' 
    else 
     split(line, path_components[idx])[0] + path_components[idx] 
    end as fq_path 
    , case 
     when idx = 0 then 
     null 
     when idx = 1 then 
     '/' 
    else 
     substring(split(line, path_components[idx])[0],0,size(split(line, path_components[idx])[0])-1) 
    end as parent 
    , case 
     when idx = 0 then 
     [] 
     else 
     [1] 
    end as find_parent 
merge (new_comp:Component {fq_path: fq_path}) 
set new_comp.name = component 
foreach (y in find_parent | 
    merge (theparent:Component {fq_path: parent}) 
    merge (theparent)<-[:IN]-(new_comp) 
)  
return * 

Si vous voulez faire la différence ici entre les fichiers et les dossiers sont quelques questions que vous pouvez exécuter ensuite pour définir une autre étiquette sur les noeuds respectifs.

Trouver les fichiers et les définir comme File

// find the last Components in a tree (no inbound IN) 
// and set them as Files 
match (c:Component) 
where not (c)<-[:IN]-(:Component) 
set c:File 
return c 

Trouver les dossiers et les définir comme Folder

// find all Components with an inbound IN 
// and set them as Folders 
match (c:Component) 
where (c)<-[:IN]-(:Component) 
set c:Folder 
return c