Find “friends of friends” with OrientDB SQL

前端 未结 3 588
自闭症患者
自闭症患者 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:26

    Have you tried this?

    select 
          expand(bothE('is_friend_with')[status = 'approved'].inV().bothE('is_friend_with')[status = 'approved'].inV()) 
    from user where uuid = '95920a96a60c4d40a8f70bde98ae1a24'
    
    0 讨论(0)
  • 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")
    
    0 讨论(0)
  • 2021-01-25 07:45

    This should be much simpler:

    select expand(
      bothE('is_friend_with')[status = 'approved'].bothV()
      .bothE('is_friend_with')[status = 'approved'].bothV()
    ) from user where uuid = '95920a96a60c4d40a8f70bde98ae1a24'
    

    With bothE() and then bothV() you get both in/out connections at edge/vertex level.

    In order to exclude current user you could use:

    select expand(
      bothE('is_friend_with')[status = 'approved'].bothV()
      .bothE('is_friend_with')[status = 'approved'].bothV()
      .remove( @this )
    ) from user where uuid = '95920a96a60c4d40a8f70bde98ae1a24'
    
    0 讨论(0)
提交回复
热议问题