Neo4j:使用Cypher生成实时建议

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/360082.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Windows 8.1 新增控件之 Hyperlink

Windows 8.1 新增控件之 Hyperlink 原文:Windows 8.1 新增控件之 HyperlinkHyperlink 控件应该不用过多介绍大家肯定十分清楚其作用&#xff0c;它的功能就像HTML中的<a href””>标签一样&#xff0c;只不过是在XAML中实现。 使用Hyperlink 标记的文字在应用中会以特殊颜…

Linux的slab和nginx的区别,Nginx核心知识100讲》nginx Slab管理器

极客专栏《Nginx核心知识100讲》38小节的笔记nginx 不同的worker之间需要共享信息的时候&#xff0c;只能通过共享内存。共享内存会使用链表&#xff0c;红黑树这样的数据结构。但是每个红黑树上有很多节点&#xff0c;每个节点上都需要分配内存去存放。怎样把一整块共享内存切…

睡觉时:新增的Java 8新增功能

自Java 8推出以来&#xff0c;最有趣的功能是什么&#xff1f; Java 8最近庆祝了它的第一个生日&#xff0c;而主要版本刚刚一年多前发布。 这当然值得庆祝。 自从最初的Java 8版本问世以来&#xff0c;已经发布了六个更新。 这些更新中的一些元素是次要的&#xff0c;但是如…

Gridview中实现求和统计功能

GridView加入自动求和求平均值小计效果图&#xff1a;解决方案&#xff1a; private double sum 0; //取指定列的数据和&#xff0c;你要根据具体情况对待可能你要处理的是int protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e){if (e.Row.R…

树莓派安装win10arm linux,在树莓派3B 上安装 Windows 10 ARM 版的方法

早先关注我们的朋友可能对《国外开发者尝试在树莓派3上运行Windows 10桌面版》有印象。本文转自 amatfan.com&#xff0c;文末视频来自 daveb778(感谢柠栀和刺分享)&#xff0c;给出了如何在树莓派3B上安装Windows10 ARM版&#xff0c;是的&#xff0c;这次并非IoT版&#xff0…

MVC中跳转到其他页面,并传参数

return RedirectToAction("MemberManager", "Shop", new { id Session["shopid"] }); MemberManager&#xff1a;页面的Action&#xff1b;Shop&#xff1a;Controller名称&#xff1b;id&#xff1a;要传的参数名&#xff1b;Session["…

ld-linux.so.2 重定向,Linux Shell脚本Ldd命令原理及使用方法

1、首先ldd不是一个可执行程序&#xff0c;而只是一个shell脚本2、ldd能够显示可执行模块的dependency&#xff0c;其原理是通过设置一系列的环境变量如下&#xff1a;LD_TRACE_LOADED_OBJECTS、LD_WARN、LD_BIND_NOW、LD_LIBRARY_VERSION、 LD_VERBOSE等。当LD_TRACE_LOADED_O…

各种触摸手势

轻按(UITapGestureRecognizer) -- 用一个或多个手指在屏幕上轻按。 按住(UILongPressGestureRecognizer) -- 用一个或多个手指在屏幕上按住。 轻扫(UISwipeGestureRecognizer) -- 用一个或多个手指沿特定方向轻扫。 张合(UIPinchGestureRecognizer) -- 张合手指以缩放对象。 旋…

宝塔linux取消登录,宝塔面板如何关闭安全入口

通过 SSH 终端关闭安全入口通过 SSH 终端连接rm -f /www/server/panel/data/admin_path.pl即可关闭宝塔 Linux 面板的安全入口&#xff0c;关闭之后的面板登录地址就是&#xff1a;http://服务器 IP:8888。不过关闭这个安全入口之后很难恢复&#xff0c;所以不建议关闭宝塔面板…

一种通过变量插值读取属性的方法

最近&#xff0c;我尝试在应用程序服务器中定义和读取全局属性。 在应用程序服务器中配置的此类属性的好处–可以在此服务器上部署的所有Web应用程序之间共享该属性。 每个部署的应用程序都可以读取同一属性&#xff0c;该属性仅在一个位置配置一次。 我试图做的是在值部分中包…

