用da构建一个实时推荐引擎

我已经在Neo4j上工作了两年,但是已经在Neo4j和Cypher上工作了三年。
我在得克萨斯大学奥斯汀分校读研究生时,就读了这个统计图数据库,并专注于社交网络。

实时推荐引擎是Neo4j的最常用用例之一,也是使其功能如此强大且易于使用的方面之一。
为了对此进行探讨,我将说明如何通过使用示例数据集将统计方法纳入这些建议中。

首先是简单的-完全在Cypher中,重点关注社交推荐。
接下来,我们将介绍相似性建议,其中涉及可以计算的相似性指标,最后是聚类建议。

以下数据集包括达拉斯沃斯堡国际机场(美国主要的机场枢纽之一)的餐饮场所:

用da构建一个实时推荐引擎

我们将节点放置为黄色,并根据门和终端对其位置进行建模。
并且我们还按照食品和饮料的主要类别对地点进行了分类。
其中一些包括墨西哥美食,三明治,酒吧和烧烤。

让我们做一个简单的建议。
我们想在机场的某个位置找到一种特定类型的食物,并且大括号表示正在输入到我们假设的应用程序中的用户输入:

用da构建一个实时推荐引擎

这个英语句子非常适合作为Cypher查询:

用da构建一个实时推荐引擎

这将拉动用户请求的类别,终端和登机口中的所有位置。
然后,我们获得到用户所在门的位置的绝对距离,并以升序返回结果。
同样,仅根据用户在机场中的位置向用户推荐非常简单的Cypher。

让我们看一下社交推荐。
在我们的假设应用程序中,我们的用户可以以类似于Facebook的方式登录并“喜欢”地点,还可以检查以下地点:

用da构建一个实时推荐引擎

在上面的应用程序中,我们还拥有与某个地点节点具有“喜欢”关系的用户,并且他们也是与其他用户的朋友。
在我们探索的第一个模型的基础上考虑此数据模型,现在让我们在用户朋友喜欢的任何终端中,找到以下类别中最接近登机口的饮食场所:

用da构建一个实时推荐引擎

该子句与第一个Cypher查询的子句非常相似,除了现在我们在以下位置进行匹配:

用da构建一个实时推荐引擎

前三行相同,但是对于有问题的用户(即“登录”的用户),我们希望通过关系以及这些朋友喜欢的地方来找到他们的朋友。
仅增加了几行Cypher,我们现在就将推荐引擎考虑到了社交方面。

同样,我们只在用户所在的终端中显示用户明确要求的类别。
而且,当然,我们要根据登录并发出此请求的用户进行过滤,然后返回该地点的名称以及其位置和类别。
我们还考虑了有多少朋友喜欢该地方,以及该地方到大门的距离的绝对值,这些均在该子句中返回。

现在,让我们看一下相似性推荐引擎:

用da构建一个实时推荐引擎

与我们之前的数据模型类似,我们的用户可以喜欢地点,但是这次他们也可以使用1到10之间的整数对地点进行评分。
通过在节点或关系中添加属性,可以轻松地在Neo4j中对此建模。

这使我们能够找到其他类似的用户,例如Greta和Alice的示例。
我们查询了他们共同喜欢的地方,对于每个地方,我们可以看到他们分配的权重。
大概,我们可以使用这些数字来确定它们彼此之间的相似程度:

用da构建一个实时推荐引擎

现在,向量有两个长度:

用da构建一个实时推荐引擎

现在,我们应用欧几里得距离来找到这两点之间的距离:

用da构建一个实时推荐引擎

当我们插入所有数字时,我们得到以下相似性度量,它实际上是两个用户之间的距离度量:

用da构建一个实时推荐引擎

您可以在Cypher中轻松地在两个特定用户之间进行此操作,特别是如果他们只喜欢一小部分地方。
同样,在这里我们要匹配两个用户Alice和Greta,并试图找到他们共同喜欢的地方:

用da构建一个实时推荐引擎

它们都必须与要在此结果中找到位置的关系有关,然后我们可以轻松地用它们在Cypher中平方差之和的平方根来计算它们之间的欧几里得距离。

While this may work in an example with two specific people, it doesn’t necessarily work in real time when you’re trying to infer similar users from another user on the fly, by comparing them against every other user in the database in real time。 不用说,这不是很好。

为了找到解决此问题的方法,我们预先计算了此计算并将其存储在实际关系中:

用da构建一个实时推荐引擎

虽然在大型数据集中,我们将分批执行此操作,但在此小型示例数据集中,我们可以匹配所有用户和他们共同喜欢的地点的笛卡尔积。
这只是一个技巧,可确保您不会在左右两边都找不到同一对。

然后,根据它们的欧几里得距离和它们自己,我们将在它们之间创建一个关系,并将其设置为。
从理论上讲,我们还可以在用户之间的某些关系上存储其他相似性度量,以捕获不同的相似性度量,因为在某些情况下某些度量可能比其他度量更有用。

正是这种在Neo4j中为关系上的属性建模的能力使这种事情变得异常简单。
但是,实际上,您不希望存储可能存在的每一个关系,因为您只想返回邻居的头几个人。

因此,您可以仅根据某个阈值存储顶部,这样就不会拥有完全连接的图表。
这样,您就可以实时执行如下所示的图形数据库查询,因为我们已经对其进行了预先计算并将其存储在关系中,并且在Cypher中,我们将能够非常迅速地进行查询:

用da构建一个实时推荐引擎

