图中的边是由两部分组成的,论文与作者的联系,以及论文与会议的联系。这里使用Union操作,将描述两种对应关系的表合并起来。需要注意的是,合并时需要两个数据表有相同的数据列名和类型。具体实现代码如下:
BatchOperator <?> edges = new UnionBatchOp().linkFrom( paper_author.select("paper_id AS source_id, author_id AS target_id"), paper_conf.select("paper_id AS source_id, conf_id AS target_id") );
使用DeepWalk计算Embedding的代码如下,直接将边的数据接入DeepWalk组件,设置边的起始节点列名称与目标节点列名称;如果需要将图看作是无向图,可以通过设置参数IsToUndigraph为ture实现;指定生成向量的维度(VectorSize),游走路径的长度(WalkLength),每个节点作为游走的初始节点,生成游走路径的数量(WalkNum);参数NumIter是对训练数据迭代训练的次数。训练出的Embedding模型会被保存到文件路径TEMP_DIR + DEEPWALK_EMBEDDING。
edges .link( new DeepWalkBatchOp() .setSourceCol("source_id") .setTargetCol("target_id") .setIsToUndigraph(true) .setVectorSize(100) .setWalkLength(10) .setWalkNum(20) .setNumIter(1) ) .link( new AkSinkBatchOp() .setFilePath(DATA_DIR + DEEPWALK_EMBEDDING) .setOverwriteSink(true) ); BatchOperator.execute();
使用Node2Vec组件与使用DeepWalk组件类似,不同的是需要设置参数P和Q,关于这两个参数的介绍详见前面Node2Vec算法的介绍部分。具体代码如下,训练出的Embedding模型会被保存到文件路径TEMP_DIR + NODE2VEC_EMBEDDING。
edges .link( new Node2VecBatchOp() .setSourceCol("source_id") .setTargetCol("target_id") .setIsToUndigraph(true) .setVectorSize(100) .setWalkLength(10) .setWalkNum(20) .setP(2.0) .setQ(0.5) .setNumIter(1) ) .link( new AkSinkBatchOp() .setFilePath(DATA_DIR + NODE2VEC_EMBEDDING) .setOverwriteSink(true) ); BatchOperator.execute();
最后,我们来尝试MetaPath2Vec算法,需要事先构造一个映射表,每个节点赋予一个类型值,论文节点对应类型“P”、作者节点对应类型“A”、会议节点对应类型“C”。并使用UnionBatchOp组件将三部分数据合并在一起。
BatchOperator id_type = new UnionBatchOp() .linkFrom( paper.select("paper_id AS node_id, 'P' AS node_type"), id_author.select("author_id AS node_id, 'A' AS node_type"), id_conf.select("conf_id AS node_id, 'C' AS node_type") );
MetaPath2VecBatchOp组件需要设置参数MetaPath,就是由节点类型表示的路径模版,模版的最后一个类型与第一个类型相同,相当于尾首连接,重复此模式。譬如:“APA”就表示路径以类型为“A”的节点开始,然后选择的是类型“P”的节点,随后是类型“A”节点,第四个节点类型为“P”……。对应到路径的实际意义,选择一个作者1,选择作者1的一篇论文1,在论文1的共同作者中选择作者2,然后选择作者2的一篇论文2,在论文2的共同作者中选择作者3……。相比前两种算法,多一个节点类型的数据输入,并在参数中设置节点列名VertexCol和类型列名TypeCol,如下面代码所示:
new MetaPath2VecBatchOp() .setMetaPath("APA,APCPA") .setVertexCol("node_id") .setTypeCol("node_type") .setSourceCol("source_id") .setTargetCol("target_id") .setIsToUndigraph(true) .setVectorSize(100) .setWalkLength(10) .setWalkNum(20) .setNumIter(1) .linkFrom(edges, id_type) .link( new AkSinkBatchOp() .setFilePath(DATA_DIR + METAPATH2VEC_EMBEDDING) .setOverwriteSink(true) ); BatchOperator.execute();