Como você acompanha as relações de registro no NoSQL?

117

Estou tentando descobrir o equivalente a chaves estrangeiras e índices em bancos de dados NoSQL KVP ou Document. Uma vez que não há tabelas centrais (para adicionar chaves que marcam uma relação entre dois objetos), estou realmente perplexo sobre como você seria capaz de recuperar dados de uma forma que seria útil para páginas da web normais.

Digamos que eu tenha um usuário e esse usuário deixe muitos comentários em todo o site. A única maneira que consigo pensar para acompanhar os comentários dos usuários é

  1. Incorpore-os no objeto do usuário (o que parece bastante inútil)
  2. Crie e mantenha um user_id:commentsvalor que contém uma lista da chave de cada comentário [comentário: 34, comentário: 197, etc ...] para que eu possa buscá-los conforme necessário.

No entanto, tomando o segundo exemplo, você logo atingirá uma parede de tijolos ao usá-lo para rastrear outras coisas como uma chave chamada "active_comments", que pode conter 30 milhões de ids, fazendo com que custar uma tonelada para consultar cada página apenas para saber alguns comentários ativos. Também seria muito sujeito a condições de corrida, pois muitas páginas poderiam tentar atualizá-lo ao mesmo tempo.

Como posso rastrear relações como as seguintes em um banco de dados NoSQL?

  • Todos os comentários de um usuário
  • Todos os comentários ativos
  • Todas as postagens marcadas com [palavra-chave]
  • Todos os alunos em um clube - ou todos os clubes em que um aluno está

Ou estou pensando sobre isso incorretamente?

Xeoncross
fonte

Respostas:

186

Todas as respostas sobre como armazenar associações muitos para muitos no "modo NoSQL" se reduzem à mesma coisa: armazenamento de dados redundantemente.

No NoSQL, você não projeta seu banco de dados com base nos relacionamentos entre entidades de dados. Você projeta seu banco de dados com base nas consultas que executará nele. Use os mesmos critérios que você usaria para desnormalizar um banco de dados relacional: se for mais importante que os dados tenham coesão (pense em valores em uma lista separada por vírgulas em vez de em uma tabela normalizada), então faça dessa forma.

Mas isso inevitavelmente otimiza para um tipo de consulta (por exemplo, comentários de qualquer usuário para um determinado artigo) em detrimento de outros tipos de consultas (comentários para qualquer artigo de um determinado usuário). Se seu aplicativo precisa que ambos os tipos de consultas sejam igualmente otimizados, você não deve desnormalizar. E da mesma forma, você não deve usar uma solução NoSQL se precisar usar os dados de forma relacional.

Existe o risco de desnormalização e redundância de conjuntos redundantes de dados que fiquem fora de sincronia uns com os outros. Isso é chamado de anomalia . Quando você usa um banco de dados relacional normalizado, o RDBMS pode evitar anomalias. Em um banco de dados desnormalizado ou em NoSQL, torna-se sua responsabilidade escrever o código do aplicativo para evitar anomalias.

Alguém pode pensar que seria ótimo para um banco de dados NoSQL fazer o trabalho árduo de prevenir anomalias para você. Existe um paradigma que pode fazer isso - o paradigma relacional.

Bill Karwin
fonte
5

A abordagem de couchDB sugere emitir classes apropriadas de coisas na fase de mapa e resumi-las em reduzir. Assim, você pode mapear todos os comentários e emitir 1para um determinado usuário e depois imprimir apenas alguns. No entanto, seria necessário muito armazenamento em disco para construir visualizações persistentes de todos os dados rastreáveis ​​no couchDB. btw eles também têm esta página wiki sobre relacionamentos: http://wiki.apache.org/couchdb/EntityRelationship .

Riak, por outro lado, possui uma ferramenta para construir relações. É um link. Você pode inserir o endereço de um documento vinculado (aqui comentário) ao documento 'raiz' (aqui documento do usuário). Tem um truque. Se for distribuído, pode ser modificado ao mesmo tempo em vários locais. Isso causará conflitos e, como resultado, uma enorme árvore de relógio vetorial: / ..não tão ruim, não tão bom.

Riak também tem outro 'mecanismo'. Possui espaço de nome de chave de 2 camadas, também chamado de intervalo e chave. Portanto, por exemplo, o aluno, se temos os clubes A, B e C e o aluno StudentX, StudentY, você pode manter a seguinte convenção:

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

e para ler a relação, basta listar as chaves em determinados depósitos. O que há de errado nisso? É muito lento. Listar baldes nunca foi prioridade para riak. Está ficando cada vez melhor. btw. você não desperdiça memória porque este exemplo {true}pode ser vinculado a um único perfil completo de StudentX ou Y (aqui os conflitos não são possíveis).

Como você vê, NoSQL! = NoSQL. Você precisa examinar a implementação específica e testá-la por si mesmo.

Mencionado antes, os armazenamentos de colunas parecem bons para relações .. mas tudo depende de suas necessidades A e C e P;) Se você não precisa de A e tem menos que Peta bytes, deixe-o, vá em frente com MySql ou Postgres.

boa sorte

user425720
fonte
4
  1. user: userid: comments é uma abordagem razoável - pense nisso como o equivalente a um índice de coluna em SQL, com o requisito adicional de que você não pode consultar colunas não indexadas.

  2. É aqui que você precisa pensar sobre seus requisitos. Uma lista com 30 milhões de itens não é irracional porque é lenta, mas porque é impraticável fazer algo com ela. Se sua necessidade real é exibir alguns comentários recentes, é melhor manter uma lista muito curta que é atualizada sempre que um comentário é adicionado - lembre-se de que o NoSQL não tem requisitos de normalização. As condições de corrida são um problema com listas em um armazenamento de valor de chave básico, mas geralmente ou sua plataforma oferece suporte a listas corretamente, você pode fazer algo com bloqueios ou você realmente não se preocupa com atualizações falhas.

  3. O mesmo que para comentários de usuários - crie uma palavra-chave de índice: posts

  4. Mais do mesmo - provavelmente uma lista de clubes como propriedade do aluno e um índice nesse campo para obter todos os sócios de um clube

Tom Clarkson
fonte
2

Você tem

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

Bem, em um banco de dados relacional, a coisa normal a fazer seria em uma relação de um para muitos é normalizar os dados. Isso é a mesma coisa que você faria em um banco de dados NoSQL também. Simplesmente indexe os campos com os quais você buscará as informações.

Por exemplo, os índices importantes para você são

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

Se você estiver usando o NosDB (um banco de dados NoSQL baseado em .NET com suporte a SQL), suas consultas serão 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 os tipos de consulta com suporte em sua folha de dicas SQL ou documentação.

Basit Anwer
fonte