Comment enregistrez-vous les relations dans NoSQL?

117

J'essaie de comprendre l'équivalent des clés étrangères et des index dans les bases de données NoSQL KVP ou Document. Puisqu'il n'y a pas de tableaux croisés dynamiques (pour ajouter des clés marquant une relation entre deux objets), je suis vraiment perplexe quant à la façon dont vous pourriez récupérer des données d'une manière qui serait utile pour les pages Web normales.

Disons que j'ai un utilisateur, et cet utilisateur laisse de nombreux commentaires sur tout le site. Le seul moyen auquel je pense pour suivre les commentaires des utilisateurs est de

  1. Intégrez-les dans l'objet utilisateur (ce qui semble assez inutile)
  2. Créez et maintenez une user_id:commentsvaleur qui contient une liste de la clé de chaque commentaire [commentaire: 34, commentaire: 197, etc ...] afin que je puisse les récupérer si nécessaire.

Cependant, en prenant le deuxième exemple, vous allez bientôt heurter un mur de briques lorsque vous l'utilisez pour suivre d'autres choses comme une clé appelée "active_comments" qui peut contenir 30 millions d'identifiants, ce qui coûte une TONNE d'interroger chaque page juste pour en savoir plus commentaires actifs. Il serait également très sujet aux conditions de course, car de nombreuses pages pourraient essayer de le mettre à jour en même temps.

Comment puis-je suivre des relations comme les suivantes dans une base de données NoSQL?

  • Tous les commentaires d'un utilisateur
  • Tous les commentaires actifs
  • Tous les messages tagués avec [mot-clé]
  • Tous les étudiants d'un club - ou tous les clubs auxquels appartient un étudiant

Ou est-ce que je pense mal à cela?

Xeoncross
la source
Il n'y a pas une seule façon de le faire dans les bases de données NoSQL, cette question est plutôt une question de savoir comment puis-je suivre les relations dans les programmes C.
stonemetal
3
Wow, alors je suppose que le battage médiatique autour du remplacement de SGBDR par NoSQL est impossible.
Xeoncross
11
Oui, NoSQL est définitivement surhypé. Je ne dis pas que les nouvelles technologies ne sont pas utiles dans les bonnes circonstances, mais il est ridicule de penser qu'elles remplaceront le SGBDR. Voir en.wikipedia.org/wiki/Hype_cycle
Bill Karwin
1
N'auriez-vous pas juste une collection "d'utilisateurs" et une collection de commentaires. Et puis, chaque commentaire comme une propriété «auteur» dont la valeur est une référence à un identifiant d'utilisateur?
CodeFinity

Réponses:

186

Toutes les réponses pour savoir comment stocker des associations plusieurs-à-plusieurs de la «manière NoSQL» se résument au même: stocker les données de manière redondante.

Dans NoSQL, vous ne concevez pas votre base de données en fonction des relations entre les entités de données. Vous concevez votre base de données en fonction des requêtes que vous exécuterez sur elle. Utilisez les mêmes critères que vous utiliseriez pour dénormaliser une base de données relationnelle: s'il est plus important que les données aient une cohésion (pensez aux valeurs dans une liste séparée par des virgules au lieu d'une table normalisée), alors faites-le de cette façon.

Mais cela optimise inévitablement pour un type de requête (par exemple les commentaires de tout utilisateur pour un article donné) au détriment d'autres types de requêtes (commentaires pour tout article par un utilisateur donné). Si votre application a besoin que les deux types de requêtes soient également optimisés, vous ne devez pas dénormaliser. Et de même, vous ne devez pas utiliser de solution NoSQL si vous devez utiliser les données de manière relationnelle.

La dénormalisation et la redondance risquent de voir des ensembles de données redondants se désynchroniser les uns avec les autres. C'est ce qu'on appelle une anomalie . Lorsque vous utilisez une base de données relationnelle normalisée, le SGBDR peut éviter les anomalies. Dans une base de données dénormalisée ou en NoSQL, il devient de votre responsabilité d'écrire le code de l'application pour éviter les anomalies.

On pourrait penser que ce serait formidable pour une base de données NoSQL de faire le dur travail de prévention des anomalies pour vous. Il existe un paradigme qui peut faire cela - le paradigme relationnel.

