¿Cómo se registran las relaciones en NoSQL?

117

Estoy tratando de averiguar el equivalente de claves e índices externos en NoSQL KVP o bases de datos de documentos. Dado que no hay tablas pivotales (para agregar claves que marcan una relación entre dos objetos), estoy realmente perplejo en cuanto a cómo podría recuperar datos de una manera que sería útil para páginas web normales.

Digamos que tengo un usuario, y este usuario deja muchos comentarios en todo el sitio. La única forma que se me ocurre para realizar un seguimiento de los comentarios de los usuarios es

  1. Incrustarlos en el objeto de usuario (que parece bastante inútil)
  2. Cree y mantenga un user_id:commentsvalor que contenga una lista de la clave de cada comentario [comentario: 34, comentario: 197, etc.] para que pueda recuperarlos según sea necesario.

Sin embargo, tomando el segundo ejemplo, pronto se encontrará con una pared de ladrillos cuando lo use para rastrear otras cosas, como una clave llamada "active_comments", que puede contener 30 millones de identificadores, por lo que cuesta una TONELADA consultar cada página solo para conocer algunos datos recientes. comentarios activos. También sería muy propenso a las condiciones de carrera, ya que muchas páginas podrían intentar actualizarlo al mismo tiempo.

¿Cómo puedo rastrear relaciones como las siguientes en una base de datos NoSQL?

  • Todos los comentarios de un usuario
  • Todos los comentarios activos
  • Todas las publicaciones etiquetadas con [palabra clave]
  • Todos los estudiantes en un club, o todos los clubes en los que está un estudiante

¿O estoy pensando en esto incorrectamente?

Xeoncross
fuente
No hay una forma única de hacerlo en las bases de datos NoSQL, esta pregunta es más bien similar a preguntar cómo haría un seguimiento de las relaciones en los programas C.
stonemetal
3
Vaya, entonces supongo que la publicidad sobre NoSQL reemplazando a RDBMS es imposible.
Xeoncross
11
Sí, NoSQL definitivamente está sobrevalorado. No digo que las nuevas tecnologías no sean útiles en las circunstancias adecuadas, pero es ridículo pensar que reemplazarán al RDBMS. Ver en.wikipedia.org/wiki/Hype_cycle
Bill Karwin
1
¿No tendrías simplemente una colección de 'usuarios' y una colección de comentarios? Y luego, ¿cada comentario es simplemente una propiedad de 'autor' cuyo valor es una referencia a una identificación de usuario?
CodeFinity

Respuestas:

186

Todas las respuestas sobre cómo almacenar asociaciones de varios a varios en la "forma NoSQL" se reducen a lo mismo: almacenar datos de forma redundante.

En NoSQL, no diseña su base de datos en función de las relaciones entre las entidades de datos. Usted diseña su base de datos basándose en las consultas que ejecutará contra ella. Use los mismos criterios que usaría para desnormalizar una base de datos relacional: si es más importante que los datos tengan cohesión (piense en valores en una lista separada por comas en lugar de en una tabla normalizada), hágalo de esa manera.

Pero esto inevitablemente se optimiza para un tipo de consulta (por ejemplo, comentarios de cualquier usuario para un artículo determinado) a expensas de otros tipos de consultas (comentarios de cualquier artículo de un usuario determinado). Si su aplicación necesita que ambos tipos de consultas estén igualmente optimizadas, no debe desnormalizar. Y del mismo modo, no debe utilizar una solución NoSQL si necesita utilizar los datos de forma relacional.

Con la desnormalización y la redundancia existe el riesgo de que los conjuntos de datos redundantes no estén sincronizados entre sí. Esto se llama anomalía . Cuando usa una base de datos relacional normalizada, el RDBMS puede prevenir anomalías. En una base de datos desnormalizada o en NoSQL, es su responsabilidad escribir el código de la aplicación para evitar anomalías.

Uno podría pensar que sería genial que una base de datos NoSQL hiciera el trabajo duro de prevenir anomalías por usted. Hay un paradigma que puede hacer esto: el paradigma relacional.

Bill Karwin
fuente
20
"No debe usar una solución NoSQL si necesita usar los datos de una manera relacional". Entonces, ¿cómo se salen con la suya otros que ejecutan NoSQL? ¿Cómo puede saber todas las formas en que consultará datos cuando diseñe su aplicación por primera vez? Ejemplo de Fox, podría querer comentarios recientes, comentarios por usuario, comentarios por etiqueta, comentarios para una publicación determinada, comentarios marcados como spam, comentarios activos, comentarios mejor calificados, etc.
Xeoncross
14
Exactamente, no existe tal cosa como "simplemente funciona" como les gusta afirmar a los defensores de NoSQL. O realiza un montón de análisis por adelantado para su modelado de datos relacionales, o hace un montón de análisis por adelantado para sus consultas de máxima prioridad, o realiza una refactorización costosa a lo largo del proyecto a medida que descubre qué partes de su diseño no obtuve suficiente análisis por adelantado.
Bill Karwin
1
Si almacenamos datos de forma redundante, ¿cómo deberíamos actualizar las cosas? Por ejemplo, cambia su nombre y escribe algunos comentarios. Su nombre ya se cambió en la colección de usuarios, pero ¿cómo cambiar todos los nombres almacenados de forma redundante en la colección de comentarios?
Mohammad Kermani
3
@ M98, Ah, has encontrado la debilidad en esta estrategia. Debe conocer todos los lugares que necesita actualizar y luego escribir código en su aplicación para actualizarlos todos cuando actualice alguno. ¡Buena suerte!
Bill Karwin
2
El mismo problema existe para una base de datos relacional desnormalizada .
Bill Karwin
5

