在Redis中搜索用户并按大多数共同朋友排序?

时间:2016-11-17 22:36:06

标签: c# sql .net sql-server redis

我有一个拥有500万用户的潜在数据库,每个用户都有一定数量的朋友。我需要做的是实现搜索,这样用户可以按某些属性(即其他用户的性别等)进行过滤,这部分相当简单。

  

用户A搜索所有男性并获取结果集。用户B,用户C,用户D

但是,用户还应该可以选择按用户A与结果集中所有用户的共同朋友数量对搜索结果进行排序

  

假设
     用户A和用户B = 3个相互朋友
     用户A和用户C = 8个相互朋友
     用户A和用户D = 5个相互朋友

然后,搜索应按以下顺序对结果进行排序

  

用户C,用户D,用户A

最重要的是,由于结果将显示在网页上,我也需要支持分页,因此每次用户在搜索结果之间导航时,都不会处理所有500万条左右的条目。

Web代码是用C#编写的,但就数据库而言,我非常开放,可以使用SQL,NoSQL或Redis。主要优先考虑的是高性能,因此Redis似乎是一个不错的选择。如何从数据存储区和伪代码的角度实现这样的搜索要求?

2 个答案:

答案 0 :(得分:1)

在redis中,您可能希望将其存储在zset中;红色中没有内置的自动索引,因此当您添加或删除朋友时,您需要zaddzincrbyzincrby以减去负数)。然后,您只需zrangezrangebyscore即可查询。这些方法都可以在NuGet上SortedSet包中的StackExchange.Redis前缀下使用。

答案 1 :(得分:1)

我的两分钱。

如果您将性别索引保持为Set,则可以利用ZINTERSTORE,并且共同的朋友计为每个用户的SortedSet(分数是共同的朋友数)。 此外,每位用户还需要一组朋友。

对于性别使用,使用密钥格式设置为gender:{gender},每个项目都是用户ID。

对于朋友,请使用包含密钥格式的设置:friends:{userId},每个项目都是用户ID。

对于共同的朋友,请使用密钥格式为mutual:{userId}的SortedSet,每个项目都是用户ID,分数将是普通朋友的数量。

因此,在添加用户时:

void AddUser(string user, string gender)
{
    // Add to a gender set  "gender:{gender}"->{users}
    db.SetAdd($"gender:{gender}", user);
}

在两个用户之间添加友谊:

void AddFriendship(string user1, string user2)
{
    // All friends of user1, should increment its mutual count with user2
    var user1Friends = db.SetMembers($"friends:{user1}");
    foreach(var user1Friend in user1Friends)
    {
        db.SortedSetIncrement($"mutual:{user1Friend}", user2, 1);
        db.SortedSetIncrement($"mutual:{user2}", user1Friend, 1);
    }

    // All friends of user2, should increment its mutual count with user1
    var user2Friends = db.SetMembers($"friends:{user2}");
    foreach (var user2Friend in user2Friends)
    {
        db.SortedSetIncrement($"mutual:{user2Friend}", user1, 1);
        db.SortedSetIncrement($"mutual:{user1}", user2Friend, 1);
    }

    // Add to friend sets   "friends:{user}->{users}"
    db.SetAdd($"friends:{user1}", user2);
    db.SetAdd($"friends:{user2}", user1);
}

并按共同朋友的顺序排列用户:

static IEnumerable<string> GetUsersByGenderOrderByMutualFriends(string user, string gender)
{
    var db = mux.GetDatabase();
    var tempKey = "temp";
    db.SortedSetCombineAndStore(SetOperation.Intersect, tempKey, $"gender:{gender}", $"mutual:{user}", Aggregate.Sum);
    var result = db.SortedSetRangeByRank(tempKey, 0, -1, Order.Descending).Select(x => x.ToString());
    db.KeyDelete(tempKey);
    return result;
}