目前为止,网络上能找到的关于large attributed graph的数据集还非常少。更多的是单纯的关系图,这样就缺少了必要的属性数据。所以我们需要在获得原始数据后,再经过一系列数据计算处理得到我们所要的图数据。下面我将提供已经处理好了的三组完整属性图数据的下载链接,同时利用前面讲过的PyHuksy来介绍其中的一组数据的生成过程。
下面要介绍的是第3组数据DBLP_Title_Graph的生成过程。这组生成数据集并不大,顶点数在百万级,每一顶点代表一位作者;边数是千万级,是对应的合作作者的列表;同时通过处理得到每位作者所发表的文章名字中出现词频前20的单词作为每位作者的特性。
原始数据是一个XML格式的文件,在根节点下面的每个子节点存储的是一篇文章的相关信息,包括作者、标题、年份、链接等等。在vim中截取部分数据,格式如下:
可以看到关于Object-oriented software patterns for engineering design standards processing这篇文章,一共有三位合作作者,分别是Mustafa Kamal Badrah,Iain MacLeod和Bimal Kumar。我们有上百万个这样的节点。
再来看看最后生成的一条数据的格式:
“2576640\tsoft;fingertip;modeling;based;sensor;rheological;model;human;force;deformation;tactile;simulation;parameter;identification;axis;three;systems;object;mri;method\t16 1574320 2268359 1708353 1529432 1202998 1664588 1836295 2857847 2490268 1402803 2322311 1137987 2617558 1049528 2781111 2205572”
我们最后已经将作者名字ID化,每个作者名字以一串数字代替。如上的2576640,可以从生成的Index_Name.txt中查得对应的作者是Zhongkui Wang;紧接的”soft;fingertip;modeling;based;sensor;rheological;model;human;force;deformation;tactile;simulation;parameter;identification;axis;three;systems;object;mri;method”是由Zhongkui Wang发表的所有文章标题中提取出来的前20个最高频出现的单词;后面的16及接下来的一系列数字则代表对应于顶点2576640的边数及各边的ID号,即所有合作过的作者。
思路:
第一步,从XML中提取信息,保存成json格式。由于XML文档比较大,直接读入遍历会占用特别大的内存,所以我们使用ElementTree提供的iterparse来处理XML流:
import xml.etree.ElementTree as ET
num = 0
for event,child in ET.iterparse('dblp-2017-03-03.xml'):
if child.attrib.has_key('mdate'):
if num%30000==0:
if num >1:
fh.close()
fh = open('./2017-03-03_'+str(num/30000),'a')
print str(num/30000)+'\n'
dd = {'author':[],'title':''}
for cc in child:
if cc.tag=='author':
dd['author'].append(cc.text)
if cc.tag =='title':
dd['title']=cc.text
break
dd = json.dumps(dd)
fh.write(dd+'\n')
child.clear()
num += 1
运行结束,得到上百个文件,其中每个文件包含30000篇文章数据,文件格式如下图所示:
第二步,将文件上传到HDFS上,下面我们将使用PyHusky上建立每篇文章和作者之间的映射关系。若是不熟悉PyHusky的使用,可以参考PyHusky接口功能及实例介绍。
开启PyHusky交互式界面后,读入数据:
#获取作者和文章映射
def author_title(x):
res = []
for dt in x['author']:
res.append((dt,x['title']))
return res
#将同一著者的所有文章的title切割并剔除无关单词(统计全部单词中前100高频中的弱意义单词),保存到words
import re
words_not_in = set(['home','page','of','for','and','a','in','the','on','with','to','using','an','from','by','via','as','over','at'])
def single_words(x):
words = []
for i in x[1]:
wds = re.sub('[\W]',' ',i.lower()).split()
wds = list(set(wds).difference(words_not_in))
wds = [xx for xx in wds if len(xx)>2]
words.extend(wds)
return [x[0],words]
#计算每个作者的单词列表中的每个单词出现的频率,得到最高频率的前n个单词
def cal_topn(x,n):
#若单词数本身少于需要的n,则全部囊括
if len(list(set(x[1])))<=n:
return (x[0],list(set(x[1])))
else:
dic_tmp = {}
for i in x[1]:
if dic_tmp.has_key(i):
dic_tmp[i]+=1
else:
dic_tmp[i] = 1
list_tmp = list(dic_tmp.iteritems())
list_tmp = [(sec,fir) for (fir,sec) in list_tmp]
list_tmp.sort(reverse=True)
list_res = [item[1] for item in list_tmp[:n]]
return (x[0],list_res)
#得到每个作者和从其全部文章title中提取出的作为特性的前20的高频单词
author_keywords = flat_map(lambda x: author_title(x) ).group_by_key().map(lambda x: single_words(x)).map(lambda x:cal_topn(x,20))
承上,计算得到的author_keywords的结果如下:
将名字ID化,结果author_keywords_index,查看一个元素信息:
author_keywords_index.topk(1)
#result,100000为一个作者名字的代码:
[[1000000,
[u'unification',
u'solving',
u'theories',
u'proofs',
u'modulo',
u'linear',
u'diophantine',
u'termination',
u'systems',
u'shostak',
u'rewriting',
u'ground',
u'equations',
u'completion',
u'certified',
u'automated',
u'variables',
u'rewrite',
u'reduction',
u'proving']]]
第三步,根据每篇文章的作者关系,进行两两排列,得出合作关系,生成属性图的边:
#著作者两两排列
def author_pair(x):
author_pairs = []
for i in x:
for j in x:
author_pairs.append((i,j))
return author_pairs
#汇集合著者
def author_coauthors(x):
a = x[0]
b = x[1]
b = list(set(b))
b.remove(a)
return (a,b)
author_coauthors = line.flat_map(lambda x: user_pair(x['author']) ).group_by_key().map(lambda x:hh(x)).cache()
#topk(k)查看前k个元素,下面k=2,仅查看两条信息:
author_coauthors.topk(2)
#结果,每一条代表一个作者和其合著者的列表
[[u"'Maseka Lesaoana",
[u'Chris N. Potts',
u'Philimon Nyamugure',
u'Nicholas G. Hall',
u'Elias Munapo',
u'Santosh Kumar']],
[u'(Max) Zong-Ming Cheng',
[u'Joshua S. Yuan',
u'Joseph J. Bozell',
u'Nicole Labbe',
u'Crissa Doeppke',
u'Weibing Shi',
u'Peng Gao',
u'Jason N. Burris',
u'Xia Ye 0002',
u'Zhanyou Xu',
u'Kristen L. Reichel',
u'Dandan Zhang',
u'Xiaohan Yang',
u'Robert W. Sykes',
u'Nathan R. Stewart',
u'Xin Zhou',
u'Jun Hu',
u'Gerald A. Tuskan',
u'C. Neal Stewart Jr.',
u'Ryan D. Syrenne',
u'Mark Davis',
u'Douglas G. Hayes',
u'Bin Cai']]]
#ID化,以数字代表名字,结果:
author_coauthors_index.topk(2)
[[1000000,
[1352314,
1454594,
2799078,
2415256,
2690687,
2864461,
2288070,
1889987,
1706887,
2386705,
2562332,
1770439,
1804282,
1936839,
2552213,
2777103,
1217400,
2640418,
1340499,
2404711,
2775204,
1966581,
1583768,
2502194]],
[1000001, [2681706, 2361444, 1010469, 2648067, 1464501, 1707186]]]
最后,整合上述第二步得到的author_keywords_index和第三步得到的author_coauthors_index,得到最终结果:
def to_keywords_str(x):
if len(x[1])==0:
return (x[0],'0')
else:
re s = ''
for i in range(len(x[1])):
if i==0:
res = x[1][i]
else:
res += ';'+x[1][i]
return (x[0],res)
#将keywords列表转化成str
author_keywords_str=author_keywords_index.map(lambda x: to_keywords_str(x))
#调用concat()和group_by_key(),将同一作者的特性keywords及合著者coauthors整合到一起:
author_comb=author_coauthors_index.concat(author_keywords_str).group_by_key()
#连接两边数据
def get_result(x):
keywords = ''
coauthors = ''
if type(x[1][0]) is not list:
keywords = '\t'+x[1][0]+'\t'
coauthors = str(len(x[1][1]))
for au in x[1][1]:
coauthors += ' '+str(au)
else:
keywords = '\t'+x[1][1]+'\t'
coauthors = str(len(x[1][0]))
for au in x[1][0]:
coauthors += ' '+str(au)
return str(x[0])+keywords+coauthors
#将最终结果写到'/haipeng/hongzhi/dblp/result_final'
author_comb.map(lambda x: get_result(x) ).write_to_hdfs('/haipeng/hongzhi/dblp/result_final')
我们查看最后结果,格式如下:
#读入数据,并展示前5个元素,即5位作者的数据:
ph.env.load('/haipeng/hongzhi/dblp/result_final').topk(5)
result:
[‘1000000\tunification;solving;theories;proofs;modulo;linear;diophantine;termination;systems;shostak;rewriting;ground;equations;completion;certified;automated;variables;rewrite;reduction;proving\t24 1352314 1454594 2799078 2415256 2690687 2864461 2288070 1889987 1706887 2386705 2562332 1770439 1804282 1936839 2552213 2777103 1217400 2640418 1340499 2404711 2775204 1966581 1583768 2502194’,
‘1000001\tlogic;functional;semantics;systems;programming;programs;time;rewriting;narrowing;functions;constructor;choice;call;plural;non;singular;deterministic;typing;types;type\t6 2681706 2361444 1010469 2648067 1464501 1707186’,
‘1000002\tevaluation;editorial;partial;cps;transformation;abstract;semantics;machines;directed;type;lambda;continuations;syntactic;between;style;reduction;normalization;delimited;back;simple\t63 2162240 1180224 1010717 1601704 2371746 2301354 1043174 2721497 2067024 2034082 1539031 1192503 2815871 2668539 2547009 2637240 1454558 1097502 1973060 1823304 1084748 2014370 2002377 1042863 1401289 1359924 2424795 1423125 1234921 2299133 1954036 1624493 2531246 2099227 1349790 2034392 2013150 1213622 2506239 1528201 2869952 2776385 2587669 1317166 2890148 2491135 1875758 2684818 1496105 2362764 2553989 1623552 1129591 1972713 2048008 2815870 2332926 1180226 2055398 1265417 1549061 1411744 1728016’,
‘1000003\tparticipatory;game;serious;design;conservation;biodiversity;support;management;experience;decision;agent;user;training;social;simulations;simparc;role;protected;project;playing\t12 1908499 2403796 1200546 2870923 1317758 1077716 1189960 1876139 2382216 1086432 1003939 2705721’,
‘1000004\tsector;training;interaction;natural;simulator;electricity;atrevee;procedure;use;interaction;natural;enrich;telemedicine;experience;user;systems\t5 2586342 2291542 1182451 1643771 2735369’]