Моделирование данных в Datomic

Я изучал Datomic, и это выглядит очень интересно. Но хотя есть очень хорошая информация о том, как Datomic работает с технической точки зрения, я мало что видел на как следует думать о моделировании данных.

Каковы некоторые рекомендации по моделированию данных в Datomic? Есть ли хорошие ресурсы по этому вопросу?


person Tobias Furuholm    schedule 27.04.2012    source источник
comment
Изменена ссылка, указывающая на учебник по datomic.   -  person Tobias Furuholm    schedule 23.08.2012
comment
Пример моделирования простого блога см. на странице stackoverflow.com/a/16755573/610484.   -  person a2ndrade    schedule 26.05.2013


Ответы (2)


Предостережение Лектор

Поскольку Datomic является новым, и мой опыт работы с ним ограничен, этот ответ ни в коем случае не следует рассматривать как передовой опыт. Воспринимайте это как введение в Datomic для тех, у кого есть реляционный опыт и кто стремится к более продуктивному хранилищу данных.

Начиная

В Datomic вы моделируете данные своего домена как сущности, которые обладают значениями для атрибутов. Поскольку ссылка на другой сущность может быть значением атрибута, вы можете моделировать отношения между Сущности просто.

На первый взгляд, это не так уж сильно отличается от того, как данные моделируются в традиционной реляционной базе данных. В SQL строки таблицы — это сущности, а имена столбцов таблицы — атрибуты, которые имеют значения. Связь представлена ​​внешним ключом Value в одной строке таблицы, ссылающимся на первичный ключ Value другой строки таблицы.

Это сходство приятно, потому что вы можете просто набросать свои традиционные диаграммы ER при моделировании вашей предметной области. Вы можете полагаться на отношения так же, как в базе данных SQL, но вам не нужно возиться с внешними ключами, так как это обрабатывается за вас. Записи в Datomic являются транзакционными, а ваши чтения согласованными. Таким образом, вы можете разделить свои данные на объекты с любой степенью детализации, которая кажется вам подходящей, полагаясь на соединения для получения более широкой картины. Это удобство, которое вы теряете во многих хранилищах NoSQL, где обычно используются БОЛЬШИЕ денормализованные сущности для достижения некоторого полезного уровня атомарности во время обновлений.

На данный момент, у вас хорошее начало. Но Datomic гораздо более гибок, чем база данных SQL.

Пользуясь

Время по своей сути является частью всех данных Datomic, поэтому нет необходимости специально включать историю ваших данных как часть вашей модели данных. Это, пожалуй, самый обсуждаемый аспект Datomic.

В Datomic ваша схема не определена жестко в «прямоугольной форме», необходимой для SQL. То есть сущность1 может иметь любые атрибуты, необходимые для удовлетворения вашей модели. Сущность не обязательно должна иметь NULL или значения по умолчанию для неприменимых к ней атрибутов. И вы можете добавлять атрибуты к конкретному отдельному объекту по своему усмотрению.

Таким образом, вы можете изменять форму отдельных сущностей с течением времени, чтобы реагировать на изменения в вашем домене (или изменения в вашем понимании домена). Ну и что? Это мало чем отличается от хранилищ документов, таких как MongoDB и CouchDB.

Разница в том, что с Datomic вы можете атомарно применять изменения схемы ко всем затрагиваемым объектам. Это означает, что вы можете выполнить транзакцию для обновления формы всех сущностей, на основе произвольной логики предметной области, написанной на вашем языке[2], которая будет выполняться, не затрагивая читателей, пока преданный идее. Я не знаю ничего близкого к такой мощности ни в реляционном, ни в хранилище документов.

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

Например, ваша модель может потребовать, чтобы:

  • Человеку требуются атрибуты :name, :ssn, :dob
  • Сотруднику требуется :name, :title, :salary
  • Резидент требует :name, :address
  • Участнику требуются :id, :plan, :expiration

Что означает сущность, подобную мне:

{:name "Brian" :ssn 123-45-6789 :dob 1976-09-15 
 :address "400 South State St, Chicago, IL 60605"
 :id 42 :plan "Basic" :expiration 2012-05-01}

можно предположить, что это Person, Resident и Member но НЕ Employee.

Запросы Datomic выражаются в журнале данных и могут включать правила, выраженные на вашем родном языке, со ссылками на данные и ресурсы. которые не хранятся в Datomic. Вы можете хранить Функции базы данных как первоклассные значения внутри Datomic. Они напоминают хранимые процедуры в SQL, но ими можно манипулировать как значениями внутри транзакции, а также они написаны на вашем языке. Обе эти функции позволяют вам выражать запросы и обновления более ориентированным на предметную область способом.

Наконец, несоответствие импеданса между объектно-ориентированным и реляционным мирами всегда расстраивало меня. Использование функционального языка, ориентированного на данные (Clojure), помогает в этом, но Datomic стремится обеспечить надежное хранилище данных, которое не требует умственной гимнастики для перехода от кода к хранилищу.

Например, объект, полученный из Datomic, выглядит и действует как карта Clojure (или Java). Его можно передать на более высокие уровни приложения без преобразования в экземпляр объекта или общую структуру данных. Обход отношений этой сущности будет лениво извлекать связанные сущности из Datomic. Но с гарантией того, что они будут соответствовать исходному запросу даже при одновременном обновлении. И эти объекты будут казаться простыми старыми картами, вложенными в первый объект.

Это делает моделирование данных более естественным и, на мой взгляд, гораздо менее сложным.

