Модераторы: skyboy, MoLeX, Aliance, ksnk

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Граф в БД, Алгоритмы для работы с графами 
:(
    Опции темы
Sunvas
Дата 28.7.2007, 10:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Соль и сахар
****


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

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



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

Например:
1 - 2,4
2 - 1,3,4
3 - 2,4
4 - 3,1,2

Как проверить и исправить ошибки в записи этого графа?
Т.е. если первая вершина соеденена с 4й, то и 4я должна быть соеденена с первой. Если в connectedids четвертой нет первой, то такую запись надо добавить.

Как удалить вершину графа?
Вместе с удалением всей записи вершины, удалить из connectedids других вершин все ссылки на удаленную

Никак не могу придумать оптимального алгоритма с минимальным количеством запросов в базу.  smile Помогите.  smile 


--------------------
Воспитывая детей по своему образу и подобию, родители почему-то надеются, что они будут лучше их.
PM MAIL   Вверх
Mal Hack
Дата 28.7.2007, 11:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Мудрый...
****


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

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



У тебя изначально информация не верно хранится. Надо хранить отдельно родителей, отдельно предков.
Плюс, задача проверки - какая? Графы разгные бывают и замкнутые в том числе.
И вообще, задача на практике - какая?
PM ICQ   Вверх
Golda
Дата 28.7.2007, 15:02 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 460
Регистрация: 26.3.2007
Где: Ариель, Израиль

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



Цитата(Mal Hack @  28.7.2007,  11:45 Найти цитируемый пост)
Надо хранить отдельно родителей, отдельно предков.


Что-то не поняла идею. 

Я бы предложила хранить отдельно врешины, отдельно ребра. Поскольку по условию задачи граф не ориентированный, то каждое ребро достаточно хранить один раз. Если уже записали (1,4), не нужно писать (4,1). Тогда и такая проверка на ошибки записи не нужна. А ответственность за целостность данных (удаление ребер, при удалении инцидентных им вершин) можно возложить на саму базу, если использовать foreign keys, указав ON DELETE CASCADE 


--------------------
"For every problem, there exists a simple and elegant solution which is absolutely wrong." -- J. Wagoner, U.C.B. Mathematics
PM MAIL   Вверх
Mal Hack
Дата 28.7.2007, 21:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Мудрый...
****


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

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



Цитата
Что-то не поняла идею. 

Идея - дерево.
Тут главное, чтобы автор пояснил свою задачу в абстрактном изъяснении... А иначе будем гадать что и как. Дерево тож не везде сгодится.
PM ICQ   Вверх
WolfON
Дата 28.7.2007, 22:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Mal Hack, идея не понятна по другому, допустим есть:
Код

1 -> 2 -> 3
        \ 4 -> 5

Тут у элемент 1 - корень дерева, у элемента 2 - родитель 1, а у элементов 3 и 4 - родитель 2.
Те хранить отдельно родителей и детей не получится - задача поставлена не верно.
Причем условием является хранение графа, а не дерева, как его частного случая.
PM MAIL ICQ   Вверх
Mal Hack
Дата 28.7.2007, 22:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Мудрый...
****


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

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



Я сказал: "хранить родителей и детей отдельно для КАЖДОЙ вершины или единицы графа". Это совершенно другой смысл.
PM ICQ   Вверх
Golda
Дата 28.7.2007, 23:17 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 460
Регистрация: 26.3.2007
Где: Ариель, Израиль

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



Цитата(Mal Hack @  28.7.2007,  21:14 Найти цитируемый пост)
Идея - дерево.


А, в смысле, надо было читать, отдельно родителей, отдельно ДЕТЕЙ. Так ясно.  Дерево хорошо тем, что для него есть подробно разработанные схемы обхода. Но, как Вы справедливо заметили, не подойдет для графа с циклами. В общем-то, для неориентированного графа понятия родителей и детей - несколько искуственное, только для обхода и имеет смысл. Но Вы правы, лучше подождать разъяснения автора темы о характере задачи, тогда можно будет отбирать более рациональный вариант


--------------------
"For every problem, there exists a simple and elegant solution which is absolutely wrong." -- J. Wagoner, U.C.B. Mathematics
PM MAIL   Вверх
WolfON
Дата 28.7.2007, 23:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Mal Hack
Цитата
Надо хранить отдельно родителей, отдельно предков.

Это не рационально - допустим три связанные вершины - в худшем случае получится 3 таблицы - в одной все предки 1 вершины, во второй все предки второй и тд
В лучшем случае получится таблица предков и таблица родителей с дублированной информацией.

Вот есть такая идея:
http://forums.lavag.org/index.php?showtopic=3250
воообщем-то тоже самое, что сказала Golda
PM MAIL ICQ   Вверх
Sunvas
Дата 29.7.2007, 17:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Соль и сахар
****


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

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



Объясняю суть задачи.
Требуется доработать проект большой энциклопедии, а именно добавить функцию списка "смотри также".
Т.е. каждая статья является вершиной графа. А в отдельном поле каждой статьи храняется связанные с ней по смыслу статьи. Понятное дело, что если 4я статья ссылается на 107ю, то и 107я должна ссылаться на 4ю.
Такой метод хранения был выбран поскольку акцент делается именно на незамедлительный просмотр связанных статей.


--------------------
Воспитывая детей по своему образу и подобию, родители почему-то надеются, что они будут лучше их.
PM MAIL   Вверх
Mal Hack
Дата 29.7.2007, 17:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Мудрый...
****


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

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



WolfON, еще раз посмотри на мою фразу: "Я сказал: "хранить родителей и детей отдельно для КАЖДОЙ вершины или единицы графа". Это совершенно другой смысл. " 

Ты не понимаешь меня ;)


