相似度算法在知识图谱中的实现

随着知识图谱的火爆从美国一路烧到了国内,近几年知识图谱技术在国内已经得到了飞速的发展,我们对知识图谱的概念及应用都不再陌生。你可以看到知识图谱技术的应用出现在越来越多的垂直领域中。从最早大家最为熟悉的在搜索引擎中的应用,逐渐地扩充到金融领域、医药领域等等。今天我们已经在各行各业中,都能够看到知识图谱的身影,更多的技术人员也加入了我们知识图谱工程的大家庭。

那么今天我们来就知识图谱的技术问题进行更深层的探讨。今天我将和大家分享一个,我在知识图谱搭建中遇到的棘手问题,相信有不少小伙伴也会遇到这样的问题。希望今天我分享的解决方案可以给大家一些帮助!

我遇到的问题:

在构建知识图谱的图关系时,基础数据来自很多不同的数据源。比如金融风控领域中,我们要构建的知识图谱中,包含地址、公司等出现频率比较高,并且名称一模一样的可能性很低的词汇。

比如:北京市国贸中心写字楼和北京朝阳区建外大街1号国贸中心是同一个地址么?

那在图关系的构建中,如果把上地址作为两个地址进行处理的话,那么就会创建两个实体,并且这两个实体之间并没有什么关联关系,这种处理方法,肯定是错误的。这个时候,需要进行的工作就是地址消歧,把两个地址经过处理后,变成同一个地址。

这个时候我们需要做的是进行相似度计算。

我的解决方案:

在Neo4j中的余弦相似度计算如何满足这种应用场景。

那么什么是余弦相似度呢?余弦相似度是n维空间中两个n维向量之间角度的余弦。它是两个向量的点积除以两个向量的长度(或幅度)的乘积。

余弦相似度公式:

那么计算的值介于-1和1之间,其中-1完全不同,1完全相似。

那么在neo4j中怎么使用余弦相似度计算呢?

非常幸运,neo4j的一个插件可以提供这样一个功能,让我们能够直接在其上实现相似度计算。

环境安装:

这里你只需要一个jar包,就可以将其搞定。

下载链接:https://github.com/neo4j-contrib/neo4j-graph-algorithms/releases

将下载的graph-algorithms-algo-3.5.0.1.jar包拷贝到$NEO4J_HOME/plugins目录中

注意:要修改neo4j的配置将

dbms.security.procedures.unrestricted=algo.*

添加到neo4j.conf文件当中,一定要做,要不然后边的试验会失败

重启neo4j数据库就可以了。

第一个例子:

打开你的neo4j数据库,输入 :RETURN algo.similarity.cosine([3,8,7,5,2,9], [10,8,6,6,4,5]) AS similarity

这个语句的意思就是调用neo4j提供的算法计算库中的函数,并且计算[3,8,7,5,2,9]和 [10,8,6,6,4,5]两组数据的余弦相似度,那么返回的结果是:

那么这个值已经非常的接近1了。这就是这两个数字列表的余弦相似度值。

此时你应该感觉到,使用Neo4j库中的插件来实现,非常的简单。

那么下面,我们可以自己来根据公式进行推理一下。

首先,我们创建一个图关系:

具体Cypher如下:

MERGE (french:Cuisine {name:'French'})MERGE (italian:Cuisine {name:'Italian'})MERGE (indian:Cuisine {name:'Indian'})MERGE (lebanese:Cuisine {name:'Lebanese'})MERGE (portuguese:Cuisine {name:'Portuguese'})MERGE (zhen:Person {name: "Zhen"})MERGE (praveena:Person {name: "Praveena"})MERGE (michael:Person {name: "Michael"})MERGE (arya:Person {name: "Arya"})MERGE (karin:Person {name: "Karin"})MERGE (praveena)-[:LIKES {score: 9}]->(indian)MERGE (praveena)-[:LIKES {score: 7}]->(portuguese)MERGE (zhen)-[:LIKES {score: 10}]->(french)MERGE (zhen)-[:LIKES {score: 6}]->(indian)MERGE (michael)-[:LIKES {score: 8}]->(french)MERGE (michael)-[:LIKES {score: 7}]->(italian)MERGE (michael)-[:LIKES {score: 9}]->(indian)MERGE (arya)-[:LIKES {score: 10}]->(lebanese)MERGE (arya)-[:LIKES {score: 10}]->(italian)MERGE (arya)-[:LIKES {score: 7}]->(portuguese)MERGE (karin)-[:LIKES {score: 9}]->(lebanese)MERGE (karin)-[:LIKES {score: 7}]->(italian)

neo4j插入结果:

那么我们用这个数据再进行一次计算

Cypher如下:

MATCH (p:Person), (c:Cuisine) OPTIONAL MATCH (p)-[likes:LIKES]->(c) WITH {item:id(p), weights: collect(coalesce(likes.score, 0))} as userData WITH collect(userData) as data CALL algo.similarity.cosine.stream(data) YIELD item1, item2, count1, count2, similarity RETURN algo.getNodeById(item1).name AS from, algo.getNodeById(item2).name AS to, similarity ORDER BY similarity DESC

相似度计算结果:

以上,我们可以看到Arya和Karin的食物口味最相似,得分为0.889。最高分为1,因此它们非常接近最大相似度

下边还有很多相似度为0的,原因是我数据库中原本有一些数据导致,那么现在我们要把这些数据过滤掉

Cypher如下:

MATCH (p:Person), (c:Cuisine)

OPTIONAL MATCH (p)-[likes:LIKES]->(c)

WITH {item:id(p), weights: collect(coalesce(likes.score, 0))} as userData

WITH collect(userData) as data

CALL algo.similarity.cosine.stream(data, {similarityCutoff: 0.0})

YIELD item1, item2, count1, count2, similarity

RETURN algo.getNodeById(item1).name AS from, algo.getNodeById(item2).name AS to, similarity

ORDER BY similarity DESC

运行结果:

我们可以看到那些没有相似性的用户已被过滤掉了。如果我们正在实现k-Nearest Neighbors类型查询,我们可能希望k为给定用户找到最相似的用户。我们可以通过传入topK参数来做到这一点。

以下将返回用户流以及最相似的用户(即k=1):

Cypher如下:

MATCH (p:Person), (c:Cuisine)

OPTIONAL MATCH (p)-[likes:LIKES]->(c)

WITH {item:id(p), weights: collect(coalesce(likes.score, 0))} as userData

WITH collect(userData) as data

CALL algo.similarity.cosine.stream(data, {topK:1, similarityCutoff: 0.0})

YIELD item1, item2, count1, count2, similarity

RETURN algo.getNodeById(item1).name AS from, algo.getNodeById(item2).name AS to, similarity

ORDER BY from

执行结果:

细心的同学会发现,以上的结果有一点问题,第一行的结果和第二行的结果其实是相同的。

那么我们现在要做的是为每个用户找到最相似的用户,并存储这些用户之间的关系:

Cypher如下

MATCH (p:Person), (c:Cuisine)

OPTIONAL MATCH (p)-[likes:LIKES]->(c)

WITH {item:id(p), weights: collect(coalesce(likes.score, 0))} as userData

WITH collect(userData) as data

CALL algo.similarity.cosine(data, {topK: 1, similarityCutoff: 0.1, write:true})

YIELD nodes, similarityPairs, write, writeRelationshipType, writeProperty, min, max, mean, stdDev, p25, p50, p75, p90, p95, p99, p999, p100

RETURN nodes, similarityPairs, write, writeRelationshipType, writeProperty, min, max, mean, p95

执行结果如下:


然后,我们可以写一个查询,以找出与我们相似的其他人可能喜欢的美食类型。

以下将找到与Praveena最相似的用户

Cypher:

MATCH (p:Person {name: "Praveena"})-[:SIMILAR]->(other),

(other)-[:LIKES]->(cuisine)

WHERE not((p)-[:LIKES]->(cuisine))

RETURN cuisine.name AS cuisine

执行结果:

以上就是整个的计算过程。

贪心科技
贪心科技

贪心科技是国内首家AI和大数据课程为主的自适应学习平台。我们追求最精炼的AI教育内容和个人量身定制的课堂。我们鼓励大家拥有“贪心精神”:对知识不断的渴望,对现状不满希望进步的愿望。贪心科技,满足贪心的你。

工程算法知识图谱
41
相关数据
参数技术

在数学和统计学裡,参数(英语:parameter)是使用通用变量来建立函数和变量之间关系(当这种关系很难用方程来阐述时)的一个数量。

知识图谱技术

知识图谱本质上是语义网络,是一种基于图的数据结构,由节点(Point)和边(Edge)组成。在知识图谱里,每个节点表示现实世界中存在的“实体”,每条边为实体与实体之间的“关系”。知识图谱是关系的最有效的表示方式。通俗地讲,知识图谱就是把所有不同种类的信息(Heterogeneous Information)连接在一起而得到的一个关系网络。知识图谱提供了从“关系”的角度去分析问题的能力。 知识图谱这个概念最早由Google提出,主要是用来优化现有的搜索引擎。不同于基于关键词搜索的传统搜索引擎,知识图谱可用来更好地查询复杂的关联信息,从语义层面理解用户意图,改进搜索质量。比如在Google的搜索框里输入Bill Gates的时候,搜索结果页面的右侧还会出现Bill Gates相关的信息比如出生年月,家庭情况等等。

查询技术

一般来说,查询是询问的一种形式。它在不同的学科里涵义有所不同。在信息检索领域,查询指的是数据库和信息系统对信息检索的精确要求

请问现在neo4j中没有algo.similarity.cosine.stream()算法了应该如何计算呢?谢谢!