Neo4j的最常见用途之一是构建实时推荐引擎,一个共同的主题是它们利用大量不同的数据来提出有趣的推荐。

例如, 在此视频中, 阿曼达(Amanda)展示了约会网站如何通过社交联系开始,然后介绍热情,位置和其他一些东西,从而构建实时推荐引擎。

Graph Aware有一个简洁的框架 ,可以帮助您使用Java构建自己的推荐引擎,我很好奇Cypher版本的外观。
这是示例图:

CREATE(m:Person:Male {name:'Michal', age:30}),(d:Person:Female {name:'Daniela', age:20}),(v:Person:Male {name:'Vince', age:40}),(a:Person:Male {name:'Adam', age:30}),(l:Person:Female {name:'Luanne', age:25}),(c:Person:Male {name:'Christophe', age:60}),(lon:City {name:'London'}),(mum:City {name:'Mumbai'}),(m)-[:FRIEND_OF]->(d),(m)-[:FRIEND_OF]->(l),(m)-[:FRIEND_OF]->(a),(m)-[:FRIEND_OF]->(v),(d)-[:FRIEND_OF]->(v),(c)-[:FRIEND_OF]->(v),(d)-[:LIVES_IN]->(lon),(v)-[:LIVES_IN]->(lon),(m)-[:LIVES_IN]->(lon),(l)-[:LIVES_IN]->(mum);

我们想向“亚当”推荐一些潜在的朋友,因此我们查询的第一层是找到他的朋友,因为其中肯定有一些潜在的朋友:

MATCH (me:Person {name: "Adam"})
MATCH (me)-[:FRIEND_OF]-()-[:FRIEND_OF]-(potentialFriend)
RETURN me, potentialFriend, COUNT(*) AS friendsInCommon==> +--------------------------------------------------------------------------------------+
==> | me                             | potentialFriend                   | friendsInCommon |
==> +--------------------------------------------------------------------------------------+
==> | Node[1007]{name:"Adam",age:30} | Node[1006]{name:"Vince",age:40}   | 1               |
==> | Node[1007]{name:"Adam",age:30} | Node[1005]{name:"Daniela",age:20} | 1               |
==> | Node[1007]{name:"Adam",age:30} | Node[1008]{name:"Luanne",age:25}  | 1               |
==> +--------------------------------------------------------------------------------------+
==> 3 rows

该查询为我们提供了潜在朋友的列表以及我们有多少个共同的朋友。

现在我们有了一些潜在的朋友,让我们开始为他们每个人建立一个排名。 一个可以吸引潜在朋友的指标是,如果他们和我们生活在同一地点,那么可以将其添加到查询中:

MATCH (me:Person {name: "Adam"})
MATCH (me)-[:FRIEND_OF]-()-[:FRIEND_OF]-(potentialFriend)WITH me, potentialFriend, COUNT(*) AS friendsInCommonRETURN  me,potentialFriend,SIZE((potentialFriend)-[:LIVES_IN]->()<-[:LIVES_IN]-(me)) AS sameLocation==> +-----------------------------------------------------------------------------------+
==> | me                             | potentialFriend                   | sameLocation |
==> +-----------------------------------------------------------------------------------+
==> | Node[1007]{name:"Adam",age:30} | Node[1006]{name:"Vince",age:40}   | 0            |
==> | Node[1007]{name:"Adam",age:30} | Node[1005]{name:"Daniela",age:20} | 0            |
==> | Node[1007]{name:"Adam",age:30} | Node[1008]{name:"Luanne",age:25}  | 0            |
==> +-----------------------------------------------------------------------------------+
==> 3 rows

接下来,我们将通过比较每个节点的标签来检查Adams的潜在朋友是否与他具有相同的性别。 我们有“性别”和“性别”标签来表示性别。

