Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Consulta de Graus de Separação


Veja como realizar a pesquisa usando uma pesquisa de caminho mais curto e em largura, usando JOIN. Não há mágica neste algoritmo, pois estamos usando o MySQL para encontrar nossa resposta e não estamos incorporando nenhum algoritmo de pesquisa sofisticado que use qualquer tipo de heurística ou otimização.

Minha tabela de 'amigos' tem relacionamentos unidirecionais, então temos duplicatas no sentido de que '1 para 2' e '2 para 1' são armazenados. Também estou excluindo is_active, pois a implementação será óbvia:

Aqui estão os dados:
member_id   friend_id
1           2
1           3
1           4
2           1
2           3
2           5
2           6
3           2
3           1
4           1
5           2
6           2
6           7
7           6
7           8
8           7

Temos o membro 1 selecionado, e estamos perguntando é 1 amigo com 7, amigo de um amigo, etc.? Uma contagem de 0 significa não, e uma contagem de 1 significa sim.
SELECT COUNT(*)
FROM friends f1
WHERE f1.member_id = 1
  AND f1.friend_id = 7

Se não, então eles são amigos de um amigo?
SELECT COUNT(*)
FROM friends f1
JOIN friends f2
  ON f2.member_id = f1.friend_id
WHERE f1.member_id = 1
  AND f2.friend_id = 7

Se não, então amigo de um amigo de um amigo?
SELECT COUNT(*)
FROM friends f1
JOIN friends f2
  ON f2.member_id = f1.friend_id
JOIN friends f3
  ON f3.member_id = f2.friend_id
WHERE f1.member_id = 1
  AND f3.friend_id = 7

E assim por diante...

A terceira consulta encontraria o caminho '1 a 2', '2 a 6' e '6 a 7', retornando a contagem de 1.

Cada consulta se torna mais cara (devido ao maior número de junções), então você pode querer limitar a pesquisa em algum momento. Uma coisa legal é que essa busca funciona das duas pontas em direção ao meio, que é uma simples otimização sugerida para buscas de caminho mais curto.

Veja como encontrar essas recomendações de amigos em comum para o membro 1:
SELECT f2.friend_id
FROM friends f1
JOIN friends f2
  ON f2.member_id = f1.friend_id
LEFT JOIN friends f3
  ON f3.member_id = f1.member_id
  AND f3.friend_id = f2.friend_id
WHERE f1.member_id = 1
  AND f2.friend_id <> f1.member_id // Not ourself
  AND f3.friend_id IS NULL // Not already a friend