J'écris actuellement une application qui permet de stocker des images, puis de tagler ces images. J'utilise Python et le PEEWEE ORM (http://charlesleifer.com/docs/peewee/), qui ressemble beaucoup à l'ormes de Django.
Mon modèle de données ressemble à ceci (simplifié): P> < Pré> xxx pré>
Maintenant, je comprends de manière conceptuelle comment interroger sur toutes les images qui ont un ensemble donné de balises: p> Cependant, je veux aussi être capable de faire des recherches plus complexes. Spécifiquement, j'aimerais pouvoir spécifier une liste de "toutes les balises" - c'est-à-dire qu'une image doit avoir toutes les balises spécifiées à être renvoyées, ainsi qu'une liste de "toute" et une liste de "Aucun". < / p> EDIT: strong> J'aimerais clarifier cela un peu. Plus précisément, la requête ci-dessus est une "toutes les balises" -style. Il renvoie des images qui ont toutes les balises données. Je veux être capable de spécifier quelque chose comme: "Donnez-moi toutes les images qui ont les étiquettes (vertes, montagne), l'une des balises (arrière-plan, paysage) mais pas les étiquettes (numériques, dessin)". P> Maintenant, idéalement, j'aimerais que cela soit une requête SQL, car la pagination devient alors très facile avec la limite et le décalage. J'ai eu une implémentation de la mise en œuvre qui vous permet de tout charger dans des ensembles Python, puis utilisez les différents opérateurs d'intersection. Ce que je me demande, c'est s'il y a une méthode de faire tout cela à la fois? P> Aussi, pour les personnes intéressées, j'ai envoyé l'auteur de Peewee sur la manière de représenter la requête ci-dessus à l'aide de Peewee, et il a répondu avec la solution suivante: p> ou, alternativement, une version plus courte: p> Merci d'avance pour votre temps . p> p>
3 Réponses :
La requête suivante doit renvoyer toutes les images étiquetées avec les deux ('A' et 'B') et ('C' ou 'D' ou 'D') mais pas 'E' et 'F'
SELECT Image.key
FROM Image
INNER JOIN TagRelationship
ON Image.ID = TagRelationship.ImageID
INNER JOIN Tag tag1
ON TagRelationship.TagID = tag1.ID
INNER JOIN Tag tag2
ON TagRelationship.TagID = tag2.ID
WHERE tag1.tag
IN ( 'A' , 'B' )
AND tag2.tag NOT IN ('E', 'F')
GROUP BY Image.key
HAVING COUNT(*) = 2
UNION
SELECT Image.key
FROM Image
INNER JOIN TagRelationship
ON Image.ID = TagRelationship.ImageID
INNER JOIN Tag tag1
ON TagRelationship.TagID = tag1.ID
INNER JOIN Tag tag2
ON TagRelationship.TagID = tag2.ID
WHERE tag1.tag
IN ( 'C' , 'D' )
AND tag2.tag NOT IN ('E', 'F')
Si tag.tag code> est dans ('a', 'B') code>, il ne peut jamais être trouvé dans ('E', 'F') code>. Les deux pas dans code> les conditions ont l'air redondant dans votre requête particulière.
S'il veut plus de 2 tags, vous devrez faire une autre jointure pour TAG3. Cela va rapidement sortir de la main et très lent s'il veut de nombreuses tags.
Je pense que cette requête ne retournera aucun résultat. Tag1 == Tag2 est possible car Tag1! = Tag2 n'est pas appliqué. Donc, vous pourriez avoir une situation où vous obtenez image. Valeur 1 avec des balises A, B, C, D et PAS E, F. Mais vous obtiendrez TAG1 = A, TAG2 = A, ainsi que A, B A, C A, D B, A et toutes les autres permutations. Donc, le comte finira par être 8
Si une image a des étiquettes A, E, F et ID 1. Vous obtiendrez des rangées de 1AA, 1AA, 1Ae, 1ea, 1f, 1EF, 1EF, 1FE, 1FE et le comte (*) sera 2 parce que 1AA et 1AA être accepté.
La moitié supérieure obtient les mots qui correspondent aux balises obligatoires. La moitié inférieure fait les étiquettes où au moins 1 doivent être présents. La requête inférieure n'a pas de groupe par parce que je veux savoir si une image apparaît deux fois. Si c'est le cas, il a à la fois de l'arrière-plan et du paysage. La commande par compte (*) fera des photos avec des balises d'arrière-plan et de paysage à apparaître en haut. Si vert, montagne, paysage de fond sera le plus pertinent. Puis des images vertes, montagne, fond ou paysage.
SELECT Image.key, count(*) AS 'relevance'
FROM
(SELECT Image.key
FROM
--good image candidates
(SELECT Image.key
FROM Image
WHERE Image.key NOT IN
--Bad Images
(SELECT DISTINCT(Image.key) --Will reduce size of set, remove duplicates
FROM Image
INNER JOIN TagRelationship
ON Image.ID = TagRelationship.ImageID
INNER JOIN Tag
ON TagRelationship.TagID = Tag.ID
WHERE Tag.tag
IN ('digital', 'drawing' )))
INNER JOIN TagRelationship
ON Image.ID = TagRelationship.ImageID
INNER JOIN Tag
ON TagRelationship.TagID = Tag.ID
WHERE Tag.tag
IN ('green', 'mountain')
GROUP BY Image.key
HAVING COUNT(*) = count('green', 'mountain')
--we need green AND mountain
UNION ALL
--Get all images with one of the following 2 tags
SELECT *
FROM
(SELECT Image.key
FROM Image
INNER JOIN TagRelationship
ON Image.ID = TagRelationship.ImageID
INNER JOIN Tag
ON TagRelationship.TagID = Tag.ID
WHERE Tag.tag
IN ( 'background' , 'landscape' ))
)
GROUP BY Image.key
ORDER BY relevance DESC
SELECT Image.key
FROM Image
JOIN TagRelationship
ON Image.ID = TagRelationship.ImageID
JOIN Tag
ON TagRelationship.TagID = Tag.ID
GROUP BY Image.key
HAVING COUNT(CASE WHEN Tag.tag IN (mandatory tags ) THEN 1 END) = N /*the number of mandatory tags*/
AND COUNT(CASE WHEN Tag.tag IN (optional tags ) THEN 1 END) > 0
AND COUNT(CASE WHEN Tag.tag IN (prohibited tags) THEN 1 END) = 0
Est-ce que la déclaration d'avoir fonctionne correctement? Depuis que vous effectuez un groupe, vous n'aurez que 1 valeur pour la balise. Puisque c'est en somme, cela ira-t-il sur toutes les étiquettes et préfère le chèque? C'est beaucoup plus élégant que le mien si cela fonctionne.
Je pensais après avoir regroupé par un attribut, vous n'avez pas pu préformer l'analyse sur des lignes individuelles dans des groupes tels que Tag.tag In (Tags obligatoires)) = N. Je pourrais avoir à configurer des tables et tester cette requête pour moi-même. Je sais que des opérations globales telles que la somme fonctionneront, mais je ne sais pas si tag.tag in (tags obligatoires)) = n fonctionnera. Pas parce que je doute de toi, mais parce que je n'ai pas vu ni fait ça. C'est nouveau pour moi.
@JustinDanielson: Oui, vous pouvez avoir des expressions de référencement non-groupe par des colonnes à l'intérieur des fonctions globales, si c'est ce que vous demandez. Les résultats des expressions sont agrégés en conséquence. Vous savez que vous pouvez somme (valeur) code>, mais de la même manière que vous pouvez somme (valeur * qty) code> ou somme (valeur> 10) code >. Dans la saveur de MySQL de SQL, quelle est ma requête, dans code> peut être visualisé comme un autre opérateur, comme * code> ou + code>, seulement il renvoie Un booléen (qui est implicitement converti en un entier), comme << / code> ou = code> aussi.
Merci d'avoir expliqué cela avec des détails. Heureux que j'ai appris ça. Je vais me sauver beaucoup de temps en cas où je dois écrire une autre requête comme celle-ci. Découvrez le mien, je l'ai fait la dure. : [
Salut là-bas - merci pour ça! Ça marche vraiment bien. Juste un petit changement - le ">" dans la deuxième condition devrait être "> =", pour couvrir le cas que toutes les balises correspondent. Autre que cela, merci encore. J'ai marqué cela comme une réponse :)
Si je comprends bien, vous avez la réponse dont vous avez besoin dans Peewee Code, mais vous voulez savoir comment faire la même chose en SQL droit?
Pouvez-vous s'il vous plaît expliquer la pièce "Cependant, je veux aussi pouvoir faire des recherches plus complexes. Spécifiquement, je voudrais être capable de spécifier une liste de" toutes les balises "- c'est-à-dire une image doit avoir toutes les balises spécifiées Pour être retourné, avec une liste de "toute" et une liste de "Aucun". "
@naresh Spécifiquement, la requête ci-dessus est une "liste des balises" -style. Il renvoie des images qui ont toutes les balises données. Je veux pouvoir spécifier quelque chose comme: "Donnez-moi toutes les images qui ont les étiquettes (vertes, montagne), l'une des balises (arrière-plan, paysage) mais pas les étiquettes (numériques, dessin)". S'il vous plaît laissez-moi savoir si ce n'est pas clair.
Oh, cela clarifie beaucoup. Je pensais que la question ci-dessus était un peu ambiguë. C'est possible cependant. Est-ce que ça va bien s'il avait vert, montagne et paysage?
@JustinDanielson - Ouais, ça irait bien. N'importe quel "vert, montagne, paysage" ou "vert, montagne, fond", avec des autres étiquettes qui ne sont pas "numériques" ou "dessin" fonctionnent.
Ok donc tu veux ((A et B) ou (c et d)) mais pas (e et f)?
@JustinDanielson - Utilisation de la logique booléenne: (A et B) et (c ou d) et (non (e ou f)))
@JustinDanielson Pouvez-vous vérifier ma réponse mise à jour?