Bill Karwin
la source
20
"vous ne devriez pas utiliser une solution NoSQL si vous avez besoin d'utiliser les données d'une manière relationnelle" - Alors comment les autres exécutant NoSQL s'en sortent-ils? Comment pouvez-vous connaître toutes les façons dont vous interrogerez les données lors de la première conception de votre application? Exemple Fox, je pourrais vouloir des commentaires récents, des commentaires par utilisateur, des commentaires par tag, des commentaires pour un article donné, des commentaires marqués comme spam, des commentaires actifs, des commentaires les mieux notés, etc.
Xeoncross
14
Exactement - il n'y a rien de tel que "ça marche" comme les partisans de NoSQL aiment à le prétendre. Soit vous effectuez une série d'analyses à l'avance pour votre modélisation de données relationnelles, soit vous effectuez une série d'analyses à l'avance pour vos requêtes prioritaires, ou vous effectuez une refactorisation coûteuse tout au long du projet lorsque vous découvrez quelles parties de votre conception n'a pas obtenu suffisamment d'analyse à l'avance.
Bill Karwin
1
Si nous stockons des données de manière redondante, comment devrions-nous mettre à jour les choses? Par exemple, change son nom et il a écrit quelques commentaires. Son nom est déjà changé dans la collection d'utilisateurs, mais comment changer tous les noms stockés de manière redondante dans la collection de commentaires?
Mohammad Kermani
3
@ M98, Ah, vous avez trouvé la faiblesse de cette stratégie. Vous devez connaître tous les emplacements dont vous avez besoin pour mettre à jour, puis écrire du code dans votre application pour tous les mettre à jour lorsque vous mettez à jour l'un d'entre eux. Bonne chance!
Bill Karwin
2
Le même problème existe pour une base de données relationnelle dénormalisée .
Bill Karwin
5

L'approche couchDB suggère d'émettre des classes appropriées de trucs dans la phase de carte et de les résumer en réduire. Ainsi, vous pouvez mapper tous les commentaires et émettre 1pour l'utilisateur donné et en imprimer plus tard seulement. Il faudrait cependant beaucoup de stockage sur disque pour créer des vues persistantes de toutes les données traçables dans couchDB. btw ils ont aussi cette page wiki sur les relations: http://wiki.apache.org/couchdb/EntityRelationship .

Riak, d'autre part, a un outil pour construire des relations. C'est un lien. Vous pouvez saisir l'adresse d'un document lié (ici commentaire) dans le document «racine» (ici document utilisateur). Il a un truc. S'il est distribué, il peut être modifié en une seule fois dans de nombreux endroits. Cela provoquera des conflits et par conséquent un énorme arbre d'horloge vectorielle: / ..pas si mal, pas si bon.

Riak a également un autre «mécanisme». Il dispose d'un espace de nom de clé à 2 couches, appelé seau et clé. Ainsi, par exemple étudiant, si nous avons les clubs A, B et C et étudiant StudentX, StudentY, vous pouvez maintenir la convention suivante:

{ Key = {ClubA, StudentX}, Value = true }, 
{ Key = {ClubB, StudentX}, Value = true }, 
{ Key = {ClubA, StudentY}, Value = true }

et pour lire la relation, il suffit de lister les clés dans des compartiments donnés. Qu'est-ce qui ne va pas avec ça? C'est sacrément lent. La liste des seaux n'a jamais été une priorité pour riak. Cela va de mieux en mieux. btw. vous ne gaspillez pas de mémoire car cet exemple {true}peut être lié à un seul profil complet de StudentX ou Y (ici les conflits ne sont pas possibles).

Comme vous le voyez NoSQL! = NoSQL. Vous devez examiner une implémentation spécifique et la tester par vous-même.

Mentionné avant Les magasins de colonnes semblent bien adaptés aux relations .. mais tout dépend de vos besoins A, C et P;) Si vous n'avez pas besoin de A et que vous avez moins de Peta octets, laissez-le simplement, continuez avec MySql ou Postgres.

bonne chance