Sunvas, тебе нужно как раз дерево, причем все рализовывается намного проще, чем ты думаешь.
Скажи, как храняться сами статьи в базе и должны ли показываться ссылки на "похожие" страницы, когда мы смотрим 4 статью, а для нее "похожая" 119, а для нее - 136, более глубоки по уровню "похожести"?
PM ICQ   Вверх
Sunvas
Дата 29.7.2007, 17:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Соль и сахар
****


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

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



Статьи хранятся в одной таблице, со структурой:

id - номер статьи
title, contenet, [другие служебные поля]
seealso - вот тут мы через запятую и храним ссылки на другие статьи


--------------------
Воспитывая детей по своему образу и подобию, родители почему-то надеются, что они будут лучше их.
PM MAIL   Вверх
Mal Hack
Дата 29.7.2007, 19:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Мудрый...
****


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

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



Есть возможность сделать еще одну таблицу из двух полей или обязательно надо обойтись полем seealso?
PM ICQ   Вверх
Sunvas
Дата 29.7.2007, 20:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Соль и сахар
****


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

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



Таблицу создать, проблем нет. Но опять таки, акцент делается именно на моментальную загрузку любой статьи с наименьшим количеством запросов.


--------------------
Воспитывая детей по своему образу и подобию, родители почему-то надеются, что они будут лучше их.
PM MAIL   Вверх
Mal Hack
Дата 29.7.2007, 21:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Мудрый...
****


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

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



Я бы сделал так.
Делаем таблицу из двух полей. Оба поля содержат ID статей.
Соотвественно в эти поля заносим два ID дву статей, которые "похожи" друг на друга.
Соответственно, когда надо достать список, делаем
SELECT `*` FROM myt WHERE id1 = $id OR id2 = $id.
Так получим список ID статей, которые так или иначе "похожи" на нашу.
Причем надо будет потом, из него (мы же получим матрицу из двух столбцов и n строк) сделать один массив, откуда удалить повторяющиеся (по хорошему этого быть не должно, надо следить за повторами на этапе добавления связи).
Затем делаем SELECT `*` FROM myt WHERE id1 IN ($mylist) OR id2 IN ($mylist).
Это уже два этапа вложенности, думаю хватит.
Проверок соответственно уже не надо делать, а саязана ли 4 с 3, если 3 связана с 4.
PM ICQ   Вверх
Sunvas
Дата 29.7.2007, 23:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Соль и сахар
****


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

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



Хм. Я подумаю над таким вариантом. Однако статей в энциклопедии действительно много, за быстродействие опасаюсь. Нужен только один уровень вложенности.


--------------------
Воспитывая детей по своему образу и подобию, родители почему-то надеются, что они будут лучше их.
PM MAIL   Вверх
Mal Hack
Дата 30.7.2007, 00:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Мудрый...
****


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

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



Если действительно статей, как в википедии, то можно воспользоваться и одним полем в таблице самих статей. Сделать его строковым, к примеру разделить числа "|", ну и в момент редактирования статьи, если похожая статья добавляется, то ее надо добавить и в добавляемой. При удалении тоже самое. Я бы так сделал вряд ли. Уж на крайний случай сделал так, но в отдельной таблице, где есть поля только ID статьи и seealso.

Тут надо тестировать... 
PM ICQ   Вверх
Sunvas
Дата 30.7.2007, 00:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Соль и сахар
****


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

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



А чем отдельная таблица лучше дополнительного поля?


