Comments 11
У меня, простите, идиотский вопрос.
Как с помощью этих "квантов информации" выразить простой факт: баланс на счету мистера Икс на 09.09.1909 составлял 800 франков?
Спасибо @lair за внимание к нам и статьям. Очень приятно видеть такие вдумчивые вопросы и интерес.
Мы еще не релизнули packer/unpacker который бы позволял пушить ассоциативные модели с правами и поведением в пакет для пакетных мендежеров.
Сделал за 10 минут пример. Он работоспособен в демке.
Но если представлять как это могло бы быть не придираясь к словам: это были бы типы add, at, time в дополнение к тем что есть в демке. Я бы их добавил в mp нужный для запросов (это в следующей статье как раз). Пунктирные линии - визуализация materialized path вычисленного в триггере в момент когда mp_include добавил к каждому из новых типов.
Пример запроса для вычисления баланса. Если эти вычисления нужны очень часто, легко добавить линк sum и с помощью (еще не описанных) Associative handlers на js прямо в триггере в рамках транзакции он будет вычисляться, при добавлении или удалении add.
{
number_aggregate(where: {
link: {
_by_item: { path_item_id: { _eq: 37 } },
type_id: { _eq: 31 },
},
}) {
aggregate {
sum {
value
}
}
}
}
{
"data": {
"number_aggregate": {
"aggregate": {
"sum": {
"value": 19
}
}
}
}
}
Поиск всех данных что есть
Вставка этой демо структуры в демке. Пока так. В разработке обращение к типам не по id а по package/typename (если сильно упрощать).
Прошу учитывать:
сейчас нет некоторых механик, и временный побочный эффект - необходимость указания id
пример перестанет работать уже в течении месяца-двух, так как 31, 32... id будут заполнены и вероятно появиться reserved id механика и механика обращения к линкам по package/linkName.
mutation {
insert_types: insert_links(objects: [
{ id: 31, type_id: 1, from_id: 0, to_id: 0 },
{ id: 32, type_id: 1, from_id: 0, to_id: 0 },
{ id: 33, type_id: 1, from_id: 31, to_id: 32 },
]) {
returning { id }
}
insert_type_names: insert_string(objects: [
{ link_id: 31, value: "add" },
{ link_id: 32, value: "time" },
{ link_id: 33, value: "at" },
]) {
returning { id }
}
insert_mp_include: insert_links(objects: [
{ id: 34, type_id: 22, from_id: 23, to_id: 31 },
{ id: 35, type_id: 22, from_id: 23, to_id: 32 },
{ id: 36, type_id: 22, from_id: 23, to_id: 33 },
]) {
returning { id }
}
insert_demo_user: insert_links(objects: [
{ id: 37, type_id: 14, from_id: 0, to_id: 0 },
{ id: 38, type_id: 31, from_id: 0, to_id: 0 },
{ id: 39, type_id: 31, from_id: 0, to_id: 0 },
{ id: 40, type_id: 31, from_id: 0, to_id: 0 },
{ id: 41, type_id: 32, from_id: 0, to_id: 0 },
{ id: 42, type_id: 32, from_id: 0, to_id: 0 },
{ id: 43, type_id: 32, from_id: 0, to_id: 0 },
{ id: 44, type_id: 13, from_id: 37, to_id: 38 },
{ id: 45, type_id: 13, from_id: 37, to_id: 39 },
{ id: 46, type_id: 13, from_id: 37, to_id: 39 },
{ id: 47, type_id: 33, from_id: 38, to_id: 41 },
{ id: 48, type_id: 33, from_id: 39, to_id: 42 },
{ id: 49, type_id: 33, from_id: 40, to_id: 43 },
]) {
returning { id }
}
insert_demo_values:insert_number(objects: [
{ link_id: 38, value: 12 },
{ link_id: 39, value: 7 },
{ link_id: 40, value: 15 },
]) {
returning { id }
}
}
Получение всего о юзере
{
links: links(where: {
_by_item: { path_item_id: { _eq: 37 } },
}) {
id
type_id
number {
id
value
}
}
}
{
"data": {
"links": [
{
"id": 37,
"type_id": 14,
"number": null
},
{
"id": 38,
"type_id": 31,
"number": {
"id": 1,
"value": 12
}
},
{
"id": 39,
"type_id": 31,
"number": {
"id": 2,
"value": 7
}
},
{
"id": 41,
"type_id": 32,
"number": null
},
{
"id": 42,
"type_id": 32,
"number": null
},
{
"id": 44,
"type_id": 13,
"number": null
},
{
"id": 45,
"type_id": 13,
"number": null
},
{
"id": 46,
"type_id": 13,
"number": null
},
{
"id": 47,
"type_id": 33,
"number": null
},
{
"id": 48,
"type_id": 33,
"number": null
}
]
}
}
GUI будет намного приятнее, мы работаем над собственным вьювером, интуитивным управлением, и еще очень много чем. То что доступно сейчас - временно решение для наглядности демонстрации.
Мы будем подерживать кастомные таблички вроде этих string/number, поставляемые вместе с ассоциативными моделями. Единственное ограничение - они не должны использоваться для ссылочны данных, только для хранения данных.
А что такое number
в этой вашей записи? В статье ничего такого нет.
В статье и не должно быть. Статьи постепенно говорят о разных подходах, и концепциях. Все разом будет слишком много. Я учту что вы бы хотели большую насыщенность)
Так что же это такое?
В конце моего первого ответа я сразу дал ответ на этот вопрос.
Продублирую специально для вас.
Мы будем подерживать кастомные таблички вроде этих string/number, поставляемые вместе с ассоциативными моделями. Единственное ограничение - они не должны использоваться для ссылочны данных, только для хранения данных.
Я не понимаю, что такое "кастомные таблички". Слово "кастомные" наводит меня на мысль, что это что-то, что не является частью основной модели — а это, в свою очередь, наводит на мысль, что основная модель не способна к выражению нужных мне фактов.
Ну и да, сравнение вашего рисунка сверху с записью:
{
ts: 1909-09-09
holder: mr_x,
balance: 800,
currency: CHF
}
явно не в пользу первого, уж простите.
Вы описали принцип работы, наверно, любой графовой субд. Чем ваша реализация отличается? Ну, кроме крайней неэффективности запросов из-за отсутствия "легковесных" рёбер (прямые ссылки между узлами) и необходимости приджойнивать таблицы со значениями (про которые в статье вы почему-то забыли упомянуть).
Теория графов по определению не позволяет ребрам ссылаться на рёбра. Поэтому у нас не графовая СУБД, а ассоциативная. Ассоциативная теория сейчас в разработке: первый черновик (апрель 2022-го), последний черновик (на декабрь 2023-го). Если коротко, общий случай: L ↦ L² (связи-дуплеты), частный случай L ↦ L³ (связи-триплеты).
В ассоциативной СУБД всегда можно добавить любое количество необходимых "легковесных" рёбер между связями/ассоциациями, просто создав связь/ассоциацию между ними. Да, требуется использовать join, однако у нас есть реализация materialized path индексации, которая позволяет снизить нагрузку на joins в SQL. И в целом mp это не единственный способ дополнительной индексации, которую можно наложить поверх связей. Что касается самих join, то наш следующий собственный движок СУБД разработанный с нуля на Rust делает их в 1000+ раз быстрее чем PostgreSQL, за счёт того, что из движка убрано всё лишнее (бенчмарк). И хотя сами легковесные рёбра уже способ оптимизации поиска или индексации, их можно заменить на битовые строки, которые позволят делать очень эффективное пересечение или объединение данных. С этим способом индексации мы тоже будем экспериментировать в новом движке.
И уже когда мы перейдём на этот движок, то все значения привязанные к связям, числа, строки, json и т.п. будут разложены на Дуплеты. И благодаря такому подходу сразу включится дедупликация последовательностей внутри значений, так и между значениями.
"Ребро на которое можно ссылаться" изоморфно просто промежуточному узлу и соответственно не может быть легковесным.
У materialized path переносы узлов крайне дорогие, так как затрагивают всех потомков.
Проблема джойнов не в скорости, а в асимптотике. Их скорость работы сильно зависит от размера базы.
При использовании шифровании дедупликация всё равно не работает. А без шифрования базу неизбежно сольют.
про легковесность да
mp применяется только для деревьев где нужно применять права и правила доступа или иные причины для этого
мы ставили эксперименты с решением проблемы джойнов с помощью партицирования по критериям селекторов, и пробросом критерия какие партиции использовать при поиске
про дедубликацию мы практикуем создание комплексной базы например на википедии, а отдельные сообщения или цельное хранилище конкретного проекта может шифроваться целиком и не использовать само себя быть зависимым от обученной дедублицированной базы
Ассоциативные связи