sql >> Base de Datos >  >> RDS >> Mysql

MySQL / PHP:encuentre elementos similares / relacionados por etiqueta / taxonomía

Te preguntas sobre ¿Cómo calculo cuáles son las ciudades más cercanas? Por ejemplo. Si estuviera mirando la ciudad 1 (París), los resultados deberían ser:Londres (2), Nueva York (3) y según el conjunto de datos proporcionado, solo hay una cosa que relacionar, que son las etiquetas comunes entre las ciudades, por lo que las ciudades que comparten las etiquetas comunes serían las más cercanas a continuación, es la subconsulta que encuentra las ciudades (aparte de la que se proporciona a encontrar sus ciudades más cercanas) que comparte las etiquetas comunes

SELECT * FROM `cities`  WHERE id IN (
SELECT city_id FROM `cities_tags` WHERE tag_id IN (
SELECT tag_id FROM `cities_tags` WHERE city_id=1) AND city_id !=1 )

Trabajando

Supongo que ingresará una de las identificaciones o el nombre de la ciudad para encontrar la más cercana en mi caso, "París" tiene la identificación

 SELECT tag_id FROM `cities_tags` WHERE city_id=1

Encontrará todas las etiquetas de identificación que tiene París entonces

SELECT city_id FROM `cities_tags` WHERE tag_id IN (
    SELECT tag_id FROM `cities_tags` WHERE city_id=1) AND city_id !=1 )

Obtendrá todas las ciudades excepto París que tiene las mismas etiquetas que también tiene París

Aquí está tu Fiddle

Al leer sobre la similitud/índice de Jaccard Encontré algunas cosas para entender sobre lo que realmente son los términos, tomemos este ejemplo, tenemos dos conjuntos A y B

Ahora muévete hacia tu escenario

Aquí está la consulta hasta ahora que calcula el índice jaccard perfecto; puede ver el siguiente ejemplo de violín

SELECT a.*, 
( (CASE WHEN a.`intersect` =0 THEN a.`union` ELSE a.`intersect` END ) /a.`union`) AS jaccard_index 
 FROM (
SELECT q.* ,(q.sets + q.parisset) AS `union` , 
(q.sets - q.parisset) AS `intersect`
FROM (
SELECT cities.`id`, cities.`name` , GROUP_CONCAT(tag_id SEPARATOR ',') sets ,
(SELECT  GROUP_CONCAT(tag_id SEPARATOR ',')  FROM `cities_tags` WHERE city_id= 1)AS parisset

FROM `cities_tags` 
LEFT JOIN `cities` ON (cities_tags.`city_id` = cities.`id`)
GROUP BY city_id ) q
) a ORDER BY jaccard_index DESC 

En la consulta anterior, he derivado el conjunto de resultados a dos subselecciones para obtener mis alias calculados personalizados

Puede agregar el filtro en la consulta anterior para no calcular la similitud consigo mismo

SELECT a.*, 
( (CASE WHEN a.`intersect` =0 THEN a.`union` ELSE a.`intersect` END ) /a.`union`) AS jaccard_index 
 FROM (
SELECT q.* ,(q.sets + q.parisset) AS `union` , 
(q.sets - q.parisset) AS `intersect`
FROM (
SELECT cities.`id`, cities.`name` , GROUP_CONCAT(tag_id SEPARATOR ',') sets ,
(SELECT  GROUP_CONCAT(tag_id SEPARATOR ',')  FROM `cities_tags` WHERE city_id= 1)AS parisset

FROM `cities_tags` 
LEFT JOIN `cities` ON (cities_tags.`city_id` = cities.`id`) WHERE  cities.`id` !=1
GROUP BY city_id ) q
) a ORDER BY jaccard_index DESC

Entonces, el resultado muestra que París está estrechamente relacionada con Londres y luego con Nueva York

Fiddle de similitud de Jaccard