在此查询中,我们匹配的是地点和类别:

用da构建一个实时推荐引擎

同样,前三行相同,除了登录用户外,我们得到的用户与他们之间有密切的联系。
这就是我们之前介绍的内容发挥作用的地方–实际上,您应该只将最重要的关系存储给与他们相似的用户,这样您就不会在此子句中吸引大量用户。
取而代之的是,我们吸引的是与他们有远距离关系的用户,他们喜欢那个地方。

这使我们仅用几行就可以表达出某种复杂的模式。
我们还将获取关系并将其放在变量中,因为稍后将使用这些权重来应用评分。

在此重要的是,由于这是一个距离指标,因此我们要按用户的升序对他们进行排序,并且我们希望距离最小,因为这表明他们是最相似的。

根据欧几里德距离排序的其他用户,我们将收集前三名用户的评分,并使用这些评分作为我们的平均分数来推荐这些地点。
换句话说,我们选择了一个活跃用户,根据他们喜欢的位置找到了与他们最相似的数据库同步 用户,然后对这些相似用户给出的分数进行平均,以在结果集中对这些位置进行排名。

我们实质上是在这里取一个平均值,将其加起来并除以集合中元素的数量,然后按该平均值递增的顺序进行排序。
其次,我们按登机口距离排序。
假设,我想可能会有联系,然后您按门距排序,然后返回名称,类别,门和终端。

我们的最后一个示例将是群集建议,可以将其视为离线计算的工作流,这可能是Cypher中的一种解决方法。
基于以下原因,现在可能已过时

GraphConnect Europe宣布了新的程序,但有时您必须执行Cypher版本2的某些算法方法。
3不暴露。

在这里,您可以使用某种形式的统计软件,将Neo4j中的数据提取到诸如Apache Spark,R或Python之类的软件中。
下面是一个R代码示例,用于从Neo4j中提取数据,运行算法,然后(如果适用)将该算法的结果作为属性,节点,关系或新标签写回到Neo4j中。

通过将该算法的结果持久化到图中,您可以将其实时用于与我们刚刚研究过的查询类似的查询:

用da构建一个实时推荐引擎

以下是一些有关如何在R中执行此操作的示例代码,但是您可以使用自己最熟悉的任何软件(例如Python或Spark)轻松地执行相同的操作。
您要做的就是登录并连接到图形。

在以下示例中,我根据用户的相似性将他们聚在一起。
每个用户都表示为一个观察值,我希望获得他们给每个类别的平均评分:

用da构建一个实时推荐引擎

大概,以类似方式对条形类别进行评分的用户通常是相似的。
在这里,我获取了喜欢同一类别中地点的用户的名称,类别名称以及“喜欢”关系的平均权重(作为平均权重),这将为我提供一个表格,如下所示:

用da构建一个实时推荐引擎

因为我们希望每个用户都可以观察,所以我们必须操纵数据,其中每个功能都是他们给该类别中每个类别的餐厅的平均体重等级。
然后,我们将使用它来确定它们的相似程度,并且我将使用聚类算法来确定不同集群中的用户。

在R中,这非常简单:

用da构建一个实时推荐引擎

对于此演示,我们使用k-means,它使您可以轻松地获取集群分配。
总而言之,我运行了一个群集算法,现在为每个用户分配了一个群集。

Bob和David处于同一个群集中-他们位于第二群集中-现在我可以实时查看已确定哪些用户位于同一群集中。

接下来,我们将其写入CSV,然后将其加载到图形中:

用da构建一个实时推荐引擎

我们有用户和集群分配,因此CSV只有两列。
是Cypher内建的语法,可让您从某些文件路径或URL调用CSV,并将其作为别名。
然后,我们将匹配图中已存在的用户,从CSV中获取用户列,然后在集群上进行合并。

在这里,我们在图中创建了一个新的标记节点,该节点由k-means给出。
接下来,我们在用户和集群之间创建关系,这使我们可以轻松查询到相同集群中的实际推荐用户。

现在,我们有了一个新的标签集群,其中同一个集群中的用户与该集群有关系。
下面是我们探索的其他数据模型之上的新数据模型:

用da构建一个实时推荐引擎

现在,考虑以下查询:

用da构建一个实时推荐引擎

借助此Cypher查询,我们不仅将相似的用户扩展到了同一集群中的用户。
此时,我们还删除了这些距离关系:

用da构建一个实时推荐引擎

在此查询中,我们采用了已登录的用户,根据用户-集群关系找到他们的集群,并找到在同一集群中的邻居。

We’ve assigned that to some variable , and we’re getting other users — which I’ve aliased as a variable — who have a user-cluster relationship to that same cluster, and then we’re getting the places that neighbor has liked。
再次,我们将“喜欢”放在变量上,因为我们要从关系中获取权重以对结果进行排序。

我们在查询中所做的全部更改是,我们不使用相似距离,而是在同一集群中捕获用户,声明类别,声明终端,并断言我们仅捕获已登录的用户。
我们正在从邻居喜欢的地方收集所有“喜欢”关系的权重,获取类别,距离的绝对值,以降序排列并返回结果。

在这些示例中,我们能够进行一个相当复杂的过程并将其保留在图形中,然后实时使用该算法的结果-聚类算法和聚类分配的结果。

我们首选的工作流程是按照您认为合适的频率(例如,每晚或每小时)更新这些群集分配。
而且,当然,您可以凭直觉确定更新这些群集分配的可接受频率。