从CSV文件导入Neo4j中的目录/文件结构的好方法是什么?

时间:2016-07-28 15:31:44

标签: csv import neo4j cypher directory-structure

我希望使用Neo4j将大量文件名导入图形数据库。数据来自外部源,可在CSV文件中使用。我想从数据中创建一个树结构,这样我可以在以后轻松地“导航”查询中的结构(即查找某个目录下的所有文件,所有文件出现在多个目录中等)。

因此,给出示例输入:

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

我想创建以下图表:

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

(其中每个节点标签实际上是一个属性,例如路径:)。

使用固定数量的目录级别时,我已经能够达到预期的效果;例如,当每个文件的深度为三级时,我可以创建一个包含4列的CSV文件:

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

使用密码查询导入它:

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)

但是我希望有一个适用于任何级别的子目录(以及一个数据集中的级别组合)的通用解决方案。请注意,如果需要,我可以预处理输入,因此我可以在输入CSV文件中创建任何所需的结构。

我看过要点或插件,但似乎找不到有用的东西。我想/希望我能用split()函数做一些事情,即使用split('/',row.path)获取路径元素列表,但我不知道如何处理这个列表一系列MERGE运营。

1 个答案:

答案 0 :(得分:1)

这是第一次更广泛的切入。

前提是您可以将完全限定的路径拆分为组件,然后使用它的每个组件来拆分路径,以便为较大路径的每个单独组件构建完全限定的路径。使用此键作为合并项目的键,并在合并后设置单个组件。如果某些东西不是根级别,那么找到单个组件的父级并创建回到它的关系。如果完全限定路径中存在重复的组件名称,则会中断。

首先,我首先在fq_path

上创建唯一性约束
create constraint on (c:Component) assert c.fq_path is unique;

这是加载声明。

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 *

如果要区分文件和文件夹,可以在此处运行一些查询,以便在相应节点上设置另一个标签。

查找文件并将其设置为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

找到文件夹并将其设置为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