MATCH (me:Person {name: "Adam"})
MATCH (me)-[:FRIEND_OF]-()-[:FRIEND_OF]-(potentialFriend)WITH me, potentialFriend, COUNT(*) AS friendsInCommonRETURN  me,potentialFriend,SIZE((potentialFriend)-[:LIVES_IN]->()<-[:LIVES_IN]-(me)) AS sameLocation,LABELS(me) = LABELS(potentialFriend) AS gender==> +--------------------------------------------------------------------------------------------+
==> | me                             | potentialFriend                   | sameLocation | gender |
==> +--------------------------------------------------------------------------------------------+
==> | Node[1007]{name:"Adam",age:30} | Node[1006]{name:"Vince",age:40}   | 0            | true   |
==> | Node[1007]{name:"Adam",age:30} | Node[1005]{name:"Daniela",age:20} | 0            | false  |
==> | Node[1007]{name:"Adam",age:30} | Node[1008]{name:"Luanne",age:25}  | 0            | false  |
==> +--------------------------------------------------------------------------------------------+
==> 3 rows

接下来,让我们计算亚当和他的潜在朋友之间的年龄差异:

MATCH (me:Person {name: "Adam"})
MATCH (me)-[:FRIEND_OF]-()-[:FRIEND_OF]-(potentialFriend)WITH me, potentialFriend, COUNT(*) AS friendsInCommonRETURN me,potentialFriend,SIZE((potentialFriend)-[:LIVES_IN]->()<-[:LIVES_IN]-(me)) AS sameLocation,abs( me.age - potentialFriend.age) AS ageDifference,LABELS(me) = LABELS(potentialFriend) AS gender,friendsInCommon==> +--------------------------------------------------------------------------------------+
==> | me                             | potentialFriend                   | sameLocation | ageDifference | gender | friendsInCommon |
==> +--------------------------------------------------------------------------------------+
==> | Node[1007]{name:"Adam",age:30} | Node[1006]{name:"Vince",age:40}   | 0            | 10.0          | true   | 1               |
==> | Node[1007]{name:"Adam",age:30} | Node[1005]{name:"Daniela",age:20} | 0            | 10.0          | false  | 1               |
==> | Node[1007]{name:"Adam",age:30} | Node[1008]{name:"Luanne",age:25}  | 0            | 5.0           | false  | 1               |
==> +--------------------------------------------------------------------------------------+
==> 3 rows

现在,让我们进行一些筛选,以摆脱与亚当已经成为朋友的人–推荐这些人没有多大意义!

MATCH (me:Person {name: "Adam"})
MATCH (me)-[:FRIEND_OF]-()-[:FRIEND_OF]-(potentialFriend)WITH me, potentialFriend, COUNT(*) AS friendsInCommonWITH me,potentialFriend,SIZE((potentialFriend)-[:LIVES_IN]->()<-[:LIVES_IN]-(me)) AS sameLocation,abs( me.age - potentialFriend.age) AS ageDifference,LABELS(me) = LABELS(potentialFriend) AS gender,friendsInCommonWHERE NOT (me)-[:FRIEND_OF]-(potentialFriend)RETURN me,potentialFriend,SIZE((potentialFriend)-[:LIVES_IN]->()<-[:LIVES_IN]-(me)) AS sameLocation,abs( me.age - potentialFriend.age) AS ageDifference,LABELS(me) = LABELS(potentialFriend) AS gender,friendsInCommon==> +---------------------------------------------------------------------------------------+
==> | me                             | potentialFriend                   | sameLocation | ageDifference | gender | friendsInCommon |
==> +---------------------------------------------------------------------------------------+
==> | Node[1007]{name:"Adam",age:30} | Node[1006]{name:"Vince",age:40}   | 0            | 10.0          | true   | 1               |
==> | Node[1007]{name:"Adam",age:30} | Node[1005]{name:"Daniela",age:20} | 0            | 10.0          | false  | 1               |
==> | Node[1007]{name:"Adam",age:30} | Node[1008]{name:"Luanne",age:25}  | 0            | 5.0           | false  | 1               |
==> +---------------------------------------------------------------------------------------+
==> 3 rows

在这种情况下,我们实际上并未将任何人过滤掉,但是对于其他一些人,我们会看到潜在朋友数量的减少。

我们的最后一步是为每个我们认为对提出朋友建议很重要的功能评分。

如果人们居住在与亚当相同的地方或性别相同,我们将给满分10分,否则给0分。 对于ageDifference和friendsInCommon,我们将应用对数曲线,以使这些值不会对我们的最终分数产生不成比例的影响。 我们将使用ParetoScoreTransfomer中定义的公式来执行此操作:

public <OUT> float transform(OUT item, float score) {if (score < minimumThreshold) {return 0;}double alpha = Math.log((double) 5) / eightyPercentLevel;double exp = Math.exp(-alpha * score);return new Double(maxScore * (1 - exp)).floatValue();}

现在,对于我们完整的推荐查询:

MATCH (me:Person {name: "Adam"})
MATCH (me)-[:FRIEND_OF]-()-[:FRIEND_OF]-(potentialFriend)WITH me, potentialFriend, COUNT(*) AS friendsInCommonWITH me,potentialFriend,SIZE((potentialFriend)-[:LIVES_IN]->()<-[:LIVES_IN]-(me)) AS sameLocation,abs( me.age - potentialFriend.age) AS ageDifference,LABELS(me) = LABELS(potentialFriend) AS gender,friendsInCommonWHERE NOT (me)-[:FRIEND_OF]-(potentialFriend)WITH potentialFriend,// 100 -> maxScore, 10 -> eightyPercentLevel, friendsInCommon -> score (from the formula above)100 * (1 - exp((-1.0 * (log(5.0) / 10)) * friendsInCommon)) AS friendsInCommon,sameLocation * 10 AS sameLocation,-1 * (10 * (1 - exp((-1.0 * (log(5.0) / 20)) * ageDifference))) AS ageDifference,CASE WHEN gender THEN 10 ELSE 0 END as sameGenderRETURN potentialFriend,{friendsInCommon: friendsInCommon,sameLocation: sameLocation,ageDifference:ageDifference,sameGender: sameGender} AS parts,friendsInCommon + sameLocation + ageDifference + sameGender AS score
ORDER BY score DESC==> +---------------------------------------------------------------------------------------+
==> | potentialFriend                   | parts                                                                                                           | score             |
==> +---------------------------------------------------------------------------------------+
==> | Node[1006]{name:"Vince",age:40}   | {friendsInCommon -> 14.86600774792154, sameLocation -> 0, ageDifference -> -5.52786404500042, sameGender -> 10} | 19.33814370292112 |
==> | Node[1008]{name:"Luanne",age:25}  | {friendsInCommon -> 14.86600774792154, sameLocation -> 0, ageDifference -> -3.312596950235779, sameGender -> 0} | 11.55341079768576 |
==> | Node[1005]{name:"Daniela",age:20} | {friendsInCommon -> 14.86600774792154, sameLocation -> 0, ageDifference -> -5.52786404500042, sameGender -> 0}  | 9.33814370292112  |
==> +----------------------------------------------------------------------------------------+

最终查询还不错-唯一真正复杂的部分是对数曲线计算。 将来用户定义的功能将在此发挥作用。

这种方法的好处是我们不必走出密码的道路,因此,如果您对Java不满意,仍然可以进行实时建议! 另一方面,推荐引擎的不同部分都混杂在一起,因此要查看整个管道并不像使用图形感知框架那样容易。

下一步是将其应用于Twitter图形,并在此提供关注者建议。

翻译自: https://www.javacodegeeks.com/2015/03/neo4j-generating-real-time-recommendations-with-cypher.html