--------------------
Воспитывая детей по своему образу и подобию, родители почему-то надеются, что они будут лучше их.
PM MAIL   Вверх
Fally
Дата 30.7.2007, 09:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Хранить в одном поле информацию, которую затем ещё и парсить, занятие, ИМХО, не из благородных (в отношении к серверу.).. т.к. вместо того, чтобы нормализовать БД вынеся всю схожую информацию в отдельную таблицу и выбирать это 1-2 запросами, Вы будете выбирать информацию, а потом средствами РНР её ещё и парсить... очень много интересеного по поводу древовидных структур в БД и работы с ними можно прочитать здесь.


--------------------
Прежде чем задать вопрос на форуме воспользуйтесь поиском.
user posted image
user posted image
PM MAIL   Вверх
Mal Hack
Дата 30.7.2007, 13:51 (ссылка) |    (голосов:2) Загрузка ... Загрузка ... Быстрая цитата Цитата


Мудрый...
****


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

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



Sunvas, отдельная таблица - ты покупаешь кухонный стол, а в единой таблице, ты покупаешь стол, тебе дают 20 стульев, 25 сервизов, лампочку и зубную счетку, и спрашивается а нафига мне напильник, если  не курю.
PM ICQ   Вверх
Sunvas
Дата 30.7.2007, 14:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Соль и сахар
****


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

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



Fally, проблем с парсингом нет. Тут один хороший человек показал как сделать все красиво. Mal Hack, интересно объяснил. )


--------------------
Воспитывая детей по своему образу и подобию, родители почему-то надеются, что они будут лучше их.
PM MAIL   Вверх
Golda
Дата 31.7.2007, 07:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 460
Регистрация: 26.3.2007
Где: Ариель, Израиль

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



Mal Hack, объяснение - супер  smile 

Кстати, Вы, фактически, повторили мою идею, и к дереву Ваш последний вариант отношения не имеет, т.к. не гарантируется ни связаность графа, ни отсутсвие циклов. Рассмотрите, например, вариант,

(1, 2, 3), (4,5) - где в каждых скобках - набор попарно связанных статей. Это никак не дерево.

Добавлю также, что если сделать сочетание (id1, id2) - первичным ключом, и выработать соглашение, благодаря которому пары всегда будут записываться в одном и том же порядке (например, id1 - всегда меньший, id2 - всегда больший, то и дополнительные запросы для проверки целостности не понадобятся. Ну и не забыть сделать для каждого из полей id1, id2 - внешний ключ с ON DELETE CASCADE, чтобы не заботиться о том, что будет со связями при удалении.

Sunvas, хранение нескольких значений в одном поле противоречит одному из ключевых принципов построения реляционной базы данных: атомарности полей таблиц. DB. Вы теряете на этом возможность переложить на базу данных часть забот о ее целостности и усложняете себе жизнь при составлении всевозможных запросов, кроме, может быть, одного, заранее выбранного. Вариант, при котором ребра хранятся отдельно от вершин, если проставлены все нужные ключи, дает Вам больше гарантий целостности базы и, думаю, должен положительно сказаться на быстродействии при выборе статьи. Вам ведь на самом деле, наверное, не id связанной статьи в базе нужно  показать, а какие-то другие ее поля (название, например).
Значит, понадобятся два запроса: одним выбирает seealso, а дальше в PHP нужно составлять второй запрос типа 

Код

$sql = ".. AND id IN ($seealso)";


В случае же, о которым писали Mal Hack и я, несложно сделать все на уровне SQL, не прибегая к помощи PHP.

Код

SELECT a.title
FROM article AS a INNER JOIN relations AS r ON a.id = r.id1 OR a.id = r.id2
WHERE r.id1 = 5 OR r.id2 = 5


Но даже, если Вы не потратили впустую первый запрос, выбрав в нем все остальные данные о статье, конструкция IN в запрросе - не самая быстрая. Посмотрите, недавно Sta1ker приводил данные своего тестирования для MySQL. http://forum.vingrad.ru/forum/topic-165156.html

Подумайте о том, что усложняются и все остальные операции: добавления, удаления статей, выбора всевозможной статистики. Вы лишаете себя возможности сделать что бы то ни было, связанное с полем seealso, одним запросом.


--------------------
"For every problem, there exists a simple and elegant solution which is absolutely wrong." -- J. Wagoner, U.C.B. Mathematics
PM MAIL   Вверх
Страницы: (2) [Все] 1 2 
Ответ в темуСоздание новой темы Создание опроса
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | PHP: Базы Данных | Следующая тема »


 




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


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

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