Mysql
 sql >> Database >  >> RDS >> Mysql

Interrogazione dei gradi di separazione

Ecco come eseguire la ricerca utilizzando una ricerca in ampiezza e nel percorso più breve, utilizzando JOIN. Non c'è magia in questo algoritmo, poiché stiamo usando MySQL per trovare la nostra risposta e non stiamo incorporando alcun algoritmo di ricerca di fantasia che utilizzi alcun tipo di euristica o ottimizzazione.

La mia tabella "amici" ha relazioni unidirezionali, quindi abbiamo duplicati nel senso che sono archiviati sia "da 1 a 2" che "da 2 a 1". Sto anche escludendo is_active poiché l'implementazione sarà ovvia:

Ecco i dati:

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

Abbiamo selezionato il membro 1 e stiamo chiedendo se 1 amico con 7, un amico di un amico, ecc. Un conteggio di 0 significa no e un conteggio di 1 significa sì.

SELECT COUNT(*)
FROM friends f1
WHERE f1.member_id = 1
  AND f1.friend_id = 7

Se no, allora sono amici di un amico?

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 no, allora amico di un amico di un amico?

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 così via...

La terza query troverebbe il percorso "da 1 a 2", "da 2 a 6" e "da 6 a 7", restituendo il conteggio di 1.

Ogni query diventa più costosa (a causa del maggior numero di join), quindi potresti voler limitare la ricerca a un certo punto. Una cosa interessante è che questa ricerca funziona da entrambe le estremità verso il centro, che è una semplice ottimizzazione suggerita per le ricerche sul percorso più breve.

Ecco come trovare i consigli di amici comuni per il 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