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

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

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

Ответ 1

Будьте осторожны

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

Начиная

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

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

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

На данный момент, у вас хорошее начало. Но 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.

Двухатомные запросы выражаются в Datalog и могут включать правила, выраженные на вашем родном языке, ссылаясь на данные и ресурсы, которые не хранятся в 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.

Ответ 2

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

  • Если вы храните множество объектов схожими, но не равными "типами" или схемами, используйте ключевое слово типа в схеме, например

    
    [: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 и проанализируйте их с помощью меток multimethods по типу, если они необходимы, поскольку трудно сделать хороший запрос для всех атрибутов в некоторых более сложная схема.