我正在使用一个推荐系统来推荐其他用户。第一个结果应该是与“搜索者”用户最“相似”的用户。用户回答问题和以相同方式回答问题的数量就是相似性的数量。问题是我不知道如何编写查询]
因此,用技术术语来说,我需要按具有特定属性值的边的数量对用户进行排序,我尝试使用此查询,我认为它应该可以工作,但是不起作用:
let query = g.V().hasLabel('user');
let search = __;
for (const question of searcher.questions) {
search = search.outE('response')
.has('questionId', question.questionId)
.has('answerId', question.answerId)
.aggregate('x')
.cap('x')
}
query = query.order().by(search.unfold().count(), order.asc);
引发此gremlin内部错误:
org.apache.tinkerpop.gremlin.process.traversal.step.util.BulkSet cannot be cast to org.apache.tinkerpop.gremlin.structure.Vertex
我也为每个问题尝试了多个.by()
,但结果的符合程度并没有排序。
如何编写此查询?
[当您cap()
是一个aggregate()
时,它会返回一个BulkSet
,它是一个Set
,该计数对每个对象在该Set
中存在的次数进行计数。通过展开每个对象与计数的关联大小对其进行迭代时,其行为类似于List
。因此,由于cap('x')
的输出为BulkSet
,但由于要在循环中构建search
,因此您基本上会在该outE('response')
上调用BulkSet
,而这是无效的语法,因为has()
期望由错误指示的图形Element
,例如Vertex
。
我认为您希望选择更类似的东西:
let query = g.V().hasLabel('user').
outE('response');
let search = [];
for (const question of searcher.questions) {
search.push(has('questionId', question.questionId).
has('answerId', question.answerId));
}
query = query.or(...search).
groupCount().
by(outV())
order(local).by(values, asc)
我可能没有完全正确的JavaScript语法(并且我在spread syntax中使用了or()
只是为了快速传达需要发生的事情的想法),但基本上,这里的想法是过滤与您的问题标准相匹配的边,然后使用groupCount()
计数这些边。
首先,我认为您可能会为数据考虑不同的架构,这可能会使此推荐算法更像图。一种想法可能是使问题/答案成为一个顶点(也许是“ qa”标签),并使边缘从用户顶点延伸到“ qa”顶点。然后,用户直接链接到他们给出的问题。您可以通过边缘轻松地看到直接的关系,即用户给出了相同的问题/答案组合。当问到“哪些用户以用户'A'的相同方式回答问题?”时,该更改使查询的流动更加自然。
g.V().has('person','name','A'). out('responds'). in('responds'). groupCount(). order(local).by(values)
通过该更改,您可以看到我们可以摆脱所有这些
has()
过滤器,因为它们由“响应”边隐式暗示,这些边将它们编码为图形数据本身。