Подтвердить что ты не робот

Принципы моделирования документов CouchDB

У меня есть вопрос, на который я пытаюсь ответить некоторое время, но не могу понять:

Как вы разрабатываете или делят документы CouchDB?

Возьмите сообщение в блоге, например.

Полуреактивный способ сделать это - создать несколько объектов:

  • Сообщение
  • Пользователь
  • Комментарий
  • Тег
  • Отрывок

Это имеет большой смысл. Но я пытаюсь использовать couchdb (по всем причинам, что это здорово), чтобы моделировать одно и то же, и это было чрезвычайно сложно.

Большинство сообщений в блоге дают вам простой пример того, как это сделать. Они в основном делят его одинаково, но говорят, что вы можете добавлять "произвольные" свойства к каждому документу, что, безусловно, хорошо. Таким образом, у вас будет что-то подобное в CouchDB:

  • Сообщение (с тегами и фрагментами "псевдо" в документе)
  • Комментарий
  • Пользователь

Некоторые люди даже скажут, что вы можете бросить комментарий и пользователя там, поэтому у вас будет следующее:


post {
    id: 123412804910820
    title: "My Post"
    body: "Lots of Content"
    html: "<p>Lots of Content</p>"
    author: {
        name: "Lance"
        age: "23"
    }
    tags: ["sample", "post"]
    comments {
        comment {
            id: 93930414809
            body: "Interesting Post"
        } 
        comment {
            id: 19018301989
            body: "I agree"
        }
    }
}

Это выглядит очень красиво и легко понять. Я также понимаю, как вы могли писать представления, которые извлекали только комментарии из всех ваших документов Post, чтобы получить их в моделях комментариев, то же самое с пользователями и тегами.

Но потом я думаю: "Почему бы просто не поместить весь мой сайт в один документ?":


site {
    domain: "www.blog.com"
    owner: "me"
    pages {
        page {
            title: "Blog"
            posts {
                post {
                    id: 123412804910820
                    title: "My Post"
                    body: "Lots of Content"
                    html: "<p>Lots of Content</p>"
                    author: {
                        name: "Lance"
                        age: "23"
                    }
                    tags: ["sample", "post"]
                    comments {
                        comment {
                            id: 93930414809
                            body: "Interesting Post"
                        } 
                        comment {
                            id: 19018301989
                            body: "I agree"
                        }
                    }
                }
                post {
                    id: 18091890192984
                    title: "Second Post"
                    ...
                }
            }
        }
    }
}

Вы можете легко сделать представление, чтобы найти то, что вам нужно.

Тогда у меня есть вопрос: как вы определяете, когда разделить документ на более мелкие документы или когда делать "ОТНОШЕНИЯ" между документами?

Я думаю, что это было бы намного больше "Object Oriented" и проще было бы сопоставлять объекты Value, если бы они были разделены так:


posts {
    post {
        id: 123412804910820
        title: "My Post"
        body: "Lots of Content"
        html: "<p>Lots of Content</p>"
        author_id: "Lance1231"
        tags: ["sample", "post"]
    }
}
authors {
    author {
        id: "Lance1231"
        name: "Lance"
        age: "23"
    }
}
comments {
    comment {
        id: "comment1"
        body: "Interesting Post"
        post_id: 123412804910820
    } 
    comment {
        id: "comment2"
        body: "I agree"
        post_id: 123412804910820
    }
}

... но затем он начинает больше напоминать реляционную базу данных. И часто раз я наследую то, что похоже на "весь сайт в документе", поэтому сложнее моделировать его с помощью отношений.

Я прочитал много вещей о том, как/когда использовать реляционные базы данных и базы данных документов, так что здесь не главная проблема. Мне больше интересно, какое хорошее правило/принцип применять при моделировании данных в CouchDB.

Другой пример - с XML файлами/данными. Некоторые данные XML имеют глубину более 10 уровней, и я хотел бы визуализировать, что с использованием одного и того же клиента (Ajax on Rails, например, или Flex), который я хотел бы сделать JSON из ActiveRecord, CouchRest или любого другого Relation Mapper объекта. Иногда я получаю огромные XML файлы, которые представляют собой всю структуру сайта, как и приведенную ниже, и мне нужно будет сопоставить ее с Value Objects для использования в моем приложении Rails, поэтому мне не нужно писать другой способ сериализации/десериализации данных


<pages>
    <page>
        <subPages>
            <subPage>
                <images>
                    <image>
                        <url/>
                    </image>
                </images>
            </subPage>
        </subPages>
    </page>
</pages>

Итак, общие вопросы CouchDB:

  • Какие правила/принципы вы используете для разделения ваших документов (отношений и т.д.)?
  • Можно ли разместить весь сайт в одном документе?
  • Если да, то как вы обрабатываете сериализацию/десериализацию документов с произвольными уровнями глубины (например, пример большого json выше или пример xml)?
  • Или вы не превращаете их в VO, вы просто решаете, что "эти слишком вложены в объектно-реляционную карту, поэтому я просто получаю доступ к ним с использованием необработанных методов XML/JSON"?