Neo4j:使用Cypher生成实时建议相关推荐

  1. neo4j cypher_Neo4j:使用Cypher生成实时建议

    neo4j cypher Neo4j的最常见用途之一是构建实时推荐引擎,一个共同的主题是它们利用大量不同的数据来提出有趣的推荐. 例如, 在此视频中, 阿曼达(Amanda)展示了约会网站如何通过社交 ...

  2. neo4j cypher_neo4j / cypher:悬挂查询参数

    neo4j cypher 一直以来,我一直在使用neo4j的密码查询语言, 迈克尔一直在告诉我在查询中使用参数,但是查询的性能始终可以接受,因此我没有必要. 但是,最近我正在研究一个数据集,并使用类似 ...

  3. (六)图数据neo4j之cypher(一)

    (六)图数据neo4j之cypher(一) 1.Cypher概述 cypher是一种声明式的图数据库查询语言,能高效的查询和更新图数据库,是依赖于模式的.所谓模式(Patterns)是就是众多节点和关 ...

  4. nginx+lua+GraphicsMagick生成实时缩略图-CentOS7

    背景说明 大多数的系统都会涉及缩略图的处理,比如新闻系统和电商系统,特别是电商系统,每个商品大图都会对应一系列尺寸的缩略图用于不同业务场景的使用.部分系统也会生成不同尺寸的缩略图以供PC.手机端.ip ...

  5. Neo4j常用Cypher查询语句

    Neo4j常用Cypher查询语句 作者:胡佳辉, CSDN博客:https://blog.csdn.net/gobitan [1] 查看图数据库中所有的标签 match (n) return dis ...

  6. Neo4j:Cypher –避免热切

    当心渴望的管道 尽管我喜欢Cypher的LOAD CSV命令使它容易地将数据获取到Neo4j中的方法,但它目前打破了最不惊奇的规则,因为它急切地在所有行中加载某些查询,即使是那些使用定期提交的查询. ...

  7. 读书笔记——Neo4j实战 Cypher查询语言

    Cypher是对图形的声明查询语言, 使用图形模式匹配作为主要的机制作图形数据选择(包括只读和变更操作) . Cypher的声明模式匹配性质意味着可以通过描述想从它那里得到什么查询图形数据. 执行Cy ...

  8. Neo4j之cypher语法

    1. 什么是Cypher Cypher是一种声明式图查询语言,表达高效查询和更新图数据库. Cypher是相对简单的查询语法,它让我们更关注业务领域问题. 找 环 MATCH p=(n)-[*2-10 ...

  9. 【国内首家】第一个基于语音生成实时知识图谱的系统来啦!!!

    点击上方,选择星标或置顶,不定期资源大放送! 阅读大概需要8分钟 Follow小博主,每天更新前沿干货 基于文本生成知识图谱的研究很常见,但是基于语音生成知识图谱,这算是第一家. 在这个信息飞速发展的 ...

最新文章

  1. sprintf函数做什么用?
  2. 用友u8计算机配置,用友软件环境配置要求!
  3. java并发订单号生成
  4. python中pygal_Python数据可视化之Pygal图表类型
  5. 【公开课】“有三说深度学习”上线
  6. FIR数字滤波器设计——频率抽样法
  7. 【敏捷案例】老板太外行,朝令夕改!要不要拿了年终奖就撤?
  8. var和function谁先优先执行_JS中如何和让异步函数优先执行?
  9. @程序员,想要基于 Python 3.4 玩爬虫该看些什么?
  10. Tyvj3308毒药解药题解
  11. 上海飞国内最远是哪里_讯飞连发三款智能录音笔!可离线转写拍视频秒配字幕,首推智能TWS耳机...
  12. linux midi编辑,MidiEditor软件下载 MIDI音乐制作软件(MidiEditor) v3.1.0 支持Windows和Linux 英文官方版 下载-脚本之家...
  13. tomcat编码配置gbk_修改Tomcat编码方式的两种方法
  14. ong拼音汉字_拼音ong的正确发音
  15. 【HBuilder】前端IDE神器
  16. 互联网项目经理的职业规划
  17. 转发-【分享】思科无线控制器HA模式升级
  18. 访问控制模型总结(DAC MAC RBAC ABAC)
  19. 测试用例(测试用例的编写、评审和管理)
  20. ggplot2:初次见面,请多多关照!

热门文章

  1. 2020蓝桥杯省赛---java---A---2(既分数组)
  2. 字符串暴力匹配算法+思路分析
  3. SpringBoot+MyBatis搭建迷你小程序
  4. python遗传算法工具箱的使用_遗传算法的python实现,非常值得看的一篇文章
  5. windows查找端口占用并杀死端口进程
  6. java集合——队列和双端队列+优先级队列
  7. java jsf_使用Java和JSF构建一个简单的CRUD应用
  8. 阿帕奇跨域_阿帕奇齿轮泵
  9. groovy grails_在Grails战争中添加一个“精简”的Groovy Web控制台
  10. cloud foundry_介绍“又一个” Cloud Foundry Gradle插件