Как посчитать количество распространенных двунаправленных соединений на графике - PullRequest
4 голосов
/ 27 ноября 2010

Я пытаюсь написать запрос, который подсчитывает количество двунаправленных (сильных) соединений между пользователями, которые представляют узлы на графике.

Для проверки запроса я создал следующий образец

alt text

, который хранится в таблице month_connections_test:

calling_party, called_party, link_strength


z1  z2  1,0000000
z1  z3  1,0000000
z3  z1  1,0000000
z1  z4  1,0000000
z1  z5  1,0000000
z5  z1  1,0000000
z2  z4  1,0000000
z2  z5  1,0000000
z5  z2  1,0000000
z2  z7  1,0000000
z7  z2  1,0000000
z4  z7  1,0000000
z7  z4  1,0000000
z2  z1  1,0000000

Следующий запрос возвращает 2 для сильных соединений между z1 и z2 вместо 1:

SELECT  user1, user2, 0 AS calling_calling, 0 AS calling_called, 0 AS called_calling, 0 AS called_called, COUNT(*) AS both_directions
 FROM   (SELECT monthly_connections_test.calling_party AS user1, monthly_connections_test_1.calling_party AS user2
FROM         monthly_connections_test INNER JOIN
                      monthly_connections_test AS monthly_connections_test_1 ON 
                      monthly_connections_test.called_party = monthly_connections_test_1.called_party AND 
                      monthly_connections_test.calling_party < monthly_connections_test_1.calling_party) t1 
                      INNER JOIN monthly_connections_test AS monthly_connections_test_2 ON
                      t1.user2 = monthly_connections_test_2.called_party
                      AND t1.user2 < monthly_connections_test_2.calling_party
GROUP BY t1.user1, t1.user2

Результаты в следующем примере:

z1  z2  0   0   0   0   2
z2  z3  0   0   0   0   3
z2  z4  0   0   0   0   1
z1  z5  0   0   0   0   3
z2  z5  0   0   0   0   3
z3  z5  0   0   0   0   2
z1  z7  0   0   0   0   4
z2  z7  0   0   0   0   1
z5  z7  0   0   0   0   1

Кто-нибудь знает, как изменить запрос, чтобы он возвращал количество общих соседей, которые связаны в обоих направлениях (в этом примере правильное значение для z1, z2 равно 1, так как z5 связан с обоими z1 и z2 в обоих направления)?

Проблема, я думаю, в части

INNER JOIN monthly_connections_test AS monthly_connections_test_2 ON
                      t1.user2 = monthly_connections_test_2.called_party
                      AND t1.user2 < monthly_connections_test_2.calling_party

Правильный результат должен быть следующим:

z1  z2  0   0   0   0   1
z2  z3  0   0   0   0   1
z2  z4  0   0   0   0   1
z1  z5  0   0   0   0   1
z2  z5  0   0   0   0   1
z3  z5  0   0   0   0   1
z1  z7  0   0   0   0   1
z2  z7  0   0   0   0   0
z5  z7  0   0   0   0   1

Условие соединения должно быть сформулировано таким образом, чтобы каждое соединение подсчитывалось только один раз (ранее подключенные соединения должны быть исключены на этом этапе), но не нашли решения.

P.S. Поскольку исходная таблица состоит из 24M записей, запрос должен быть написан таким образом, чтобы он возвращал результаты в приемлемом количестве времени. Попытка сначала написать запрос с несколькими вариантами выбора заняла слишком много времени.

Ответы [ 2 ]

0 голосов
/ 28 ноября 2010

Используя несколько решений, следующий запрос вернул правильные результаты для примера выше:

    SELECT  t1.user1, t1.user2, 0 AS calling_calling, 0 AS calling_called, 0 AS called_calling, 0 AS called_called, COUNT(*) AS both_directions
 FROM   (SELECT monthly_connections_test.calling_party AS user1, monthly_connections_test_1.calling_party AS user2, monthly_connections_test.called_party AS calledUser
FROM         monthly_connections_test INNER JOIN
                      monthly_connections_test AS monthly_connections_test_1 ON 
                      monthly_connections_test.called_party = monthly_connections_test_1.called_party AND 
                      monthly_connections_test.calling_party < monthly_connections_test_1.calling_party) t1 
                      INNER JOIN monthly_connections_test AS monthly_connections_test_2 ON
                      monthly_connections_test_2.called_party = t1.user1
                      AND monthly_connections_test_2.calling_party = t1.calledUser
0 голосов
/ 27 ноября 2010

сначала написать табличную функцию -

create function getBiConnectedNeighbours
(
@P_PARTY nvarchar(50)
)
returns table
as
return
(
   select called_party as neighbour
     from monthly_connections_test a
     where calling_party = @P_PARTY
       and exists (select 1 from monthly_connections_test b
                      where a.called_party = b.calling_party and
                            b.called_party = a.calling_party) -- this subquery is to get bidirectionals only

)

затем используйте функцию как

select count(1) 
from getBiConnectedNeighbours('z1') a inner join
     getBiConnectedNeighbours('z2') b on a.neighbour = b.neighbour
...