我有一个很大的postgresql数据库,包括艺术家,歌曲和歌曲之间的封面关系。我想在数据库中找到最长的封面关系链,类似于http://www.coversproject.com/artist/longest_chain
最后我想要这样的事情:
在我的用例中,任何艺术家只能在列表中出现一次,这使得这更加棘手。我在这里也简化了我的数据库结构,使问题不那么具体,但这不应成为问题。
在我看来,没有神奇的查询会给我一个明确的答案。我想我需要某种算法,用不同的起始条目一遍又一遍地查询数据库,同时存储每个查询运行的结果。过了一会儿,我只选择那段时间内找到的最长的链条,这可能不是现有的最长的链条,但对我来说足够好了。
有关如何实现这一目标的任何指示? (本地使用postgres或编写查询数据库的脚本)
答案 0 :(得分:1)
在“The Stanford GraphBase”一节中,FOOTBALL Knuth考虑了在“A节拍B乘5,B节拍C乘9,C节拍D乘43 ......”形式的足球队之间寻找长链游戏的问题。提供一个论证,即A对Z的预期获胜幅度很大。他表示这是一个NP完全问题,并要求提出建议。他实际编程的是他称之为分层贪婪的东西,看起来很像http://en.wikipedia.org/wiki/Beam_search。
前段时间我花了一些时间玩Beam Search寻求乐趣,但最后开始想知道有限差异搜索是否更好 - 它往往要求你花更少的时间来节省部分答案的状态,因为它是非常接近回溯,当您做出更多假设或撤回似乎不起作用的假设时,您通常会对答案做出微小的更改。
答案 1 :(得分:1)
create table chain_helper (
head int,
tail int,
chain_length int
)
create index chain_helper_by_head(head);
create index chain_helper_by_tail(tail);
这个表的想法是包含所有可能的链接,其中head和tail是外键。我的情况稍微容易一点,因为我有一个严格的层次结构,不需要循环控制。源表具有id和parent_id字段。以下是我填充表格的方式:
使用简单链接初始化表格:
insert into chain_helper (head, tail, chain_length)
select id, parent_id, 1 from source_table;
我继续用长度为2的所有链子填充表格:
insert into chain_helper (head, tail, chain_length)
select parent.head, child.tail, min(parent.chain_length + 1)
from chain_helper parent
join source_table child on source_table.parent_id=parent.id
where not exists
(select * from chain_helper where head=parent.head and tail=child.tail)
group by parent.head, child.tail;
(因为我有一个严格的层次结构,我不需要聚合 - 在我的情况下不会有重复)。
重复将插入长度为3的所有链等,并且可以重复所有语句,直到无需插入任何内容。然后找到最大链长是微不足道的:
select max(chain_length) from chain_helper;
这个解决方案并不容易显示链条 - 但在我的情况下这并不是一个要求。我主要在连接中使用chain_helper来捕获层次结构中特定节点的所有子节点 - 即"此子树的总收入":
select sum(source_table.revenue)
from source_table join chain_helper on chain_helper.tail = source_table.id
where chain_helper.head = parent_of_subtree;
答案 2 :(得分:0)
我不太确定我能得到你想要的东西,a。但是,我会做类似的事情:
WITH RECURSIVE chain (artist_id, path) (
SELECT id, id::text from artist
UNION
SELECT a.id, path || ',' || a.id
FROM artist a
JOIN covers co ON (co.covered_by = a.id)
JOIN chain ch ON (co.originally_by = ch.artist_id)
)
SELECT *
FROM artist a
JOIN chain c ON c.artist_id = a.id
ORDER BY array_upper(string_to_array(c.path, ',')::int[], 1)
LIMIT 1;
请注意,对于很多艺术家而言,表现并不是那么好,但如果您可以缩小搜索条件范围,那就可以提供帮助。