Большое спасибо за вашу помощь, вопрос о том, как разделить ваши данные с CouchDB, мне трудно сказать "вот как я должен это делать с этого момента". Я надеюсь скоро приехать.

Я изучил следующие сайты/проекты.

... но они все еще не ответили на этот вопрос.

4b9b3361

Ответ 1

На это уже были отличные ответы, но я хотел добавить некоторые более свежие функции CouchDB к сочетанию опций для работы с исходной ситуацией, описанной viatropos.

Ключевым моментом, в котором нужно разделить документы, являются конфликты (как упоминалось ранее). Вы никогда не должны держать массивно "запутанные" документы вместе в одном документе, так как вы получите единственный путь к версии для полностью несвязанных обновлений (добавление комментариев, добавляющее, например, ревизию ко всему документу сайта). Управление отношениями или связями между различными, меньшими документами может сбивать с толку сначала, но CouchDB предоставляет несколько вариантов объединения разрозненных фрагментов в отдельные ответы.

Первый большой - сортировка вида. Когда вы испускаете пары ключ/значение в результаты запроса map/reduce, ключи сортируются на основе сопоставления UTF-8 ( "a" предшествует "b" ). Вы также можете вывести сложные ключи из вашей карты/уменьшить как массивы JSON: ["a", "b", "c"]. Выполнение этого позволит вам включить "дерево" типов, построенных из ключей массива. Используя приведенный выше пример, мы можем вывести post_id, затем тип вещи, на который мы ссылаемся, затем его идентификатор (если необходимо). Если затем вывести идентификатор ссылочного документа в объект в возвращаемом значении, мы можем использовать параметр запроса include_docs, чтобы включить эти документы в вывод map/reduce:

{"rows":[
  {"key":["123412804910820", "post"], "value":null},
  {"key":["123412804910820", "author", "Lance1231"], "value":{"_id":"Lance1231"}},
  {"key":["123412804910820", "comment", "comment1"], "value":{"_id":"comment1"}},
  {"key":["123412804910820", "comment", "comment2"], "value":{"_id":"comment2"}}
]}

Запрос того же представления с '? include_docs = true' добавит ключ "doc", который либо будет использовать ссылку "_id", на которую ссылается объект "значение", либо если это не присутствует в объекте "значение", он будет использовать "_id" документа, из которого была выбрана строка (в данном случае документ "post" ). Обратите внимание, что эти результаты будут включать поле "id", ссылающееся на исходный документ, из которого был сделан излучатель. Я оставил его для пространства и читаемости.

Затем мы можем использовать параметры "start_key" и "end_key", чтобы отфильтровать результаты до единичных данных:

?start_key=["123412804910820"]&end_key=["123412804910820", {}, {}]
Или даже специально извлечь список для определенного типа:
?start_key=["123412804910820", "comment"]&end_key=["123412804910820", "comment", {}]
Эти комбинации параметров запроса возможны потому что пустой объект ( "{}" ) всегда находится в нижней части сортировки, а null или "" всегда находятся в верхней части.

Вторым полезным дополнением от CouchDB в этих ситуациях является функция _list. Это позволит вам выполнить приведенные выше результаты с помощью какой-либо системы шаблонов (если вы хотите HTML, XML, CSV или что-то еще) или вывести единую структуру JSON, если вы хотите иметь возможность запрашивать весь контент (включая автор и комментарии) с единственным запросом и возвращаются в виде единого документа JSON, который соответствует вашему коду клиентской стороны/пользовательскому интерфейсу. Это позволит вам запросить унифицированный выходной документ следующим образом:

/db/_design/app/_list/posts/unified??start_key=["123412804910820"]&end_key=["123412804910820", {}, {}]&include_docs=true
Функция _list (в данном случае с именем "унифицированная" ) будет принимать результаты карты/сокращения вида (в этом случае называются "сообщения" ) и запустите их через функцию JavaScript, которая отправит ответ HTTP в нужном типе контента (JSON, HTML и т.д.).

Объединяя эти вещи, вы можете разделить свои документы на любом уровне, который вы найдете полезным и "безопасным" для обновлений, конфликтов и репликации, а затем поместите их вместе по мере необходимости, когда они будут запрошены.

Надеюсь, что это поможет.

Ответ 2

book говорит, если я правильно помню, денормализовать до тех пор, пока "это не повредит", в то время как имея в виду частоту обновления ваших документов.

  • Какие правила/принципы вы используете для разделения ваших документов (отношений и т.д.)?

