APP下载

基于Neo4j的个性化Pagerank演算法文章推荐系统实践

消息来源:baojiabao.com 作者: 发布时间:2026-05-11

报价宝综合消息基于Neo4j的个性化Pagerank演算法文章推荐系统实践

新版的Neo4j图形算法库(algo)中增加了个性化Pagerank的支援,我一直想找个有意思的应用来验证一下此算法效果。最近我看Peter Lofgren的一篇论文《高效个性化Pagerank算法》(Efficient Algorithms for Personalized PageRank)(https://arxiv.org/pdf/1512.04633.pdf),在论文中,有一个比较有趣的示例:

我们想在论文引用网络中进行个性化搜寻的尝试,但是要怎样设定个性化PageRank的引数,才能得到不同的排序结果?论文引用资料采用Citeseer检索中开放的。我们计划建立一个论文查询应用,使用者输入一个关键词和一个作者名称,得到所有包含此关键词的论文,排序是从输入作者的角度去考虑。对于每一位作者,其所有论文都给以相同的权重,然后再使用个性化PageRank对关键词搜寻出来的论文进行排序。例如,关键词“entropy”对于不同的作者有不同的含义,这样,我们就可以从不同的角度去比较关键词“entropy”搜寻出来的结果。

接下来,我们就使用Neo4j来重建这个场景

前提

Neo4jNeo4j影象库(algo)Neo4jAPOC库Graphaware的NLP外挂我们需要下载所有外挂并做如下配置:

dbms.unmanaged_extension_classes=com.graphaware.server=/graphaware

com.graphaware.runtime.enabled=true

com.graphaware.module.NLP.1=com.graphaware.nlp.module.NLPBootstrapper

dbms.security.procedures.whitelist=ga.nlp.*,algo.*,apoc.*

dbms.security.procedures.unrestricted=apoc.*,algo.*

apoc.import.file.enabled=true

图模型

从上图可见,我们的模型很简单,模型里的结点分为两类,标签分别为Author和Article,每个Author节点有一个或多个到Article节点的AUTHOR关系,同时,Article节点与其他Article节点还有REFERENCE关系。

为了优化请求,此图模型还需要定义一些索引。分别在Article节点的index属性和Author节点的name属性上建立唯一约束。

CALL apoc.schema.assert(

{},

{Article:[\'index\'],Author:[\'name\']})

资料汇入

我们使用aminer.org网站上提供的论文引用资料(https://static.aminer.cn/lab-datasets/citation/dblp.v10.zip),这是此资料的最新版本,最重要的是他以json方式储存的。

关于此数据库的更多资讯可以看这篇论文《ArnetMiner:学术社交网络的提取与挖掘》(http://keg.cs.tsinghua.edu.cn/jietang/publications/KDD08-Tang-et-al-ArnetMiner.pdf)

译者言:《ArnetMiner:学术社交网络的提取与挖掘》一文的第一作者是清华大学唐杰教授

将资料汇入到Neo4j中分为两步,第一步汇入所有论文及他们的作者,第二步建立这些论文的引用关系。

汇入资料我们使用 apoc.periodic.iterate 进行批量汇入。

汇入论文及作者

CALL apoc.periodic.iterate(

\'UNWIND ["dblp-ref-0.json","dblp-ref-1.json","dblp-ref-2.json","dblp-ref-3.json"] as file

CALL apoc.load.json("file:///neo4j/import/" + file)

yield value return value\',

\'MERGE (a:Article{index:value.id})

ON CREATE SET a += apoc.map.clean(value,["id","authors","references"],[0])

WITH a,value.authors as authors

UNWIND authors as author

MERGE (b:Author{name:author})

MERGE (b)-[:AUTHOR]->(a)\'

,{batchSize: 10000, iterateList: true})

建立引用关系

CALL apoc.periodic.iterate(

\'UNWIND ["dblp-ref-0.json","dblp-ref-1.json","dblp-ref-2.json","dblp-ref-3.json"] as file

CALL apoc.load.json("file:///neo4j/import/" + file)

yield value return value\',

\'MERGE (a:Article{index:value.id})

WITH a,value.references as references

UNWIND references as reference

MERGE (b:Article{index:reference})

MERGE (a)-[:REFERENCES]->(b)\'

,{batchSize: 10000, iterateList: true})

PageRank算法

PageRank设计之初是用来分析网页重要性的。它主要考虑的是网站拥有的连线个数和质量,如一网站,从reddit首页有一个连结到它,和从我的blog有一个连结到它,那么这两个连结的结果就完全不同了。

而这样一过程很容易应用到论文的引用网络上,论文的引用可以视为一篇文章对另一篇文章投了一个“赞成”票,而哪篇文章的“赞成”票最多?这正是PageRank最擅长解决的问题。

使用PageRank算法在全球论文引用网络上可以找到在图中最重要的文章和最有影响力的文章。

执行PageRank并把结果储存到结点的属性中

CALL algo.pageRank(\'Article\', \'REFERENCES\')

通过pagerank得到最重要的文章

MATCH (a:Article)

RETURN a.title as article,

a.pagerank as score

ORDER BY score DESC

LIMIT 10

执行结果如下:

自然语言处理(NLP)

如果我们要通过关键词来推荐档案,那么就需要从图中提取关键词。这里要感谢Graphaware的NLP外挂,让这一过程非常简单,即使你完全不了解NLP算法也可以做NLP相关工作。

NLP过程将会在我们的图模型上增加一些节点和关系,具体如下图所示:

定义NLP模型

为了优化NLP处理,这里需要定义一些特殊的约束和索引。

CALL ga.nlp.createSchema()

增加处理管道

定义一些处理管道的配置,关于处理管道的更多资讯见这里(https://github.com/graphaware/neo4j-nlp#pipelines-and-components)

CALL ga.nlp.processor.addPipeline({

textProcessor: \'com.graphaware.nlp.processor.stanford.StanfordTextProcessor\',

name: \'defaultPipeline\',

threadNumber: 4

processingSteps: {tokenize: true,

ner: true,

dependency: false}})

设定预设管道

CALL ga.nlp.processor.pipeline.default(\'defaultPipeline\')

文字标注

原始的文字被拆成了单词、段落和函式。这里对文字的分析还仅仅只是一个开始。

如果想了解更多关于文字标注,推荐你看Christophe Willemsen写的这篇文章《用Neo4j和NLP外挂逆向工程书籍储存》(https://graphaware.com/neo4j/2017/07/24/reverse-engineering-book-stories-nlp.html)

CALL apoc.periodic.iterate(

"MATCH (n:Article) WHERE exists (n.title) RETURN n",

"CALL ga.nlp.annotate({text: n.title, id: id(n)})

YIELD result MERGE (n)-[:HAS_ANNOTATED_TEXT]->(result)",

{batchSize:1, iterateList:true})

关键词提取

TextRank算法是一种相对简单、无监督的文字摘要方法,其可以直接进行主题提取。它的目标就是运用检索关键词及构建词共现关系图,得到对文件具有描述性的关键短语,而PageRank算法则对词的重要性进行排序。

---取之《使用图进行高效无监督关键词提取》(https://graphaware.com/neo4j/2017/10/03/efficient-unsupervised-topic-extraction-nlp-neo4j.html)

CALL apoc.periodic.iterate(

"MATCH (a:AnnotatedText) RETURN a",

"CALL ga.nlp.ml.textRank({annotatedText: a}) YIELD result

RETURN distinct \'done\' ",

{batchSize:1,iterateList:true}

获取文章标题中出现次数最多的10个关键词

MATCH (k:Keyword)-[:DESCRIBES]->()

WHERE k.numTerms > 1

RETURN k.value as Keyphrase,

count(*) AS n_articles

ORDER BY n_articles DESC

LIMIT 10

结果如下:

最基本的文章推荐

如果你跟着本文一步一步执行下来,那么你现在已经有了一个最基本的基于PageRank分数和NLP关键词提取的文章推荐系统。

关键词“social networks”的前十推荐文章

MATCH (k:Keyword)-[:DESCRIBES]->()WHERE k.value = "social networks"

RETURN a.title as title, a.pagerank as p

ORDER BY p DESC

LIMIT 10

结果如下:

个性化PageRank算法

个性化PageRank是从一个或多个源节点的视角给出其他节点的pagerank分。

我们再计算一次pagerank分数,但这次我们把描述中带有关键词“social networks”的文章作为源节点。

MATCH (k:Keyword)-[:DESCRIBES]->()WHERE k.value = "social networks"

WITH collect(a) as articles

CALL algo.pageRank.stream(\'Article\', \'REFERENCES\', {sourceNodes: articles})

YIELD nodeId, score

WITH nodeId,score order by score desc limit 10

MATCH (n) where id(n) = nodeId

RETURN n.title as article, score

可以看到Sergey Brin和Larry Page所著的《大型超文字搜索引擎解析》(http://infolab.stanford.edu/pub/papers/google.pdf) 排在第一位。因此,可以看出,Google早期在图和PageRank方面的研究对社交网络方面有着巨大的影响。

个性化的推荐系统

需要再次重申,本文的目标是要重现这个场景

关键词“entropy”对于不同的人意味着不同的东西,我们希望从不同的角度还比较关键词“entropy"的结果。

首先我们找到某一作者的所有文章,这些文章将会作为个性化Pagerank的源节点。接着,我们执行pagerank算法并投影关键词”entropy“描述的文章节点,同时也投影这些文章节点之间的REFERENCES关系。

我们可以通过cypher投影语句过滤掉不需要的关系

只有在源节点和目标节点都被节点查询语句中所描述时,其在关系查询语句的关系才会被投影。源节点和目标节点任一个不在节点查询语句中描述时,则此关系会被忽略。

推荐示例

下面给出的是Jose C. Principe视角下搜寻关键词“entropy”所得到的推荐文章。

MATCH (a:Article)WHERE author.name="Jose C. Principe"

WITH collect(a) as articles

CALL algo.pageRank.stream(

\'MATCH (a:Article)-[:HAS_ANNOTATED_TEXT]->() WHERE k.value contains "entropy" RETURN distinct id(a) as id\',

\'MATCH (a1:Article)-[:REFERENCES]->(a2:Article)

RETURN id(a1) as source,id(a2) as target\',

{sourceNodes: articles,graph:\'cypher\'})

YIELD nodeId, score

WITH nodeId,score order by score desc limit 10

MATCH (n) where id(n) = nodeId

RETURN n.title as article, score

HongWang视角下搜寻关键词“entropy”所得到的推荐文章

MATCH (a:Article)WHERE author.name="Hong Wang"

WITH collect(a) as articles

CALL algo.pageRank.stream(

\'MATCH (a:Article)-[:HAS_ANNOTATED_TEXT]->() WHERE k.value contains "entropy" RETURN distinct id(a) as id\',

\'MATCH (a1:Article)-[:REFERENCES]->(a2:Article)

RETURN id(a1) as source,id(a2) as target\',

{sourceNodes: articles,graph:\'cypher\'})

YIELD nodeId, score

WITH nodeId,score order by score desc limit 10

MATCH (n) where id(n) = nodeId

RETURN n.title as article, score

结论

正如我们所料,从两位作者的不同视角进行搜寻,得到的推荐结果也是不一样的。

Neo4j本身很强大,在特定的领域内使用相应的外挂时,他会变的更强大。

原文连结:https://tbgraph.wordpress.com/2018/09/09/article-recommendation-system-on-a-citation-network-using-personalized-pagerank-and-neo4j/

如果你对本文或Neo4j有任何想法,欢迎留言进行交流。

2020-02-01 03:00:00

相关文章