Groovy 具有Gremlin的二部图上的随机游动

Groovy 具有Gremlin的二部图上的随机游动,groovy,gremlin,bipartite,graph-traversal,random-walk,Groovy,Gremlin,Bipartite,Graph Traversal,Random Walk,我想使用groovy中的gremlin,根据给定的用户偏好(用户喜欢的项目)在有向二部图上随机游走,对项目进行排序 该图具有以下基本结构: [User1]--“喜欢”-->[ItemA][ItemB] 以下是我提出的问题: def runRankQuery(def userVertex) { def m = [:] def c = 0 while (c < 1000) { userVertex .out('likes')

我想使用groovy中的gremlin,根据给定的用户偏好(用户喜欢的项目)在有向二部图上随机游走,对项目进行排序

该图具有以下基本结构:

[User1]--“喜欢”-->[ItemA][ItemB]

以下是我提出的问题:

def runRankQuery(def userVertex) {
    def m = [:]
    def c = 0
    while (c < 1000) {
        userVertex
            .out('likes')   // get all liked items of current or similar user
            .shuffle[0]     // select randomly one liked item
            .groupCount(m)  // update counts for selected item
            .in('likes')    // get all users who also liked item
            .shuffle[0]     // select randomly one user that liked item
            .loop(5){Math.random() < 0.5}   // follow liked edge of new user (feed new user in loop) 
                                            // OR abort query (restart from original user, outer loop)      
            .iterate()
        c++
    }
    m = m.sort {a, b -> b.value <=> a.value}
    println "intermediate result $m"
    m.keySet().removeAll(userVertex.out('likes').toList())
    // EDIT (makes no sense - remove): m.each{k,v -> m[k] = v / m.values().sum()}
    // EDIT (makes no sense - remove): m.sort {-it.value }
    return m.keySet() as List;
}
以及输出:

intermediate result [v[2]:1000]
[]
==>null
gremlin> g.v(2).name
==>ItemA
gremlin> 

我发现这是一个非常奇怪的问题。我发现了几个很奇怪的问题,很难解释。最后,我不知道为什么会这样。我觉得奇怪的两件大事是:

  • 我不确定洗牌步骤是否有问题。在您的案例中,它似乎没有正确地随机化。我似乎无法在本案例之外重现问题,因此我不确定它是否与您的数据大小或其他因素有关
  • 使用
    Math.random()
    打破循环,我遇到了一些奇怪的问题 无论如何,我想我已经抓住了您代码的精髓,我的更改似乎满足了您的要求:

    runRankQuery = { userVertex ->
        def m = [:]
        def c = 0
        def rand = new java.util.Random()
        while (c < 1000) {
            def max = rand.nextInt(10) + 1
            userVertex._().as('x')
                .out('likes')   
                .gather.transform{it[rand.nextInt(it.size())]}
                .groupCount(m) 
                .in('likes')    
                .gather.transform{it[rand.nextInt(it.size())]}
                .loop('x'){it.loops < max}  
                .iterate()
            c++
        }
        println "intermediate result $m"
        m.keySet().removeAll(userVertex.out('likes').toList())
        m.each{k,v -> m[k] = v / m.values().sum()}
        m.sort {-it.value }
        return m.keySet() as List;
    }
    

    您可能仍然可以使用
    Math.random()
    ,因为在使用该工具的某些迭代中,它的行为是可以预测的

    非常感谢你的解决方案,斯蒂芬。它有点像我想要它做的。然而,您的更改给我留下了许多其他问题:1)为什么我们需要
    ?2) 那么
    shuffle
    的问题是否需要在某个地方进行跟踪?3) 如果我将
    loop
    命令更改为
    .loop('x'){println“gremlnloopcount:${it.loops}/$max;it.loops
    我发现循环计数总是从3(!)开始,然后增加+2,那么在
    聚集之后为什么不需要
    分散
    。我甚至看到了类似于
    gremlinopcount:3/0
    的输出。这怎么可能?5) 因此,如果我们从可变行走长度(
    Math.random()<0.5
    )更改为固定步数(
    it.loops
    ),该算法仍然可以被视为具有远程传送/重启功能的随机行走吗?我不这么认为。我只是用
    (
    )用
    x
    标记要循环的步骤。我不认为你可以直接使用
    作为一个顶点。我无法重新设置
    洗牌问题,因此我不确定这是否是一个bug。如果您有简单情况下的复制步骤,则可以在管道中创建问题。我从管道中随机选择了一个项目,因此我在
    转换中展开了
    列表
    loop
    是宽度优先的,因此您不能期望
    printlin it.loop
    按顺序打印任何内容。它可能看起来像是两次递增,但事实并非如此。还要注意,计数从技术上讲是从“2”开始的——我想你可能会认为它是“一次递减”。这在TinkerPop3中已修复。从技术上讲,这意味着我们应该看到总是从2开始的输出,我必须承认,我现在没有看到-需要进一步研究。我认为“0”是
    max
    的有效值,因为兰德应该给你一个介于0和9之间的值(10是互斥的)。编辑我的答案以添加1。不确定使用这种方法是否打破了随机行走的经典概念。这取决于您:)您可以尝试再次使用
    rand
    var来打破循环。我只知道我似乎有问题,我没有进一步探讨。也许我的问题与洗牌有关。
    runRankQuery = { userVertex ->
        def m = [:]
        def c = 0
        def rand = new java.util.Random()
        while (c < 1000) {
            def max = rand.nextInt(10) + 1
            userVertex._().as('x')
                .out('likes')   
                .gather.transform{it[rand.nextInt(it.size())]}
                .groupCount(m) 
                .in('likes')    
                .gather.transform{it[rand.nextInt(it.size())]}
                .loop('x'){it.loops < max}  
                .iterate()
            c++
        }
        println "intermediate result $m"
        m.keySet().removeAll(userVertex.out('likes').toList())
        m.each{k,v -> m[k] = v / m.values().sum()}
        m.sort {-it.value }
        return m.keySet() as List;
    }
    
    gremlin> runRankQuery(user1)                                       
    intermediate result [v[2]:1787, v[3]:326]
    ==>v[3]
    gremlin> runRankQuery(user1)
    intermediate result [v[2]:1848, v[3]:330]
    ==>v[3]
    gremlin> runRankQuery(user1)
    intermediate result [v[2]:1899, v[3]:339]
    ==>v[3]
    gremlin> runRankQuery(user1)
    intermediate result [v[2]:1852, v[3]:360]
    ==>v[3]