310 likes | 524 Views
Отображение моделей данных NoSQL в объектные спецификации. Н. А. Скворцов Институт проблем информатики РАН nskv@ipi.ac.ru RCDL’2012 , Переславль-Залесский 15 октября 2012 г. План. Общие черты и разновидности моделей данных NoSQL
E N D
Отображение моделей данных NoSQLв объектные спецификации Н. А. Скворцов Институт проблем информатики РАН nskv@ipi.ac.ru RCDL’2012, Переславль-Залесский 15 октября 2012 г.
План • Общие черты и разновидности моделей данных NoSQL • Отображение информационных ресурсов в моделях NoSQL в унифицирующую модель • Отображение модели «ключ-значение» • на примере Oracle NoSQL • Отображение модели с колоночным хранением • на примере Cassandra • Отображение документной модели • на примере MongoDB • Общие проблемы и подходы к отображению моделей разных классов NoSQL с выявлением структуры данных • Подходы к отображению моделей при невыявляемых схемах данных
Основные принципыбаз данных NoSQL • Технологии NoSQL направлены на горизонтальное масштабирование и доступ к данным сверхбольших объёмов • Отказ от хранения данных по кортежам • Организация данных с помощью • Доступ к данным в узле только по ключам • Горизонтальное масштабирование и репликация по узлам по хеш-значениям • распределённые хеш-таблицы (DHT) • Ограниченный язык манипулирования данными • CRUD (create/read/update/delete) • Сдвиг обработки с этапа запросов на этап обновления данных • Возможные разновидности запросов известны заранее • Материализованные взгляды под возможные запросы формируются на этапе обновления • Оптимизация обновленийи буферизация вставок • журнальная структура (log-structured) • eventual consistency – операции чтения и запросы используют уже имеющиеся данные, даже если эти данные ожидают обновления • BASE-транзакции (Basically Available, Soft state, Eventually consistent)
Разновидности моделей NoSQL • Хранилища ключ-значение • Пары ключ-значение • Составные ключи • Произвольные значения • Базы данных с колоночным хранением • С ключом связан набор именованных колонок со значениями • Имитация табличной структуры на основ пар ключ-значение • Документные базы данных • Значения могут содержать вложенные наборы пар ключ-значение • Иерархические структуры на основе пар ключ-значение • Иногда (не в данной работе) к NoSQLотносят также • хранилища триплетов (RDF) • графовые системы баз данных • объектно-ориентированные системы баз данных
Необходимость отображения NoSQL в объектную модель • Решение задач над множественными информационными ресурсами • Задачи выражена в объектной модели • Разрешение модельной неоднородности между спецификациями задачи и ресурсов • Отображение моделей ресурсов в унифицирующую модель • Отображение моделей NoSQL в объектную модель не всегда очевидно • Наряду со структурированными данными могут присутствовать слабоструктурированные и неструктурированные • Схема базы чаще всего не имеет спецификации, а предполагается неявно • Схема может быть нефиксированной, изменяемой динамически, может содержать сложные переплетения экземпляров данных и структурных элементов
Отображение модели«ключ-значение» На примере Oracle NoSQL
СУБД «ключ/значение» OracleNoSQL • Элемент хранения - пара • составной ключ: major keys и minor keys • произвольное неструктурированное значение • Ключ: “Smith/John/-/phonenumber/home” • Majorkey: список из 1 или более компонентов (“Smith/John”) – влияет на выбор узла хранения по хеш-значению; • Minor key: список из 0 или более компонентов (“phonenumber/home”) – все значения гарантированно на одном узле, вместе с marjorkey определяет уникальный ключ • Значение: “555 5555“ • Значение – строка байтов • Может быть сериализацией любого набора данных, структурированных или неструктурированных, с любой семантикой
Операции • Операции записи • put(key, value), putIfAbsent, putIfPresent, putIfVersion • delete(key), multiDelete • Subrange (keyFirst, keyLast) • Depth.CHILDREN_ONLY • Операции чтения • get(key) • multiGet • такжеMultiGetIterator, StoreIterator (по major key) • Subrange (keyFirst, keyLast) • Depth.CHILDREN_ONLY • multiGetKeys • Subrange (keyFirst, keyLast) • Depth.CHILDREN_ONLY
Пример List<String> majorComponents =new ArrayList<String>(); List<String> minorComponents =new ArrayList<String>(); majorComponents.add("Smith"); majorComponents.add("Bob"); minorComponents.add("phonenumber"); minorComponents.add("home"); Key myKey = Key.createKey(majorComponents, minorComponents); String data = “555 5555"; Value myValue = Value.createValue(data.getBytes()); kvstore.put(myKey, myValue); ValueVersion vv = kvstore.get(myKey); Value v = vv.getValue(); String data = new String(v.getValue());
Фиксированные и нефиксированные ключи {“Smith/Bob/-/phonenumber/home”: “555 5555”} {“Smith/Bob/-/phonenumber/mobile”: “333 3333”} Smith └ Bob └ phonenumber ├ home: “555 5555” └ mobile: “333 3333” • Разделение на major key и minor key влияет только на физическую привязку данных к узлу • Оно не влияет на отображение в объектную модель • В любом месте составного ключа могут быть данные, а могут быть фиксированные имена в структурах данных • Фиксированные (“phonenumber”, “home”, “mobile”) • Нефиксированные (“Smith”, “Bob”) • Дочерние компоненты ключей (“home”, “mobile”) – связанныес единственным значением родительского компонента (“phonenumber”)
Отображение структурOracle NoSQL • Связанные по структуре ключей пары отображаются в классы (Class1, Class2, …).Если компонент ключа имеет единственное значение в подобных ключах, то он становится именем класса. • Для нефиксированные значений компонентов ключей создаются атрибуты класса (majorKey1, majorKey2, …, minorKey1, minorKey2, …).Тип значений атрибутов строковый. Возможно задание и преобразование типов. • Для фиксированных значений компонентов создаётся атрибутом с именем, соответствующим значению компонента ключа. • Для дочерних фиксированных компонентов ключей создаются абстрактные типы данных, одноимённый со значением родительского компонента, с атрибутами, соответствующими значениям дочернего компонента. • Значение пары отображается в значение атрибута, соответствующего последнему фиксированному значению, у которого нет дочерних компонентов. Либо, если такового нет, то значение пары отображается в атрибут value.Типом значения атрибута является фрейм СИНТЕЗ. Возможно задание и преобразование типов. Если семантика и структура значения не известна, и разобрать его в виде фрейма невозможно, задаётся фрейм – значение типа битовой строки. • Набор всех атрибутов типа, образованных компонентами ключей, указывается как уникальный.Если с атрибутом, соответствующим фиксированному значению компонента ключа, связано значение, соответствующее значению в паре, то включать его в набор излишне.
Отображённый пример Smith └ Bob └ phonenumber ├ home: “555 5555” └ mobile: “333 3333” • majorKey1, majorKey2 определяют уникальное значение, так как home и mobile фиксированные значения компонента ключа { class1; in: class; instance_section: { majorKey1: String; majorKey2: String; phonenumber: Phonenumber; key: { unique; { majorKey1, majorKey2 } }; }} { Phonenumber; in: type; home: String; mobile: String; }
Отображение операций: get majorComponents.add("Smith"); majorComponents.add("Bob"); minorComponents.add("phonenumber"); minorComponents.add("home"); Key myKey = Key.createKey (majorComponents, minorComponents1); ValueVersion vv = kvstore.get(myKey); Value v = vv.getValue(); q([v]) :- class1([majorKey1, majorKey2, v : phonenumber.home]) & majorKey1=”Smith” & majorKey2=”Bob”
Отображение операций: multiget majorComponents.add("Smith"); majorComponents.add("Bob"); Key myKey = Key.createKey(majorComponents); SortedMap<Key, ValueVersion> x = kvstore.multiGet(myKey); q(x) :- class1(x/class1.inst) & x.majorKey1=”Smith” & x.majorKey2=”Bob” • В классе результата будет один объект • из нефиксированных значений компонентов ключа и значений пар будут сформированы все значения атрибутов в объекте-экземпляре класса class1.
Отображение операций:multiget и KeyRange majorComponents.add("Smith"); Key myKey = Key.createKey(majorComponents); KeyRangekr = new KeyRange( "Bob", true, "Patricia", true); SortedMap<Key, ValueVersion> x = kvstore.multiget(myKey, kr); q(x) :- class1(x/class1.inst) & x.majorKey1=”Smith” & x.majorKey2>=”Bob” & x.majorKey2<=”Patricia”
Отображение операций: multiGetKeys majorComponents.add("Smith"); Key myKey = Key.createKey(majorComponents); SortedSet<Key> k = kvstore.multiGetKeys(myKey); q([majorKey1, majorKey2]) :- class1([majorKey1, majorKey2]) & majorKey1=”Smith” • Так как у фиксированных ключей нет дочерних нефиксированных, то в результат они не включаются, хотя операция их возвращает • В языке запросов должны быть средства запросов к схеме
Вспомогательные пары • Данные дублируются с другой структуризацией для возможности поиска по другим критериям {“Smith/Bob/-/phonenumber/home”: “555 5555”} {“555 5555”: [”Smith”, ”Bob”]} majorComponents.add("555 5555"); Key myKey = Key.createKey (majorComponents); ValueVersion vv = kvstore.get(myKey); q([majorKey1, majorKey2]) :- class1([majorKey1, majorKey2, v : phonenumber.home]) & v=”555 5555”
Неструктурируемые пары {“majorkey1/…/majorkeyM/-/ minorkey1/…/ minorkeyN/” : “a value”} { db; in: class; instance_section: { minorKey: {sequence; type_of_element: String}; majorKey: {sequence; type_of_element: String}; value: Bitstring; key: { unique; { minorKey, majorKey } }; }}
Отображение модели с колоночным хранением На примере Cassandra
Основные термины Cassandra • Column (колонка) – множество пар ключ-значение (key-value) • ColumnFamily (семействоколонок) – содержитмножество колонок, у каждой из которых есть название, значение, и временная метка, и на которые ссылаются с помощью ключей строк • Keyspace(пространствоключей) – содержит набор семейств колонок • SuperColumn (суперколонки) – колонки, состоящие из набора подколонок
Операции чтения • get(): извлечь по имени колонки • multiGet(): по имени колонки для множества ключей • getSlice(): по имени колонки или ряду имён • возвращаются колонки • возвращаются суперколонки • multiGetSlice(): ряд колонок для множества ключей • getCount(): количество колонок или суперколонок • getRangeSlice(): ряд колонок для диапазона ключей
Операции записи • insert(): добавить/обновить колонку (по ключу) • batchInsert(): добавить/обновить множество колонок (по ключу) • remove(): удалить колонку • batchMutate(): как batchInsert(), но может и удалять
Отображение • Семейство колонок отображается в класс, ключ семейства становится атрибутом id, с ним связано свойство уникальности. • Если именаколонок фиксированные (в именах не данные, а названия, одни и те же для всех ключей), то имена колонок отображаются в одноимённые атрибуты. Значения колонок, связанные с одним значением ключа отображаются в значения атрибутов у объекта с id, соответствующим значению ключа семейства. • Если имена колонок нефиксированные (являются данными), то для пар имя-значение создаётся абстрактный тип данных с двумя атрибутами, а семейство колонок отображается в класс с атрибутом id и атрибутом, значением которого является лист значений созданного типа. • Ключи, имена колонок и значения вспомогательных семейств (материализованных взглядов на основные семейства) отображаются в атрибуты уже существующего класса, если все колонки присутствуют в основных семействах • Подколонки отображаются в отдельный абстрактный тип данных.
Пример users: { "1": { "firstName": "John", "lastName": "Smith", "phoneNumbers": { "home": "555 5555", "mobile": "333 3333"} }, "2": … } get({“firstName”, “lastName”}, "1“) { users; in: class; instance_section: { id: String; firstName: String; lastName: String; phoneNumbers: PhoneNumbers; key: { unique; id }; }} { PhoneNumbers; in: type; home: String; mobile: String; } q([firstName, lastName]) :- users(x/[id, firstName, lastName]) & x.id="1"
Особенные случаи • Вспомогательные колонки { “555 5555": { "firstName": "John", "lastName": "Smith",} • Данные в именах колонок • Неограниченное количество колонок { “1": { "home": “555 5555”, “mobile”: “333 3333”, “in S.-Petersburg": “222 2222", … } } Отображается в уже созданную структуру id: String; phonenumber: {sequence; type_of_element: PhoneNumber}; { Phonenumber; in: type; home: String; mobile: String; }
Отображение документной модели На примере MongoDB
Отображение документальной модели • Вложенные структуры пар ключ-значение (JSON) users: { "firstName": "John", "lastName": “Smith", "phoneNumbers": { "home": "555 5555", “mobile": "3333333” } } • Вторичные индексы db.things.ensureIndex({'lastName':1}); db.users.find({'lastName': 'Smith'}, {'phoneNumbers.home':1}); • Неограниченно вложенные иерархии отображаются в базу фреймов { users; in: class; instance_section: { firstName: String; lastName: String; phoneNumbers: PhoneNumbers; }} { PhoneNumbers; in: type; home: String; mobile: String; } q([v]) :- users([lastName, v : phonenumber.home) & lastName="Smith«
Общие проблемы и решения • Значения ключей могут быть фиксированными (имена атрибутов) или нефиксированными (данные) • Это определяет эксперт • В случае выявляемой схемы данных c фиксированные ключи отображаются в атрибуты типов, нефиксированные – в значения атрибутов • Слабая структурированность моделей NoSQL • не определяется схема данных в явном виде • значения в парах «ключ-значение» могут быть произвольными и неструктурированными • при отсутствии схемы структура пар может изменяться динамически • с помощью операции put (или Create) можно в любой момент ввести новую структуру пар «ключ-значение» • нет ограничений по длине составных ключей или по вложенности пар «ключ-значение» (в случае документных баз) • системы могут использоваться для решения задач, изначально рассчитанных на использование нефиксированных и неограниченных структур (например, иерархических) • При возможности выявляения схемы это необходимо делать в соответствии с семантикой данных • В этих случаях используется подход к отображению моделей данных, предполагающий отображение только языка манипулирования данными • Возможные разновидности запросов, используемых при решении задач над данным должны быть известны заранее • Данные, по которым необходимо организовать поиск, должны оказаться ключами в некоторых парах «ключ-значение», а искомые данные – значениями • Для этого могут формироваться вспомогательные пары, дублирующие данные в разной организации ключей и значений • Материализованные взгляды в этих парах формируются на этапе обновления • Вспомогательные пары при отображении не образуют новые классы, а отображаются в типы и классы, образованные основными парами • В случае отображения в реляционную модель в соответствии с дополнительными парами образуются вторичные ключи • Разрешены запросы со сравнением по атрибутам, являющимся ключами в дополнительных парах, при обратном отображении они отображаются в операции над дополнительными парами • Если схема не выявляется • Данные (ключи и значения) отображаются во фреймы (в слоты, значения слотов, вложенные фреймы, с учётом разбора составных ключей и значений) • Запросы производятся к базе фреймов и переписываются в операции