Как стать автором
Обновить

Комментарии 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 применяется только для деревьев где нужно применять права и правила доступа или иные причины для этого

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

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

Зарегистрируйтесь на Хабре, чтобы оставить комментарий