user425720
la source
1
Riak a récemment publié la v1.0, qui ajoute la prise en charge des index secondaires lors de l'utilisation du backend LevelDB. Fonctionnalité très précieuse.
Jon L.
4
  1. user: userid: comments est une approche raisonnable - pensez-y comme l'équivalent d'un index de colonne en SQL, avec l'exigence supplémentaire que vous ne pouvez pas interroger sur les colonnes non indexées.

  2. C'est là que vous devez réfléchir à vos besoins. Une liste de 30 millions d'articles n'est pas déraisonnable parce qu'elle est lente, mais parce qu'il est impossible d'en faire quoi que ce soit. Si votre véritable exigence est d'afficher des commentaires récents, vous feriez mieux de garder une liste très courte qui est mise à jour chaque fois qu'un commentaire est ajouté - rappelez-vous que NoSQL n'a aucune exigence de normalisation. Les conditions de concurrence sont un problème avec les listes dans un magasin de valeurs de clés de base, mais généralement, soit votre plate-forme prend en charge correctement les listes, vous pouvez faire quelque chose avec des verrous, ou vous ne vous souciez pas réellement des mises à jour qui ont échoué.

  3. Idem que pour les commentaires des utilisateurs - créez un mot-clé d'index: posts

  4. Plus de la même chose - probablement une liste des clubs en tant que propriété de l'étudiant et un index sur ce domaine pour obtenir tous les membres d'un club

Tom Clarkson
la source
Donc, fondamentalement, tout a juste besoin de listes? Il semble qu'il devrait y avoir une approche plus sophistiquée que le simple suivi manuel des chaînes d'identifiants. D'une part, vous ne pouvez aller aussi loin avant qu'ils deviennent trop gros pour être utiles. Là encore, les principaux projets poster-child de la technologie NoSQL (MongoDB, CouchDB, Membase, etc.) sont tous de nouveaux projets, alors j'ai peut-être juste besoin de leur donner plus de temps pour trouver un meilleur moyen de suivre les relations.
Xeoncross
Si vous utilisez NoSQL (magasins de données non relationnels AKA), vous devez arrêter de penser en termes relationnels. L'approche utilisée sera différente selon les plates-formes, mais l'idée de base que vous devez gérer les index est assez universelle. Les exemples de relations que vous avez donnés sont modélisés de deux manières différentes dans NoSQL: 1) Stockage - contrairement à SQL, les colonnes peuvent avoir des valeurs multiples / complexes, de sorte que l'objet enfant fait simplement partie de l'objet parent. 2) Recherche - Vos longues listes sont en fait une exigence pour la recherche, ce qui signifie l'indexation - vous pouvez utiliser une simple liste personnalisée ou un moteur de recherche plus complet.
Tom Clarkson
2

Tu as

"user": {
    "userid": "unique value",
    "category": "student",
    "metainfo": "yada yada yada",
    "clubs": ["archery", "kendo"]
}

"comments": {
    "commentid": "unique value",
    "pageid": "unique value",
    "post-time": "ISO Date",
    "userid": "OP id -> THIS IS IMPORTANT"
}

"page": {
    "pageid": "unique value",
    "post-time": "ISO Date",
    "op-id": "user id",
    "tag": ["abc", "zxcv", "qwer"]
}

Eh bien, dans une base de données relationnelle, la chose normale à faire serait de normaliser les données dans une relation un-à-plusieurs. C'est la même chose que vous feriez dans une base de données NoSQL. Indexez simplement les champs avec lesquels vous allez récupérer les informations.

Par exemple, les index importants pour vous sont

  • Commentaire.UserID
  • Commentaire.PageID
  • Comment.PostTime
  • Page.Tag []

Si vous utilisez NosDB (une base de données NoSQL basée sur .NET avec prise en charge SQL), vos requêtes seront comme

 SELECT * FROM Comments WHERE userid = That user’;

 SELECT * FROM Comments WHERE pageid = That user’;

 SELECT * FROM Comments WHERE post-time > DateTime('2016, 1, 1');

 SELECT * FROM Page WHERE tag = 'kendo'

Vérifiez tous les types de requêtes pris en charge à partir de leur aide-mémoire SQL ou de leur documentation.

Basit Anwer
la source