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