前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >3分钟将10M Stack Overflow导入Neo4j

3分钟将10M Stack Overflow导入Neo4j

作者头像
轻吻晴雯
发布2018-05-15 15:01:39
6.5K1
发布2018-05-15 15:01:39
举报
文章被收录于专栏:杂文共赏杂文共赏

我想演示如何将Stack Overflow快速导入到Neo4j中。之后,您就可以通过查询图表以获取更多信息,然后可以在该数据集上构建应用程序。如果你愿意,我们有一个运行着的(只读)Neo4j服务器,其数据在这里提供

我想先说的是:祝贺Stack Overflow,因为它非常棒和服务了许多人。他们刚刚宣布,在他们的网站上有超过一千万个编程问题被回答。(#SOreadytohelp成为了Twitter上的一个标签,类似于微博话题)

如果没有Stack Overflow,围绕Neo4j的许多问题可能永远不会被问到和回答。我很高兴我们开始摆脱Google Groups。

Stack Overflow上的Neo4j社区增长很快,问题量也很大。

图片示意
图片示意

将Stack Overflow数据导入Neo4j

将数百万Stack Overflow问题,用户,答案和意见导入Neo4j是我的一个目标。让我无法集中注意做这件事的原因是,我还要回答社区板块上8,200多个Neo4j问题

两个星期前,DamienLinkurious通过Slack channel联系了我。他询问了Neo4j的导入性能,以将整个Stack Exchange数据转储到Neo4j。

经过快速讨论后,我建议他使用Neo4j的CSV导入工具,因为转储只包含以XML格式的关系表,所以非常适合此任务。

关系表
关系表

所以Damien编写了一个小的Python脚本从XML中提取CSV文件,并使用必要的头文件neo4j-import工具完成了从巨大表格中创建图表的繁重工作。您可以在这里找到脚本和说明。

导入较小的Stack Exchange社区数据只需要几秒钟。令人惊讶的是,带有用户,问题和答案的完整Stack Overflow需要80分钟时间才能转为CSV,然后只需3分钟即可在带有SSD的普通笔记本电脑上导入Neo4j。

以下是我们的步骤:

下载Stack Exchange转储文件

首先,我们将Stack Overflow社区Internet归档文件(总共11 GB)下载到一个目录中:

  • 7.3G stackoverflow.com-Posts.7z
  • 576K stackoverflow.com-Tags.7z
  • 154M stackoverflow.com-Users.7z

如果需要,其他数据可以单独导入:

  • 91z stackoverflow.com-Badges.7z
  • 2.0G stackoverflow.com-Comments.7z
  • 36M stackoverflow.com-PostLinks.7z
  • 501M stackoverflow.com-Votes.7z

解压.7z文件

代码语言:txt
复制
for i in  * . 7z ;  do 7za - y - oextracted x $i ; 完成

这将文件解压缩到

extracted

一个目录,需要20分钟,需要66GB磁盘空间。

克隆Damien的GitHub存储库

下一步是克隆Damien的GitHub:

代码语言:txt
复制
git clone https://github.com/mdamien/stackoverflow - neo4j

注意:该命令使用Python 3,因此您必须安装

xmltodict

代码语言:txt
复制
sudo apt - get install python3 - setuptools
easy_install3 xmltodict

运行XML-to-CSV转换程序

之后,我们进行XML到CSV的转换。

代码语言:txt
复制
python3 to_csv . py extracted

转换在我的系统上运行了80分钟,9.5GB的CSV文件被压缩到3.4G。

这是导入到Neo4j中的数据结构。CSV文件的标题行显示不同的属性。

节点:

代码语言:txt
复制
posts . csv
postId : ID ( Post ) , title , postType : INT , createdAt , score : INT , views : INT , 
answers : INT , comments : INT , favorites : INT , updatedAt , body

users . csv userId : ID ( User ) , name , reputation : INT , createdAt , accessedAt , url , location , 
views : INT , upvotes : INT , downvotes : INT , age : INT , accountId : INT
tags . csv
tagId : ID ( Tag ) , count : INT , wikiPostId : INT

关系:

代码语言:txt
复制
posts_answers . csv : ANSWER    - >  : START_ID ( Post ) , : END_ID ( Post ) 
posts_rel . csv : PARENT_OF     - >  : START_ID ( Post ) , : END_ID ( Post ) 
tags_posts_rel . csv : HAS_TAG - >  : START_ID ( Post ) , : END_ID (Tag ) 
users_posts_rel . csv : POSTED - >  : START_ID ( User ) , : END_ID ( Post )

导入Neo4j

然后我们使用了Neo4j导入工具

neo/bin/neo4j-import

摄取文章,用户,标签及其之间的关系。

代码语言:txt
复制
. . / neo / bin / neo4j - import \
 -- into . . / neo / data / graph . db \
 -- id - type string \
 -- nodes : Post csvs / posts . csv \
 -- nodes : User csvs / users . csv \
 -- nodes : Tag csvs / tags . csv \
 --relationships : PARENT_OF csvs / posts_rel . csv \
 -- relationships : ANSWER csvs / posts_answers . csv \
 -- relationships : HAS_TAG csvs / tags_posts_rel . csv \
 -- relationships : POSTED csvs / users_posts_rel . csv

实际导入只需要3分钟,创建了一个18 GB的图形库。

代码语言:txt
复制
IMPORT DONE in 3m 48s 579ms . Imported : 
  31138559 nodes
  77930024 relationships
  260665346 properties

Neo4j配置

然后我们想要调整Neo4j的配置

conf/neo4j.properties

增加

dbms.pagecache.memory

选项为10G。编辑

conf/neo4j-wrapper.conf

提供更多的堆空间,如4G或8G。

然后我们开始使用Neo4j服务器

../neo/bin/neo4j start

添加索引

然后,我们可以选择直接在Neo4j的服务器UI或命令行中运行查询

../neo/bin/neo4j-shell

它连接到正在运行的服务器。

这里是我们在共有多少数据:

代码语言:txt
复制
neo4j - sh  ( ? ) $ match  ( n )  return  head ( labels ( n ) )  as label ,  count ( * ) ; 
+ -- -- -- -- -- -- -- -- -- - + 
| label   |  count ( * )        | 
+ -- -- -- -- -- -- -- -- --- + 
|  "Tag"   |  41719             | 
|  "User"  |  4551115           | 
|  "Post"  |  26545725          | 
+ -- -- -- -- -- -- -- -- -- - + 
3 rows

接下来,我们创建了一些索引和约束(constraints)供以后使用:

代码语言:txt
复制
create index on : Post ( title ) ; 
create index on : Post ( createdAt ) ; 
create index on : Post ( score ) ; 
create index on : Post ( views ) ; 
create index on : Post ( favorites ) ; 
create index on : Post ( answers ) ; 
create index on : Post ( score ) ;

create index on : User ( name ) ; 
create index on : User ( createdAt ) ; 
create index on : User ( reputation ) ; 
create index on : User ( age ) ;

create index on : Tag ( count ) ;

create constraint on  ( t : Tag ) assert t . tagId is unique ; 
create constraint on  ( u : User ) assert u . userId is unique ; 
create constraint on  ( p : Post ) assert p . postId is unique ;

然后我们等待索引创建完成。

代码语言:txt
复制
schema await

请注意:Neo4j作为图形数据库最初并不是为这些全局聚合查询而构建的。这就是为什么响应不是即时的。

使用Cypher进行深入了解

以下只是我们使用Cypher查询从Stack Overflow数据中收集到的一些信息:

前10名Stack Overflow用户

代码语言:txt
复制
match  ( u : User )  
with u , size (  ( u ) - [ : POSTED ] - > ( ) )  as posts order by posts desc limit 10  
return u . name , posts ; 
+ -- -- -- -- -- -- -- -- -- -- -- -- -- - + 
| u . name            | posts              | 
+ -- -- -- -- -- -- -- -- -- -- -- -- -- - + 
|  "Jon Skeet"        |  32174             | 
|  "Gordon Linoff"    |  20989             | 
|  " Darin Dimitrov"  |  20871             | 
|  "BalusC"           |  16579             | 
|  "CommonsWare"      |  15493             | 
|  "anubhava"         |  15207             | 
|  "Hans Passant"     | 15156              | 
|  "Martijn Pieters"  |  14167             | 
|  "SLaks"            |  14118             | 
|  "Marc Gravell"     |  13400             | 
+ -- -- -- -- -- -- -- -- -- -- -- -- -- - + 
10 rows
7342 ms

Jon Skeet用于提问的前5个tags

他似乎不问问题,只回答。

代码语言:txt
复制
match  ( u : User ) - [ : POSTED ] - > ( ) - [ : HAS_TAG ] - > ( t : Tag )  
where u . name =  "Jon Skeet"  
return t , count ( * )  as posts order by posts desc limit 5 ; 
+ -- -- -- -- -- -- -- -- -- ---- -- -- -- -- -- -- -- -- -- -- -- -- -- + 
| t                                       | posts | 
+ -- -- -- -- -- -- -- - - -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- + 
| Node [ 31096861 ] { tagId :"c#" }       |  14     | 
| Node [ 31096855 ] { tagId : ".net" }    |  7      | 
| Node [ 31101268 ] { tagId : ".net-4.0" }|  4      | 
| Node [ 31118174 ] { tagId : " c#-4.0" } |  4      | 
| Node [ 31096911 ] { tagId : "asp.net" } |  3      | 
+ -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- + 
10 rows
36 ms

BalusC回答的前5个tags

代码语言:txt
复制
match  ( u : User ) - [ : POSTED ] - > ( ) - [ : HAS_TAG ] - > ( t : Tag )  
where u . name =  "BalusC"  
return t . tagId , count ( * )  as posts order by posts desc limit 5 ;

+ -- -- -- -- -- -- -- -- -- -- -- -- + 
| t . tagId         | posts | 
+ -- -- -- -- -- -- -- -- -- -- -- -- + 
|  "java"          |  5      | 
|  "jsf"           |  3      | 
|  "managed-bean"  |  2      | 
|  "eclipse"       |  2      | 
| "cdi"            |  2      | 
+ -- -- -- -- -- -- -- -- -- -- -- -- + 
5 rows
23 ms

我和Darin Dimirtov的关系图标

代码语言:txt
复制
MATCH path =  allShortestPaths (
     ( u : User { name :“Darin Dimitrov” } )- [ * ] - ( me : User { name :“Michael Hunger” } )) 
RETURN path ;
Neo5j的可视化结果
Neo5j的可视化结果

马克是回答Neo4j相关问题最多的人

代码语言:txt
复制
MATCH  ( u : User ) - [ : POSTED ] - > ( answer ) < - [ : PARENT_OF ] - ( ) - [ : HAS_TAG ] - ( : Tag { tagId : "neo4j" } )  
WHERE u . name like "Mark % "  
RETURN u . name , u . reputation , u .location , count ( distinct answer ) AS answers
ORDER BY answers DESC ;

+ -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - - -- -- -- -- -- -- -- -- -- -- -- -- + 
| u . name                  | u . reputation | u . location              | answers |
+ -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - - -- -- -- -- -- -- -- -- -- -- -- -- + 
|  "Mark Needham"          |  1352          |  "United Kingdom"          |  36       | 
|  "Mark Leighton Fisher"  |  4065          | "Indianapolis, IN"         |  3        | 
|  "Mark Byers"            |  377313        |  "Denmark"                 |  2        | 
|  "Mark Whitfield"        |  899           |  < null >                  |  1        | 
|  "Mark Wojciechowicz"    |  1473          |  < null >                  |  1        | 
|  "Mark Hughes"           |  586           |  "London, UK"              |  1        | 
|  "Mark Mandel"           |  859           |  "Melbourne, Australia"    | 1        | 
|  "Mark Jackson"          |  56            |  "Atlanta, GA"             |  1        | 
+ -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - - -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- + 
8 rows
38 ms
以图形呈现的前20条路径
以图形呈现的前20条路径

历史上前5名的tags

代码语言:txt
复制
match  ( t : Tag )  
with t order by t . count desc limit 5  
return t . tagId , t . count ; 
+ -- -- -- -- -- -- -- -- -- -- -- -- + 
| t . tagId       | t . count | 
+ -- -- -- -- -- -- -- -- -- ---- -- + 
|  "javascript"  |  917772   | 
|  "java"        |  907289   | 
|  "c#"          |  833458   | 
|  "php"         |  791534   | 
|  "android"     |  710585   | 
+ -- -- -- -- - - -- -- -- -- -- -- -- + 
5 rows
30 ms

和JavaScript tag一起查询

代码语言:txt
复制
match  ( t : Tag { tagId : "javascript" } ) < - [ : HAS_TAG ] - ( ) - [ : HAS_TAG ] - > ( other : Tag )  
WITH other ,  count ( * )  as freq order by freq desc limit 5 
RETURN other . tagId , freq ; 
+ -- -- -- -- ---- -- -- -- -- -- + 
| other . tagId | freq    | 
+ -- -- -- -- -- -- -- -- -- -- -- + 
|  "jquery"     |  318868  | 
|  "html"       |  165725  | 
|  "css"        |  76259   | 
|  "php"        |  65615   | 
|  "ajax"       |  52080   | 
+ -- ---- -- -- -- -- -- -- -- -- + 
5 rows

最活跃的neo4j tag回答者

感谢所有回答Neo4j问题的人!

代码语言:txt
复制
match  ( t : Tag { tagId : "neo4j" } ) < - [ : HAS_TAG ] - ( ) 
       - [ : PARENT_OF ] - > ( ) < - [ : POSTED ] - ( u : User )  
WITH u ,  count ( * )  as freq order by freq desc limit 10 
RETURN u . name ,freq ;

+ -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - + 
| u . name                  | freq | 
+ -- -- -- -- - - -- -- -- -- -- -- -- -- -- -- - + 
|  "Michael Hunger"        |  1352  | 
|  "Stefan Armbruster"     |  760   | 
| "Peter Neubauer"         |  308   | 
|  "Wes Freeman"           |  277   | 
|  "FrobberOfBits"         |  277   | 
|  "cybersam"              |  277   | 
|  "Luanne"                |  235   | 
|  "Christophe Willemsen"  |  190   | 
|  "Brian Underwood"       |  169   | 
|  "jjaderberg"            |  161   | 
+ -- -- -- -- -- -- -- -- -- -- ---- -- -- -- - + 
10 rows
45 ms

还有哪些板块回答也活跃?

代码语言:txt
复制
MATCH  ( neo : Tag { tagId : "neo4j" } ) < - [ : HAS_TAG ] - ( ) 
      - [ : PARENT_OF ] - > ( ) < - [ : POSTED ] - ( u : User )  
WITH neo , u ,  count ( * )  as freq order by freq desc limit 10 
MATCH  ( u) - [ : POSTED ] - > ( ) < - [ : PARENT_OF ] - ( p ) - [ : HAS_TAG ] - > ( other : Tag ) 
WHERE NOT  ( p ) - [ : HAS_TAG ] - > ( neo ) 
WITH u , other , count ( * )  as freq2 order by freq2 desc 
RETURN u . name , collect ( distinct other . tagId ) [ 1 . . 5 ]  as tags ;


+ -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - - -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- + 
| u . name                  | tags                                                          | 
+ -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- + 
|  "cybersam"              |  [ "java" , "javascript" ,"node.js" , "arrays" ]                       | 
|  "Luanne"                |  [ "spring-data-neo4j" , "java" , "cypher" , "spring" ]                 | 
|  "Wes Freeman"           |  [ "go" , " node.js" , "java" , "php" ]                                  | 
|  "Peter Neubauer"        |  [ "graph" , "nosql" , "data-structures" , "java"]                     | 
|  "Brian Underwood"       |  [ "ruby-on-rails", "neo4j.rb" , "ruby-on-rails-3" , "activerecord" ]  | 
|  "Michael Hunger"        |  [ "spring-data-neo4j" , "nosql" , "cypher" , "graph-databases" ]       | 
|  "Christophe Willemsen"  |  [ "php" , "forms" , "doctrine2" , "sonata" ]                           | 
|  "Stefan Armbruster"     |  [ "groovy" , "intellij-idea" , "tomcat" , "grails-plugin" ]           | 
|  "FrobberOfBits"         |  [ "python" , "xsd" , "xml" , "django" ]                                | 
|  "jjaderberg"            |  [ "vim" , "logging" , "python" , "maven"]                             | 
+ -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - - -- ---- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- + 
10 rows
84 ms

请注意,上面的Cypher查询包含14个SQL连接的等效项。

在Linkurious Visualizer中呈现
在Linkurious Visualizer中呈现

关于Neo4j最多问题的人

代码语言:txt
复制
MATCH  ( t : Tag { tagId :'neo4j' } )< - [ : HAS_TAG ] - (: Post )< - [ : POSTED ] - ( u : User ) 
RETURN u 。名称,数(* ) 作为计数
ORDER BY count DESC LIMIT 10 ;

+ - - - - - - - - - - - - + 
| c 。名称          | count | 
+ - - - - - - - - - - - - + 
|  “LDB”           |  39     | 
|  “deemeetree”    |  39     | 
|  “alexanoid”     |  38     | 
|  “MonkeyBonkey”  |  35     |
|  “Badmiral”      |  35     | 
|  “Mik378”        |  27     | 
|  “Kiran”         |  25     | 
|  “红魔”          |  24     | 
|  “raHul”         |  23     | 
|  “Sovos”         |  23     | 
+ - - - - - - - - - - - - + 
10 rows
42 ms

Py2neo tag的最佳答案

代码语言:txt
复制
MATCH  ( t : Tag { tagId : 'neo4j' } ) < - [ : HAS_TAG ] - ( : Post ) < - [ : POSTED ] - ( u : User ) 
RETURN u . name , count ( * )  as count
ORDER BY count DESC LIMIT 10 ;

+ -- -- -- -- -- -- -- -- -- -- -- -- + 
| c . name          | count | 
+ -- -- -- -- -- -- -- -- -- -- -- -- + 
|  "LDB"           |  39     | 
|  "deemeetree"    |  39     | 
|  "alexanoid"     |  38     | 
|  "MonkeyBonkey"  |  35     |
|  "Badmiral"      |  35     | 
|  "Mik378"        |  27     | 
|  "Kiran"         |  25     | 
|  "red-devil"     |  24     | 
|  "raHul"         |  23     | 
|  "Sovos"         |  23     | 
+ -- -- - - -- -- -- -- -- -- -- -- -- + 
10 rows
 42 ms

哪些用户回答自己的问题

这个全局图形查询需要一点时间,因为它关系到数据库中的2亿条路径,大约60秒后它会返回。

如果您只想在4.5M用户的子集上执行此操作,则可以添加过滤条件,例如在reputation上。

代码语言:txt
复制
MATCH  ( u : User ) WHERE u . reputation >  20000 
MATCH  ( u ) - [ : POSTED ] - > ( question ) - [ : ANSWER ] - > ( answer ) < - [ : POSTED ] - ( u ) 
WITH u , count ( distinct question ) AS questions
ORDER BY questions DESC LIMIT 5 
RETURN u . name , u . reputation , questions ;

+ -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - + 
| u . name            | u . reputation | questions | 
+ -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- ---- -- -- -- - + 
|  "Stefan Kendall"  |  31622         |  133        | 
|  "prosseek"        |  31411         |  114        | 
|  "Cheeso"          |  100779        |  107        | 
|  "Chase Florell"   |  21207         |  99         | 
|  " Shimmy"         |  29175         |  96         | 
+ -- -- -- -- -- -- -- -- -- -- -- ---- -- -- -- -- -- -- -- -- -- - + 
5 rows
10 seconds

更多信息

我们很高兴为您提供Stack Overflow的图形数据库:

如果您想了解其他方式来导入或可视化Neo4j中的Stack Overflow问题,请查看以下博客文章:

再次感谢所有发布和回答Neo4j问题的人。你是那些让Neo4j社区成长的人,如果没有你,本文的乐趣将大打折扣。

回到Stack Overflow的1000万个问题,感谢您使用关于Neo4j和Cypher的#Soreadytohelp话题。

如果你发现这个数据集的其他有趣的问题和答案。只需发送电子邮件至content#neo4j.com。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 将Stack Overflow数据导入Neo4j
    • 下载Stack Exchange转储文件
      • 解压.7z文件
        • 克隆Damien的GitHub存储库
          • 运行XML-to-CSV转换程序
            • 导入Neo4j
              • Neo4j配置
                • 添加索引
                • 使用Cypher进行深入了解
                  • 前10名Stack Overflow用户
                    • Jon Skeet用于提问的前5个tags
                      • BalusC回答的前5个tags
                        • 我和Darin Dimirtov的关系图标?
                          • 马克是回答Neo4j相关问题最多的人
                            • 历史上前5名的tags
                              • 和JavaScript tag一起查询
                                • 最活跃的neo4j tag回答者
                                  • 还有哪些板块回答也活跃?
                                    • 关于Neo4j最多问题的人
                                      • Py2neo tag的最佳答案
                                        • 哪些用户回答自己的问题
                                        • 更多信息
                                        相关产品与服务
                                        大数据
                                        全栈大数据产品,面向海量数据场景,帮助您 “智理无数,心中有数”!
                                        领券
                                        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档