El enfoque de couchDB sugiere emitir las clases adecuadas de material en la fase de mapa y resumirlo en reducción. De modo que podría asignar todos los comentarios y emitir 1para el usuario dado y luego imprimir solo algunos. Sin embargo, requeriría mucho almacenamiento en disco para crear vistas persistentes de todos los datos rastreables en couchDB. por cierto, también tienen esta página wiki sobre relaciones: http://wiki.apache.org/couchdb/EntityRelationship .

Riak, por otro lado, tiene una herramienta para construir relaciones. Es un enlace. Puede ingresar la dirección de un documento vinculado (aquí comentario) al documento 'raíz' (aquí documento de usuario). Tiene un truco. Si se distribuye, puede modificarse de una vez en muchas ubicaciones. Causará conflictos y, como resultado, un enorme árbol de reloj vectorial: / ..no tan malo, no tan bueno.

Riak también tiene otro 'mecanismo'. Tiene un espacio de nombre de clave de 2 capas, llamado cubo y clave. Entonces, por ejemplo de estudiante, si tenemos el club A, B y C y el estudiante StudentX, StudentY, podría mantener la siguiente convención:

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

y para leer la relación, simplemente enumere las claves en los depósitos dados. ¿Qué está mal con eso? Es muy lento. La lista de depósitos nunca fue una prioridad para riak. Sin embargo, se está poniendo cada vez mejor. por cierto. no desperdicia memoria porque este ejemplo {true}se puede vincular a un solo perfil completo de StudentX o Y (aquí los conflictos no son posibles).

Como lo ve NoSQL! = NoSQL. Debe observar la implementación específica y probarla usted mismo.

Mencionado antes, las tiendas de columnas parecen buenas para las relaciones ... pero todo depende de sus necesidades A, C y P;) Si no necesita A y tiene menos de Peta bytes, déjelo, continúe con MySql o Postgres.

buena suerte

user425720
fuente
1
Riak lanzó recientemente v1.0, que agrega soporte para índices secundarios cuando se usa el backend de LevelDB. Característica muy valiosa.
Jon L.
4
  1. user: userid: comments es un enfoque razonable; considérelo el equivalente de un índice de columna en SQL, con el requisito adicional de que no puede consultar en columnas no indexadas.

  2. Aquí es donde debe pensar en sus requisitos. Una lista con 30 millones de elementos no es descabellada porque sea lenta, sino porque no es práctico hacer nada con ella. Si su requisito real es mostrar algunos comentarios recientes, es mejor que mantenga una lista muy corta que se actualice cada vez que se agrega un comentario; recuerde que NoSQL no tiene ningún requisito de normalización. Las condiciones de carrera son un problema con las listas en un almacén básico de valores clave, pero en general, o su plataforma admite listas correctamente, puede hacer algo con bloqueos o, en realidad, no le importan las actualizaciones fallidas.

  3. Lo mismo que para los comentarios de los usuarios: cree una palabra clave de índice: publicaciones

  4. Más de lo mismo: probablemente una lista de clubes como propiedad de los estudiantes y un índice en ese campo para obtener todos los miembros de un club.

Tom Clarkson
fuente
Entonces, ¿básicamente todo solo necesita listas? Parece que debería haber un enfoque más sofisticado que simplemente realizar un seguimiento de las cadenas de identificadores manualmente. Por un lado, solo puede llegar hasta cierto punto antes de que sean demasiado grandes para ser útiles. Por otra parte, los principales proyectos secundarios de la tecnología NoSQL (MongoDB, CouchDB, Membase, etc.) son todos proyectos nuevos, por lo que tal vez solo necesite darles más tiempo para encontrar una mejor manera de rastrear las relaciones.
Xeoncross
Si está utilizando NoSQL (también conocido como almacenes de datos no relacionales), debe dejar de pensar en términos relacionales. El enfoque utilizado diferirá entre plataformas, pero la idea básica de que tienes que administrar índices es bastante universal. Los ejemplos de relaciones que ha proporcionado se modelan de dos maneras diferentes en NoSQL: 1) Almacenamiento: a diferencia de SQL, las columnas pueden tener valores múltiples / complejos, por lo que el objeto secundario es solo parte del objeto principal. 2) Búsqueda: sus listas largas son en realidad un requisito para la capacidad de búsqueda, lo que significa indexación; podría usar una lista personalizada simple o un motor de búsqueda más completo.
Tom Clarkson
2

Tienes

"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"]
}

Bueno, en una base de datos relacional, lo normal sería normalizar los datos en una relación de uno a muchos. Eso es lo mismo que haría en una base de datos NoSQL. Simplemente indexe los campos con los que obtendrá la información.

Por ejemplo, los índices importantes para usted son

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

Si está utilizando NosDB (una base de datos NoSQL basada en .NET con soporte SQL) sus consultas serán como

 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'

Verifique todos los tipos de consulta admitidos en su hoja de trucos o documentación de SQL .

Basit Anwer
fuente