[ofbiz]设置任务计划(job),提示service_item已经传递

问题描述&#xff1a;设置任务计划(job)&#xff0c;提示service_item已经传递 解决办法&#xff1a; 红色框内不要填写&#xff0c;就可以了。"已经传递"是翻译的不准确&#xff0c;应该是"已过时"&#xff0c;所以不设置开始时间&#xff0c;或者开始时间…

c r语言中rank函数,R语言的常用函数

基本一、数据管理vector&#xff1a;向量 numeric&#xff1a;数值型向量 logical&#xff1a;逻辑型向量character&#xff1b;字符型向量 list&#xff1a;列表 data.frame&#xff1a;数据框c&#xff1a;连接为向量或列表 length&#xff1a;求长度 subset&#xff1a;求子…

mongodb查询内嵌文档

mongodb查询内嵌文档假设有这样一个文档&#xff1a;db.XXX.remove();db.XXX.insert({"id":1, "members":[{"name":"BuleRiver1", "age":27, "gender":"M"}, {"name":"BuleRiver2"…

问号在c语言中运算符,C# 运算符 ?、??、?: 各种问号的用法和说明

1、可空类型修饰符(?)&#xff1a;引用类型可以使用空引用表示一个不存在的值&#xff0c;而值类型通常不能表示为空&#xff0c;例如:string strnull;是正确的。int inull&#xff1b;编译器将报错。为了使值类型也可为空&#xff0c;可空类型出现了&#xff0c;可空类型使用…

Extjs不错的博客

http://www.cnblogs.com/fangsui/category/372751.html http://www.cnblogs.com/WangJinYang/tag/EXT.NET/ http://www.cnblogs.com/codelove/tag/Ext.NET/转载于:https://www.cnblogs.com/anbylau2130/p/3598429.html

cvi中c语言只保留两位小数,CVI编程常见问题与错误-2012.9

CVI编程常见问题或错误1.CVI编程时&#xff0c;在程序中插入函数的方法&#xff1f;如何了解该函数隶属那个函数库&#xff1f; (3)2.如何查看或者找到一个CVI或IMAQ Vision的函数&#xff1f; (4)3.实验一不能显示曲线—采用了错误的显示控件 (5)4.实验一不能显示正弦曲线 (5)…

vector C++ 详细用法

vector是C标准模板库中的部分内容&#xff0c;它是一个多功能的&#xff0c;能够操作多种数据结构和算法的模板类和函数库。vector之所以被认为是一个容器&#xff0c;是因为它能够像容器一样存放各种类型的对象&#xff0c;简单地说&#xff0c;vector是一个能够存放任意类型的…

c#枚举类似于java_如何在Java中获得类似于C的性能

c#枚举类似于java总览 Java有许多可能很慢的领域。 但是&#xff0c;对于每个问题都有解决方案。 许多解决方案/黑客都需要解决Java的保护问题&#xff0c;但是如果您需要低水平的性能&#xff0c;还是可以的。 Java使高级编程变得越来越容易&#xff0c;但代价是使低级编程变…

c支限界算法语言n皇后问题分,n皇后问题(分析)

这道题需要用到回溯算法&#xff0c;现在在这里先简单的介绍一下这个算法&#xff1a;回溯算法也叫试探法&#xff0c;它是一种系统地搜索问题的解的方法。回溯算法的基本思想是&#xff1a;从一条路往前走&#xff0c;能进则进&#xff0c;不能进则退回来&#xff0c;换一条路…

oracle instr查询字符串

INSTR (源字符串, 目标字符串, 起始位置, 匹配序号) 在Oracle/PLSQL中&#xff0c;instr函数返回要截取的字符串在源字符串中的位置。只检索一次&#xff0c;就是说从字符的开始 到字符的结尾就结束。 语法如下&#xff1a; instr( string1, string2 [, start_position [, nth_…