Как хранить связанное дерево с детьми в реляционной базе данных? - PullRequest
0 голосов
/ 28 мая 2018

У меня есть пользовательское LinkedTree с дочерними элементами (узлами), и узлы имеют отношение смежности, то есть каждый узел связан с предыдущим и следующим.Это LinkedTree очень тяжелое, большое, оно может состоять из миллионов узлов.

А вот пример кода:

package tree;

import java.io.Serializable;

public class LinkedTree<E> implements Serializable {

    private int size = 0;
    private Node<E> first;
    private Node<E> last;
    private LinkedTree<E> children;

    public LinkedTree() {
        children = new LinkedTree<>();
    }

    public LinkedTree(LinkedTree<E> children) {
        this.children = children;
    }

    public void add(E element) {

        final Node<E> l = last;
        final Node<E> newNode = new Node<>(l, element, null);
        last = newNode;
        if (l == null)
            first = newNode;
        else
            l.next = newNode;
        size++;
    }

    public void remove(E element) {

        ...
    }

    public int size() {

         return size;
    }

    public static class Node<E> implements Serializable {

        E item;
        Node<E> next;
        Node<E> prev;

        public Node(Node<E> prev, E item, Node<E> next) {

            this.item = item;
            this.next = next;
            this.prev = prev;
        }

        public E item() {

            return item;
        }

        public boolean hasPrevious() {

            return prev != null;
        }

        public Node<E> previous() {

            return prev;
        }

        public Node<E> previous(int target) {

            Node<E> n = this;
            int i = target;
            while (i-- > 0 && n != null)
                n = n.prev;
            return n;
        }

        public boolean hasNext() {

            return next != null;
        }

        public Node<E> next() {

            return next;
        }

        public E nextItem() {

            return next.item;
        }

        public E nextItem(int target) {

            return next(target).item();
        }

        public Node<E> next(int target) {

            Node<E> n = this;
            int i = 0;
            while (i++ < target && n != null)
                n = n.next;
            return n;
        }

        @Override
        public int hashCode() {

            return item != null ? item.hashCode() : 0;
        }

        @Override
        public boolean equals(Object o) {

            if (this == o)
                return true;
            if (o == null || getClass() != o.getClass())
                return false;

            Node<?> node = (Node<?>) o;

            return item != null ? item.equals(node.item) : node.item == null;
        }

        @Override
        public String toString() {

            return item.toString();
        }
    }
}

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

Я полагаю, что отношения строки должны быть в смежности и родительско-дочерних отношениях одновременно.Но я понятия не имею, как это сделать.

Ответы [ 2 ]

0 голосов
/ 29 мая 2018

Год назад у меня были те же требования, а потом я изучил множество вариантов.Тогда я решил пойти с графической базой данных.Попробуйте Neo4j, графическую базу данных.

0 голосов
/ 29 мая 2018

Я бы прокомментировал запрос дополнительной информации (в частности, примеры данных и правила вашей иерархии), поэтому простите этот первый вариант за чрезмерно общий

Я сделал следующие предположения:

  • что ваша структура глубже трех уровней - если это не так, то я бы не стал так делать, потому что это не стоило бы

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

  • параллельная запись не требуетсячастичный и разделяемый доступ или доступ без блокировки к дереву для его построения или обработки (в этом случае вам нужно указать deletes, что можно сделать, указав на замененный узел, т.е. замененный)

моя предложенная модель данных будет выглядеть примерно так:

create table treemodel (
 `node` int not null 
 , `parent` int not null 
 , `principal` int not null 
 , `state` smallint unsigned not null 
 , ...
 , `supersedes` int    /*version instead of lossy update or delete*/
 , `supersededby` int
) engine = innodb;
alter table treemodel add primary key (`principal`, `node`) using btree; 
  1. таблица древовидной модели будет содержать только структурные идентификаторы: я буду хранить данные узла в отдельномтаблицу, но я бы не стал присоединяться, чтобы получить ее, скорее, я бы выполнил секунду select ... where node in (...) - это в основном говорит о том, что «структура моих данных не зависит от моих данных»

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

  3. это будет идти вразрез с вашей моделью данных, так как вы не сохраняете дополнительный «главный» узел со своими вложенными дочерними элементами - но если вы можете изменить эту структуру, вы можете воспользоваться этим предложением, чтобы избежать запросов внутрипетли, т.е.множественные selects, или повторные запросы или самостоятельные / унарные объединения

  4. ... но ваша бизнес-логика должна будет поддерживать понятие того, что я назвал «основным» узлом

  5. ваш вариант использования зависит от того, что помещается в главный узел - я использовал эту модель для хранения причинно-следственной связи между записями наблюдений и их производными, независимо от родительских дочерних отношений, указанных нижеэтот момент - другой пример может быть: 1) клиент вызывает запрос поддержки, или 2) отправляется новое сообщение, или 3) создается новый файл, ...

  6. не имеет смысла хранить принципал как фактический корневой узел в вашей древовидной структуре (т. е. идентификатор узла «1», или «каталог данных», или что угодно) - вместо этого вы сохраните «следующий уровень вниз» ради аргументат.е.«корневой каталог пользователя» или «первый уровень ниже корневого каталога пользователя» - вот где знание вашего прецедента и бизнес-правил поможет

  7. ... и ваш код Java должен бытьобновлен, чтобы найти или скопировать и сохранить эту концепцию - она ​​всегда будет копией из родительского узла на любом insert в пределах данной ветви дерева - и если вы перемещаете ветку, и ваша логика требует изменения этого числа,update ... set principal=y where principal=x и update ... set parent=newid where node=current_principal

  8. ... и, сказав все это, я не буду обновлять строки как таковые , только insert при изменении и воссоздании всей ветви дерева (что объясняет поле state, т. е. CURRENT, DELETED, ... где корневой узел удаленной ветви все еще указывает на ее текущуюродительский узел, например, для «удаленных элементов»)

  9. вы по-прежнему сохраняете указатели на каждый соседний узел в prev & next - упорядоченные вставки узлов в ветвь дерева будут, вв худшем случае требуется select ... where principal=x for update, но, вероятно, только select ... where (node=x or prev=x or next=x) for update

правок:

  • первичный ключ / кластерный индекс должен быть уникальным - вы также можете разделить на principal, чтобы обеспечить быстрый параллельный доступ

  • воссоздание вместо обновления веток

...