Find “friends of friends” with OrientDB SQL

前端 未结 3 589
自闭症患者
自闭症患者 2021-01-25 06:42

Although one of the most common use cases for demonstrating the capabilities of a graph database, I cannot seem to find a good example or best practice for obtaining \"friends o

3条回答
  •  面向向阳花
    2021-01-25 07:35

    There may be a nicer way to do it, but I think this gives you what you're looking for:

    Setup:

    create class User extends V
    create class IsFriendsWith extends E
    create property User.name string
    create property User.uuid string
    create property IsFriendsWith.status string
    
    create vertex User set uuid = "1", name = "Bob"
    create vertex User set uuid = "2", name = "Sally"
    create vertex User set uuid = "3", name = "Eric"
    create vertex User set uuid = "4", name = "Jenny"
    create vertex User set uuid = "5", name = "Dennis"
    create vertex User set uuid = "6", name = "Mary"
    create vertex User set uuid = "7", name = "John"
    
    create edge IsFriendsWith from (select from User where uuid = "1") to (select from User where uuid = "2") set status = "approved"
    create edge IsFriendsWith from (select from User where uuid = "1") to (select from User where uuid = "3") set status = "pending"
    create edge IsFriendsWith from (select from User where uuid = "2") to (select from User where uuid = "4") set status = "approved"
    create edge IsFriendsWith from (select from User where uuid = "5") to (select from User where uuid = "2") set status = "pending"
    create edge IsFriendsWith from (select from User where uuid = "3") to (select from User where uuid = "4") set status = "approved"
    create edge IsFriendsWith from (select from User where uuid = "6") to (select from User where uuid = "1") set status = "approved"
    create edge IsFriendsWith from (select from User where uuid = "6") to (select from User where uuid = "7") set status = "approved"
    

    Query:

    select from (
        select 
          expand(unionall(
            outE("IsFriendsWith")[status="approved"].inV(), 
            inE("IsFriendsWith")[status="approved"].outV()
          ))
          from (
            select 
                expand(unionall(
                  outE("IsFriendsWith")[status="approved"].inV(), 
                  inE("IsFriendsWith")[status="approved"].outV()
                ))
            from (
              select from User where uuid = "1"
            )
          )
      )
    ) where uuid <> "1"
    

    Enrico's answer won't give you quite what you're after because it only takes into account edges in one direction when it needs to work both ways.

    Edit: To exclude people that the user happens to be friends with already, use the following (note that this example assumes the User's RID is #26:0)

      select from (
          select 
            expand(unionall(
              outE("IsFriendsWith")[status="approved"].inV(), 
              inE("IsFriendsWith")[status="approved"].outV()
            ))
            from (
              select 
                  expand(unionall(
                    outE("IsFriendsWith")[status="approved"].inV(), 
                    inE("IsFriendsWith")[status="approved"].outV()
                  ))
              from #26:0          
            )
        )
      )
      where @rid <> #26:0 and @rid NOT IN (select both("IsFriendsWith") from #26:0)
    

    Edit 2: Using variables instead.

     select from (
          select 
            expand(unionall(
              outE("IsFriendsWith")[status="approved"].inV(), 
              inE("IsFriendsWith")[status="approved"].outV()
            ))
            from (
              select 
                  expand(unionall(
                    outE("IsFriendsWith")[status="approved"].inV(), 
                    inE("IsFriendsWith")[status="approved"].outV()
                  ))
              from (
                 select expand($u) let $u = first((select from User where uuid = "1"))
              )
            )
        )
      )
      where @rid <> $u and @rid NOT IN $u.both("IsFriendsWith")
    

提交回复
热议问题