Rechercher des users et sortinger par le plus grand nombre d'amis communs dans Redis?

J'ai une database potentielle de 5 millions d'users, où chaque user a un certain nombre d'amis. Ce que je dois faire est de mettre en œuvre la search, de sorte que les users peuvent filterr selon certains attributes (c'est-à-dire le sexe d'un autre user, etc.), cette partie est assez simple.

L'user A search tous les mâles et obtient le jeu de résultats. Utilisateur B, Utilisateur C, Utilisateur D

Cependant, l'user doit également avoir la possibilité de sortinger les résultats de la search par le nombre d'amis communs que l'user A a avec tous les users du jeu de résultats.

En supposant
Utilisateur A ET Utilisateur B = 3 amis communs
Utilisateur A ET Utilisateur C = 8 amis communs
Utilisateur A ET Utilisateur D = 5 amis communs

Ensuite, la search devrait sortinger les résultats dans l'ordre suivant

Utilisateur C, Utilisateur D, Utilisateur A

En plus de cela, puisque les résultats seront affichés sur une page Web, j'ai également besoin de support pour la pagination, de sorte que toutes les 5 millions d'inputs ne sont pas traitées chaque fois que l'user navigue entre les résultats de search.

Le code web est en train d'être écrit en C #, mais en termes de database, je suis assez ouvert et je peux utiliser SQL, NoSQL ou Redis. La priorité principale est la haute performance, donc Redis semble être une bonne option. Comment mettre en œuvre une telle exigence de search à partir du datastore et du pseudo-code?

En redis, vous voudrez probablement stocker cela dans un zset ; il n'y a pas d'indexing automatique embeddede en rouge, vous aurez donc besoin de zadd ou zincrby lorsque vous ajoutez ou supprimez des amis ( zincrby avec un nombre négatif à soustraire). Ensuite, vous pourriez zrange ou zrangebyscore pour l'interroger. Ces methods sont toutes disponibles sous le préfixe StackExchange.Redis dans le package StackExchange.Redis sur NuGet.

Mes deux centimes.

Vous pourriez profiter de ZINTERSTORE si vous maintenez l'index de genre en tant que Set, et les amis communs countnt comme SortedSet pour chaque user (le score est le nombre d'amis communs). De plus, vous aurez besoin d'un set d'amis par user.

Pour le genre, utilisez un Set avec le format de key: gender:{gender} et chaque élément sera un identifiant d'user.

Pour les amis, utilisez un Set au format key: friends:{userId} et chaque élément sera un identifiant user.

Pour les amis communs, utilisez un SortedSet avec le format de key: mutual:{userId} , chaque élément sera un identifiant d'user et le score sera le nombre d'amis communs.

Ainsi, lorsque vous ajoutez un user, vous faites:

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

Pour append une amitié entre deux users:

 void AddFriendship(ssortingng user1, ssortingng 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); } 

Et pour get les users par sexe classés par nombre d'amis communs:

 static IEnumerable<ssortingng> GetUsersByGenderOrderByMutualFriends(ssortingng user, ssortingng 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.ToSsortingng()); db.KeyDelete(tempKey); return result; }