Как правило, я включаю все данные, необходимые для отображения страницы относительно рассматриваемого элемента. Другими словами, все, что вы напечатали на бумаге реального мира, которую вы передадите кому-то. Например. документ котировки акций будет содержать название компании, биржу, валюту, в дополнение к цифрам; контрактный документ будет включать имена и адреса контрагентов, всю информацию о датах и ​​подписавших стороны. Но котировки акций с разных дат будут составлять отдельные документы, отдельные контракты будут составлять отдельные документы.

  1. Можно ли разместить весь сайт в одном документе?

Нет, это было бы глупо, потому что:

  • вам нужно будет прочитать и написать весь сайт (документ) для каждого обновления, и это очень неэффективно;
  • вам не пригодится какое-либо кэширование просмотров.

Ответ 3

Я знаю, что это старый вопрос, но я столкнулся с этим, пытаясь найти лучший подход к этой же самой проблеме. Кристофер Ленц написал хороший блог о методах моделирования "присоединяется" в CouchDB. Один из моих приемов был: "Единственный способ разрешить непротиворечивое добавление связанных данных - это связать эти связанные данные с отдельными документами". Итак, для простоты вы хотите склониться к "денормализации". Но вы столкнетесь с естественным барьером из-за противоречивых писем в определенных обстоятельствах.

В вашем примере сообщений и комментариев, если одна запись и все ее комментарии проживали в одном документе, тогда два человека, пытающихся опубликовать комментарий в одно и то же время (т.е. против того же пересмотра документа), конфликт. Это будет еще хуже в сценарии "всего сайта в одном документе".

Итак, я думаю, что эмпирическое правило будет "денормализоваться до тех пор, пока оно не повредит", но точка, где это будет "больно", - это то, где у вас есть высокая вероятность того, что несколько редактирований были отправлены против одной и той же ревизии документа.

Ответ 4

Я думаю, что ответ Джейка называет один из самых важных аспектов работы с CouchDB, который может помочь вам принять решение о скоринге: конфликты.

В случае, когда у вас есть комментарии как свойство массива самой записи, и у вас просто есть "пост" БД с кучей огромных "почтовых" документов в нем, как Джейк и другие правильно указали, что вы могли себе представить сценарий в действительно популярном сообщении в блоге, в котором два пользователя одновременно отправляют редактирование в почтовый документ, что приводит к конфликту конфликтов и версий для этого документа.

ASIDE: Как эта статья указывает на, также учитывайте, что каждый раз, когда вы запрашиваете/обновляете этот документ, вы должны получить/установить документ в целом, поэтому передача массивных документов, представляющих весь сайт или сообщение с большим количеством комментариев по нему, может стать проблемой, которую вы бы хотели избежать.

В случае, когда должности моделируются отдельно от комментариев, а два человека представляют комментарий к истории, они просто становятся двумя "комментариями" в этой БД, без конфликтов; всего две операции PUT, чтобы добавить два новых комментария в "комментарий" db.

Затем, чтобы написать представления, которые вернут вам комментарии к сообщению, вы должны передать в postID, а затем испустить все комментарии, ссылающиеся на этот родительский идентификатор, отсортированные в некотором логическом порядке. Возможно, вы даже передаете что-то вроде [postID, byUsername] в качестве ключа к представлению "комментарии", чтобы указать родительский пост и как вы хотите, чтобы результаты были отсортированы или что-то в этих строках.

MongoDB обрабатывает документы немного по-другому, позволяя создавать индексы на подэлементах документа, поэтому вы можете увидеть тот же вопрос в списке рассылки MongoDB, а кто-то говорит "просто сделайте комментарии свойством родительского сообщения",.

Из-за блокировки записи и единственного мастера Mongo конфликтная проблема пересмотра двух пользователей, добавляющих комментарии, не будет spring там, и возможность запроса содержимого, как уже упоминалось, также не выполняется плохо из-за субиндексов.

Говоря, что если ваши подэлементы в одной из БД будут огромными (скажем, 10 тысяч тысяч комментариев), я считаю, что рекомендации обоих лагерей составляют эти отдельные элементы; Я, конечно, видел, что это имеет место с Монго, поскольку существуют некоторые ограничения сверху на то, насколько большой документ и его подэлементы могут быть.

Ответ 5

Чтобы добавить информацию в этот пост, я изучаю эту проблему в этой статье. Рекомендации по моделированию данных для баз данных документов NoSQL JSON и методики моделирования данных NOSQL. Эти два поста касаются не только CouchDB, но и общих руководящих указаний по моделированию баз данных NoSQL, например, в первой статье рассказывается о денормализации, родительско-дочерних отношениях - встроенном объекте, дизайне ключей составной строки, общих данных, данных событий и атрибутах объектов - Значение, дерево, список смежности, данные графика и отображение наследования, включительно, сравнивают эти методы в NoSQL и SQL. Благодарю.