Модераторы: LSD, AntonSaburov

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Рекурсия в persistence 
:(
    Опции темы
Ортхэннер
Дата 15.9.2008, 08:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 23
Регистрация: 29.1.2005
Где: Благовещенск

Репутация: нет
Всего: нет



Имеем следующий класс:
Код
@Entity
public class Bean inplements Serializable {
  protected int id;
  @Id @GeneratedValue(strategy=GenerationType.AUTO) public int getId() {
   return id;
  }
  public void setId(int id) {
   this.id = id;
  }
  protected String title;
  @Column(nullable=false) public String getTitle() {
   return title;
  }
  public void setTitle(String title) {
   this.title = title;
  }
  protected Bean parent;
  @ManyToOne public Bean getParent() {
   return parent;
  }
  public void setParent(Bean p) {
   parent = p;
  }
  protected java.util.List<Bean> children;
  @OneToMany(mappedBy="parent") public java.util.List<Bean> getChildren() {
   return children;
  }
  public void setChildren(java.util.List<Bean> children) {
   this.children = children;
  }
}


Можно ли одним запросом "выдернуть" всех потомков исходного объекта вне зависимости от поколения? (т. е. чтобы не только
Код

b.parent=?1

но и
Код

b.parent.parent=?1

и т. д.)
PM MAIL ICQ   Вверх
Plamenk
Дата 15.9.2008, 09:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 258
Регистрация: 18.2.2003

Репутация: нет
Всего: 3



Средствами Oracle можно. См. "connect by prior". 

Но судя по коду ты работаешь с объектами не БД... так что этот способ здесь наверное не поможет.
PM MAIL   Вверх
powerOn
Дата 15.9.2008, 09:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


software saboteur
****


Профиль
Группа: Участник
Сообщений: 4367
Регистрация: 7.10.2005

Репутация: 28
Всего: 159



Если ты вытянешь корневой объект (т.е. предка для тех потомков которые ищешь), то связанные объекты будут загружены либо автоматом (для односсылочных связей), либо лениво. Фактически делать ничего не нужно, только грамотно ссылки перебрать.


--------------------
user posted image нет времени думать - нужно писать КОД!

PM MAIL   Вверх
Ортхэннер
Дата 15.9.2008, 10:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 23
Регистрация: 29.1.2005
Где: Благовещенск

Репутация: нет
Всего: нет



Да знаю я, что они лениво будут загружены! Только дело-то в том как раз, что мне не надо, чтобы они грузились! Иначе приложение память будет кушать только в путь, да и медленнее обходить дерево таким образом, нежели на автомате. Ну ты сам посуди - это ж надо всё дерево будет в память загрузить. Куда это годится?

2 Plamenk: это и правда не оракул. Это Java Persistence. То есть БД там есть, но спрятана достаточно глубоко, и добраться до неё... можно, но, опять же, где гарантия, что это будет Oracle? у меня на машине вообще Java DB стоит... а надо, чтобы и с мусклом работало, и с Postgres... так что SQL-запросы если и можно использовать, то очень осторожно.
PM MAIL ICQ   Вверх
tux
Дата 15.9.2008, 10:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Летатель
***


Профиль
Группа: Участник Клуба
Сообщений: 1853
Регистрация: 10.2.2005
Где: msk.ru

Репутация: 74
Всего: 132



Цитата(Ортхэннер @  15.9.2008,  08:48 Найти цитируемый пост)
Можно ли одним запросом "выдернуть" всех потомков исходного объекта вне зависимости от поколения?

Цитата(Ортхэннер @  15.9.2008,  10:08 Найти цитируемый пост)
Только дело-то в том как раз, что мне не надо, чтобы они грузились!

Мне кажется или у вас что-то здесь не сходится? 

Цитата(Ортхэннер @  15.9.2008,  10:08 Найти цитируемый пост)
Иначе приложение память будет кушать только в путь

Если надо загрузить всех потомков, тогда будет кушать, если не надо, тогда не будет. По-моему, все просто. Не вижу проблем в обходе дерева, причем тут скорость не понятно. Плоский массив и дерево память будут расходовать одинаково - объекты одни и те же. Причем тут проблемы с памятью не ясно. Если нужно загрузить сразу все, просто поставь lazy=false.
PM MAIL Skype GTalk Jabber YIM   Вверх
Platon
Дата 15.9.2008, 10:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: 10
Всего: 40



Уважаемые, если выйти из тени JPA, то вот статья для размышления Дерево каталогов Nested Sets
PM MAIL ICQ   Вверх
powerOn
Дата 15.9.2008, 14:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


software saboteur
****


Профиль
Группа: Участник
Сообщений: 4367
Регистрация: 7.10.2005

Репутация: 28
Всего: 159



Цитата(tux @  15.9.2008,  11:33 Найти цитируемый пост)
Если нужно загрузить сразу все, просто поставь lazy=false. 

В JPA это будет как fetch=FetchType.EAGER в аннотации типа связи.


--------------------
user posted image нет времени думать - нужно писать КОД!

PM MAIL   Вверх
Ортхэннер
Дата 16.9.2008, 02:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 23
Регистрация: 29.1.2005
Где: Благовещенск

Репутация: нет
Всего: нет



Цитата(tux @  15.9.2008,  17:33 Найти цитируемый пост)
Мне кажется или у вас что-то здесь не сходится? 

Сорри, неправильно выразился. Надо получить количество потомков объекта. Но всех, а не только непосредственных.
А скорость здесь при том, что обход дерева - задача более трудоёмкая, нежели перебор массива. К тому же рекурсия сама по себе склонна потреблять больше памяти, чем итерационные алгоритмы, - за счёт стека.
PM MAIL ICQ   Вверх
Platon
Дата 16.9.2008, 08:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: 10
Всего: 40



Цитата(Ортхэннер @  16.9.2008,  03:09 Найти цитируемый пост)
К тому же рекурсия сама по себе склонна потреблять больше памяти, чем итерационные алгоритмы, - за счёт стека. 

Уважаемый пугает своей темнтой. Да ресурсов кушает больше, но от этого мало кто отказывался от ОО подхода или рекурсии.
PM MAIL ICQ   Вверх
Ортхэннер
Дата 17.9.2008, 07:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 23
Регистрация: 29.1.2005
Где: Благовещенск

Репутация: нет
Всего: нет



Уважаемый пугает своей наивностью. Всему своё место, знаете ли. Мне просто реально памяти не хватит - всё дерево обойти в нескольких потоках одновременно. StackOverflowError - видели такое?
PM MAIL ICQ   Вверх
Platon
Дата 17.9.2008, 07:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: 10
Всего: 40



Какой же такой гигантской глубины у вас дерево, если стека не хватает?
PM MAIL ICQ   Вверх
Ортхэннер
Дата 18.9.2008, 07:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 23
Регистрация: 29.1.2005
Где: Благовещенск

Репутация: нет
Всего: нет



Да не в глубине дело, вернее, не только в ней... кстати она не фиксирована, в общем случае - от 4 и выше. Там на последних двух уровнях у каждого узла уйма потомков получается. :-\ А поскольку крутится всё это не само по себе, а в компании много чего ещё - доступный объём памяти оказывается весьма ограничен. Плюс каждый поток работает с базой самостоятельно (пул, конечно, есть, но от этого не легче - это ж пул соединений с БД, а когда данные уже извлечены...), то есть при подключении десяти клиентов в памяти окажется десять "деревьев". И тут реально одно из двух - или OutOfMemoryError, или StackOverflowError, смотря по тому, хватит памяти на загрузку последней копии базы или нет. В любом случае дёргать объекты получается некошерно. Можно, конечно, делать выборку чисто ID... в этом случае памяти хватит. Но, откровенно говоря, хотелось бы всё-таки переложить эту работу на сервер приложений, а не трахаться самому... вот и интересуюсь - есть способ?
PM MAIL ICQ   Вверх
Platon
Дата 18.9.2008, 07:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: 10
Всего: 40



Цитата(Ортхэннер @  18.9.2008,  08:20 Найти цитируемый пост)
в общем случае - от 4 и выше

ну-ну, от такой рекурсии просто почти стопроцентное попадание на переполнение стека.

Добавлено через 7 минут и 50 секунд
всё, больше в занозу не лезу. smile 
PM MAIL ICQ   Вверх
Ортхэннер
Дата 18.9.2008, 11:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 23
Регистрация: 29.1.2005
Где: Благовещенск

Репутация: нет
Всего: нет



Платон, хочешь верь, хочешь нет, но такая ситуация реально была. Ты знаешь, сколько объектов находится на одном уровне иерархии? или размер в памяти одного объекта? или объём доступной памяти? нет?
Тогда хватит иронизировать. Нечего посоветовать по сабжу, лучше и правда молчи.
PM MAIL ICQ   Вверх
Hroft
Дата 22.9.2008, 17:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 310
Регистрация: 20.10.2003
Где: Москва

Репутация: нет
Всего: 3



Мне кажется, Platon всего лишь хотел сказать, что у вас принципиально что-то неправильно продумано. Он хочет вам помочь, а не выслушивать "да я сам все знаю, все умею, и вы ни фига не представляете, что у меня тут за МЕГАЗАДАЧА". Нужно как-то уважительнее относиться друг к другу.
Да, ситуации бывают разные. Но за 7 лет программирования я не видел ни одного StackOverflowError, вызванного сложностью задачи. Зато видел предостаточно вызванных... ммм... некорректным кодом.
Даже если рекурсия глубокая, кто заставляет хранить данные в автопеременных? Для больших объемов данных есть куча, может быть, полезно будет свой менеджер памяти небольшой сваять, хотя, опять же, в яве все это смотрится более чем подозрительно.
PM MAIL ICQ   Вверх
powerOn
Дата 22.9.2008, 20:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


software saboteur
****


Профиль
Группа: Участник
Сообщений: 4367
Регистрация: 7.10.2005

Репутация: 28
Всего: 159



Я так понимаю что задача сводится к нахождению всех листовых узлов дерева объектов. А может попробовать грамотно запрос на JPA написать, который их находить будет?


--------------------
user posted image нет времени думать - нужно писать КОД!

PM MAIL   Вверх
Ортхэннер
Дата 23.9.2008, 02:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 23
Регистрация: 29.1.2005
Где: Благовещенск

Репутация: нет
Всего: нет



Hroft:
В Java менеджер памяти заменить, к сожалению, впрямую нельзя (ограничения безопасности). Есть объекты-ссылки, позволяющие в какой-то степени разрулить ситуацию, когда памяти не хватает, но если полагаться на fetch=FetchType.EAGER в JPA, то пристроить эти объекты оказывается уже некуда. Может быть (и даже более вероятно), не StackOverflow, а OutOfMemory, но... с точки зрения результата - невелика разница. :( Мне памяти-то доступно метров, может, двадцать. А когда на листьях оказываются объекты размерчиком эдак по килобайту, и их несколько тысяч... а теперь представьте, что эту же структуру из базы дёргают ещё два-три хотя бы потока (а их будет не два-три)... и всё, "приплыли", как говорится.
Веб-приложение, чтоб его. :-\

powerOn, типа того, но не совсем. Мне бы количество узлов в конкретной ветви дерева найти. Листья-то что - запрос вроде вот этого, и всё:
Код

SELECT COUNT(b) FROM Bean b WHERE b.parent IS NOT NULL AND b.children IS EMPTY

Можно, конечно, извратиться и использовать вложенный запрос, но зачем? - и так сработает.
А вот как посчитать количество вообще всех потомков конкретного узла - это вопрос...
PM MAIL ICQ   Вверх
Hroft
Дата 23.9.2008, 10:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 310
Регистрация: 20.10.2003
Где: Москва

Репутация: нет
Всего: 3



Не знаю, насколько здравым будет предложение, но вот оно.
А что, если при помощи вообще сторонней программки просто создать сущность, хранящую необходимую информацию? Тупо написать обычную программу, которая с какой-то периодичностью будет обновлять эти данные. В результате при работе ограниченной по памяти (и времени, насколько я понимаю) программы вообще не будет ничего ни загружаться, ни считаться. На память сторонней программы, которая уж точно будет работать в один поток и иметь больше 20 мегов памяти в своем распоряжении, нам, по сути, наплевать.
Пойдет так?

Это сообщение отредактировал(а) Hroft - 23.9.2008, 10:58
PM MAIL ICQ   Вверх
Platon
Дата 23.9.2008, 11:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: 10
Всего: 40



Цитата(Hroft @  23.9.2008,  11:57 Найти цитируемый пост)
Не знаю, насколько здравым будет предложение, но вот оно.

По мне так очень здравое, и вообще можно сделать в логику программы инкремент в этой таблице. Получится запросов всего 4+, и памяти минимум.
PM MAIL ICQ   Вверх
Ортхэннер
Дата 25.9.2008, 02:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 23
Регистрация: 29.1.2005
Где: Благовещенск

Репутация: нет
Всего: нет



Действительно, мысль интересная. В принципе, попробовать ничто не мешает, хотя при этом в промежутке между обновлениями индекса пользователь будет получать недостоверную информацию (кстати, проверено - часто такую прогу не позапускаешь, во время анализа загрузка процессора растёт очень сильно, а снижать приоритет потоку - так он работать будет дольше желаемого). Ещё можно всё-таки сделать рекурсию в самой программе, но дёргать только ID объектов базы, а не сами объекты. Возни чуть больше, но зато в память укладываюсь, особенно если обернуть их в PhantomReference. Плюс - ID выбирается шустрее, чем сам объект, что тоже очень приятно. А количество прямых потомков узла при этом определяется автоматически - по длине результирующего списка. Не так уж сложно. "Дёрнуть" из базы после этого связанную сущность по какому-либо критерию тоже не проблема, QL-запросам можно же коллекции в качестве параметров передавать?
PM MAIL ICQ   Вверх
Страницы: (2) [Все] 1 2 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   tux
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java EE (J2EE) и Spring | Следующая тема »


 




[ Время генерации скрипта: 0.1119 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.