| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > Java EE (J2EE) и Spring > Рекурсия в persistence |
| Автор: Ортхэннер 15.9.2008, 08:48 | ||||||
Имеем следующий класс:
Можно ли одним запросом "выдернуть" всех потомков исходного объекта вне зависимости от поколения? (т. е. чтобы не только
но и
и т. д.) |
| Автор: Plamenk 15.9.2008, 09:00 |
| Средствами Oracle можно. См. "connect by prior". Но судя по коду ты работаешь с объектами не БД... так что этот способ здесь наверное не поможет. |
| Автор: powerOn 15.9.2008, 09:03 |
| Если ты вытянешь корневой объект (т.е. предка для тех потомков которые ищешь), то связанные объекты будут загружены либо автоматом (для односсылочных связей), либо лениво. Фактически делать ничего не нужно, только грамотно ссылки перебрать. |
| Автор: Ортхэннер 15.9.2008, 10:08 |
| Да знаю я, что они лениво будут загружены! Только дело-то в том как раз, что мне не надо, чтобы они грузились! Иначе приложение память будет кушать только в путь, да и медленнее обходить дерево таким образом, нежели на автомате. Ну ты сам посуди - это ж надо всё дерево будет в память загрузить. Куда это годится? 2 Plamenk: это и правда не оракул. Это Java Persistence. То есть БД там есть, но спрятана достаточно глубоко, и добраться до неё... можно, но, опять же, где гарантия, что это будет Oracle? у меня на машине вообще Java DB стоит... а надо, чтобы и с мусклом работало, и с Postgres... так что SQL-запросы если и можно использовать, то очень осторожно. |
| Автор: Platon 15.9.2008, 10:53 |
| Уважаемые, если выйти из тени JPA, то вот статья для размышления http://www.getinfo.ru/article610.html |
| Автор: powerOn 15.9.2008, 14:36 |
В JPA это будет как fetch=FetchType.EAGER в аннотации типа связи. |
| Автор: Ортхэннер 16.9.2008, 02:09 |
Сорри, неправильно выразился. Надо получить количество потомков объекта. Но всех, а не только непосредственных. А скорость здесь при том, что обход дерева - задача более трудоёмкая, нежели перебор массива. К тому же рекурсия сама по себе склонна потреблять больше памяти, чем итерационные алгоритмы, - за счёт стека. |
| Автор: Platon 16.9.2008, 08:08 | ||
Уважаемый пугает своей темнтой. Да ресурсов кушает больше, но от этого мало кто отказывался от ОО подхода или рекурсии. |
| Автор: Ортхэннер 17.9.2008, 07:22 |
| Уважаемый пугает своей наивностью. Всему своё место, знаете ли. Мне просто реально памяти не хватит - всё дерево обойти в нескольких потоках одновременно. StackOverflowError - видели такое? |
| Автор: Platon 17.9.2008, 07:39 |
| Какой же такой гигантской глубины у вас дерево, если стека не хватает? |
| Автор: Ортхэннер 18.9.2008, 07:20 |
| Да не в глубине дело, вернее, не только в ней... кстати она не фиксирована, в общем случае - от 4 и выше. Там на последних двух уровнях у каждого узла уйма потомков получается. :-\ А поскольку крутится всё это не само по себе, а в компании много чего ещё - доступный объём памяти оказывается весьма ограничен. Плюс каждый поток работает с базой самостоятельно (пул, конечно, есть, но от этого не легче - это ж пул соединений с БД, а когда данные уже извлечены...), то есть при подключении десяти клиентов в памяти окажется десять "деревьев". И тут реально одно из двух - или OutOfMemoryError, или StackOverflowError, смотря по тому, хватит памяти на загрузку последней копии базы или нет. В любом случае дёргать объекты получается некошерно. Можно, конечно, делать выборку чисто ID... в этом случае памяти хватит. Но, откровенно говоря, хотелось бы всё-таки переложить эту работу на сервер приложений, а не трахаться самому... вот и интересуюсь - есть способ? |
| Автор: Platon 18.9.2008, 07:49 |
ну-ну, от такой рекурсии просто почти стопроцентное попадание на переполнение стека. Добавлено через 7 минут и 50 секунд всё, больше в занозу не лезу. |
| Автор: Ортхэннер 18.9.2008, 11:02 |
| Платон, хочешь верь, хочешь нет, но такая ситуация реально была. Ты знаешь, сколько объектов находится на одном уровне иерархии? или размер в памяти одного объекта? или объём доступной памяти? нет? Тогда хватит иронизировать. Нечего посоветовать по сабжу, лучше и правда молчи. |
| Автор: Hroft 22.9.2008, 17:00 |
| Мне кажется, Platon всего лишь хотел сказать, что у вас принципиально что-то неправильно продумано. Он хочет вам помочь, а не выслушивать "да я сам все знаю, все умею, и вы ни фига не представляете, что у меня тут за МЕГАЗАДАЧА". Нужно как-то уважительнее относиться друг к другу. Да, ситуации бывают разные. Но за 7 лет программирования я не видел ни одного StackOverflowError, вызванного сложностью задачи. Зато видел предостаточно вызванных... ммм... некорректным кодом. Даже если рекурсия глубокая, кто заставляет хранить данные в автопеременных? Для больших объемов данных есть куча, может быть, полезно будет свой менеджер памяти небольшой сваять, хотя, опять же, в яве все это смотрится более чем подозрительно. |
| Автор: powerOn 22.9.2008, 20:15 |
| Я так понимаю что задача сводится к нахождению всех листовых узлов дерева объектов. А может попробовать грамотно запрос на JPA написать, который их находить будет? |
| Автор: Ортхэннер 23.9.2008, 02:05 | ||
| Hroft: В Java менеджер памяти заменить, к сожалению, впрямую нельзя (ограничения безопасности). Есть объекты-ссылки, позволяющие в какой-то степени разрулить ситуацию, когда памяти не хватает, но если полагаться на fetch=FetchType.EAGER в JPA, то пристроить эти объекты оказывается уже некуда. Может быть (и даже более вероятно), не StackOverflow, а OutOfMemory, но... с точки зрения результата - невелика разница. :( Мне памяти-то доступно метров, может, двадцать. А когда на листьях оказываются объекты размерчиком эдак по килобайту, и их несколько тысяч... а теперь представьте, что эту же структуру из базы дёргают ещё два-три хотя бы потока (а их будет не два-три)... и всё, "приплыли", как говорится. Веб-приложение, чтоб его. :-\ powerOn, типа того, но не совсем. Мне бы количество узлов в конкретной ветви дерева найти. Листья-то что - запрос вроде вот этого, и всё:
Можно, конечно, извратиться и использовать вложенный запрос, но зачем? - и так сработает. А вот как посчитать количество вообще всех потомков конкретного узла - это вопрос... |
| Автор: Hroft 23.9.2008, 10:57 |
| Не знаю, насколько здравым будет предложение, но вот оно. А что, если при помощи вообще сторонней программки просто создать сущность, хранящую необходимую информацию? Тупо написать обычную программу, которая с какой-то периодичностью будет обновлять эти данные. В результате при работе ограниченной по памяти (и времени, насколько я понимаю) программы вообще не будет ничего ни загружаться, ни считаться. На память сторонней программы, которая уж точно будет работать в один поток и иметь больше 20 мегов памяти в своем распоряжении, нам, по сути, наплевать. Пойдет так? |
| Автор: Platon 23.9.2008, 11:08 |
По мне так очень здравое, и вообще можно сделать в логику программы инкремент в этой таблице. Получится запросов всего 4+, и памяти минимум. |
| Автор: Ортхэннер 25.9.2008, 02:29 |
| Действительно, мысль интересная. В принципе, попробовать ничто не мешает, хотя при этом в промежутке между обновлениями индекса пользователь будет получать недостоверную информацию (кстати, проверено - часто такую прогу не позапускаешь, во время анализа загрузка процессора растёт очень сильно, а снижать приоритет потоку - так он работать будет дольше желаемого). Ещё можно всё-таки сделать рекурсию в самой программе, но дёргать только ID объектов базы, а не сами объекты. Возни чуть больше, но зато в память укладываюсь, особенно если обернуть их в PhantomReference. Плюс - ID выбирается шустрее, чем сам объект, что тоже очень приятно. А количество прямых потомков узла при этом определяется автоматически - по длине результирующего списка. Не так уж сложно. "Дёрнуть" из базы после этого связанную сущность по какому-либо критерию тоже не проблема, QL-запросам можно же коллекции в качестве параметров передавать? |