У меня есть таблица identities
(т. Е. Псевдонимы) для произвольного числа людей. Каждая строка имеет предыдущее имя и новое имя. В производстве имеется около 1 М строк. Например:Поиск остовного леса (WITH RECURSIVE, PostgreSQL 9.5)
id, old, new
---
1, 'Albert', 'Bob'
2, 'Bob', 'Charles'
3, 'Mary', 'Nancy'
4, 'Charles', 'Albert'
5, 'Lydia', 'Nancy'
6, 'Zoe', 'Zoe'
То, что я хочу, чтобы создать список users
и ссылки на все их соответствующих идентичностей. Это аналогично нахождение всех узлов в каждом графике подключенных идентичностей, или найти остовный леса:
User 1: Albert, Bob, Charles (identities: 1,2,4)
User 2: Mary, Nancy, Lydia (identities: 3,5)
User 3: Zoe (identities: 6)
Я мастерить с PostgreSQL, WITH RECURSIVE
, но она дает оба набор и подмножество для каждого. Например:
1,2,4 <-- spanning tree: good
2 <-- subset: discard
3,5 <-- spanning tree: good
4 <-- subset: discard
5 <-- subset: discard
6 <-- spanning tree: good
Что мне нужно сделать, чтобы производить только полные наборы идентификаторов (т.е. Spanning Tree) для каждого пользователя?
SQLFiddle: http://sqlfiddle.com/#!15/9eaed/4 с моей последней попыткой. Вот код:
WITH RECURSIVE search_graph AS (
SELECT id
, id AS min_id
, ARRAY[id] AS path
, ARRAY[old,new] AS emails
FROM identities
UNION
SELECT identities.id
, LEAST(identities.id, sg.min_id)
, (sg.path || identities.id)
, (sg.emails || identities.old || identities.new)
FROM search_graph sg
JOIN identities ON (identities.old = ANY(sg.emails) OR identities.new = ANY(sg.emails))
WHERE identities.id <> ALL(sg.path)
)
SELECT array_agg(DISTINCT(p)) from search_graph, unnest(path) p GROUP BY min_id;
И результаты:
1,2,4
2
3,5
4
5
6
У меня есть ощущение, что подмножества проявляющиеся в результатах, потому что они не точные дубликаты других промежуточных результатов и, следовательно, они не устранены. Это происходит из-за того, что я сохраняю избыточную информацию в 'search_graph' и не сортирую такие вещи, как содержимое' path' –
'distinct' is *** *** *** функция. –