Возможные ловушки

  • Конфликтующие атрибуты

    Приведенный выше пример иллюстрирует потенциальную ловушку в вашей модели. Что, если позже вы решите, что :id также является атрибутом Employee? Решение состоит в том, чтобы организовать ваши атрибуты в пространства имен. Таким образом, у вас будут и :member/id, и :employee/id. Если вы сделаете это заранее, это поможет избежать конфликтов в будущем.

  • Определение атрибута нельзя изменить (пока)

    После того, как вы определили атрибут в своем Datomic как определенный тип, индексированный или нет, уникальный и т. д., вы не можете изменить это позже. Здесь мы говорим ALTER TABLE ALTER COLUMN на языке SQL. А пока вы можете создать замещающий атрибут с правильным определением и переместить существующие данные.

    Это может звучать ужасно, но это не так. Поскольку транзакции сериализуются, вы можете отправить ту, которая создает новый атрибут, копирует в него ваши данные, разрешает конфликты и удаляет старый атрибут. Он будет работать без помех со стороны других транзакций и может использовать логику предметной области на вашем родном языке для выполнения своих задач. По сути, это то, что РСУБД делает за кулисами, когда вы выдаете ALTER TABLE, но вы называете правила.

  • Не будьте «ребенком в кондитерской»

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

  • Избегайте хранения больших, постоянно меняющихся данных

    Datomic не является хорошим хранилищем данных для больших двоичных объектов или очень больших данных, которые постоянно меняются. Потому что он сохраняет историческую запись предыдущих значений и нет способа очистить старые версии (пока). Такие вещи почти всегда лучше подходят для хранилища объектов, такого как S3. Обновление: есть способ отключить историю на для каждого атрибута. Обновление: теперь также есть способ акцизных данных; тем не менее, сохранение ссылок на внешние объекты, а не на сами объекты, по-прежнему может быть лучшим подходом к обработке больших двоичных объектов. Сравните эту стратегию с использованием байтовых массивов.

Ресурсы

Примечания

  1. Я имею в виду объект в смысле строки, а не в смысле таблицы, который более правильно описывается как тип объекта.
  2. Насколько я понимаю, в настоящее время поддерживаются Java и Clojure, но возможно, что в будущем будут поддерживаться и другие языки JVM.
person bkirkbri    schedule 13.05.2012
comment
Я был в середине ввода ответа, но это намного лучше. Хорошая работа. - person yamen; 13.05.2012
comment
Это действительно хороший обзор. Спасибо! - person Tobias Furuholm; 19.05.2012
comment
@bkirkbri Разница в том, что с Datomic вы можете вводить изменения схемы атомарно для всех затронутых объектов. Это означает, что вы можете выполнить транзакцию для обновления формы всех сущностей на основе произвольной логики предметной области, написанной на вашем языке[2], которая будет выполняться, не затрагивая читателей, пока не будет зафиксирована. Я не знаю ничего близкого к такой мощности ни в реляционном, ни в хранилище документов. Можете ли вы привести пример для этого, разве это не вросло? - person murtaza52; 18.12.2012
comment
@murtaza52 Конечно. Я имел в виду, что вы можете выполнить транзакцию, которая выполняет код Clojure или Java, который может последовательно считывать любые данные в вашей базе данных, общаться с внешним миром (диск, сеть), вычислять новые данные и передавать их в базу данных в новых атрибутах. атомарно. Я считаю, что ошибался в создании этих новых атрибутов в той же транзакции — Datomic не позволяет использовать атрибут в той же транзакции, в которой он определен. Хотя я считаю, что это может быть в дорожной карте. Надеюсь, это поможет. - person bkirkbri; 19.12.2012
comment
Я также хотел бы упомянуть, что может быть нецелесообразно вносить массовые изменения схемы всей базы данных в одну транзакцию. Из-за последовательной сериализации транзакций вы заблокируете другие записи на (возможно, длительный) срок транзакции. В этом случае вы можете просто изменять форму объектов небольшими партиями — просто убедитесь, что код вашего приложения может обрабатывать любую форму объекта. - person bkirkbri; 19.12.2012
comment
Другим заметным отличием являются многозначные атрибуты, отмеченные :db/cardinality.many, которые могут заменить отношения "один ко многим" {:db/id #db/id[:db.part/db] :db/ident :community/category :db/valueType :db.type/string :db/cardinality :db.cardinality/many :db/fulltext true :db/doc "All community categories" :db.install/_attribute :db.part/db} {:db/id #db/id[:db.part/user -1000151], :district/name "Lake Union"} {:db/id #db/id[:db.part/user -1000152], :neighborhood/name "South Lake Union"} {:community/category ["news" "events" "shopping" "dining"],..... - person Jaime Agudo; 08.02.2014

Очень хороший ответ от bkirkbri. Хочу сделать некоторые дополнения:

  1. Если вы храните много сущностей похожих, но не одинаковых «типов» или схем, используйте ключевое слово типа в схеме, например

    [:db/add #db/id[:db.part/user] :db/ident :article.type/animal]
    [:db/add #db/id[:db.part/user] :db/ident :article.type/weapon]
    [:db/add #db/id[:db.part/user] :db/ident :article.type/candy]

    {:db/id #db/id[:db.part/db] :db/ident :article/type :db/valueType :db.type/ref :db/cardinality :db.cardinality/one :db/doc "The type of article" :db.install/_attribute :db.part/db}

Когда вы их читаете, получите идентификаторы сущностей из запроса и используйте datomic.api/entity и eid и проанализируйте их с помощью мультиметодов, отправляя по типу, если это необходимо, поскольку трудно сделать хороший запрос для всех атрибутов в какой-то более сложной схеме.

person claj    schedule 26.08.2013