2016-03-23 10 views
0

Lassen Sie uns sagen, dass ich die folgenden 2 Klassen haben:NamedQuery für die meisten verwendete Tags

@Entity 
class Article { 

    @Id 
    int id; 

    @ManyToMany(mappedBy="articles") 
    List<Tag> tags; 
} 

@Entity 
@NamedQueries({ 
    @NamedQuery(name = "Tag.trends", query = "SELECT t FROM Tag t") // Some magic stuff here.. 
}) 
class Tag { 

    @Id 
    String name; 

    @ManyToMany 
    List<Articles> articles; 
} 

Jetzt habe ich eine benannte Abfrage erstellen möchten, die am häufigsten verwendeten Tags auswählen.

So wird dies erfordern eine beitreten, Zählung und eine um von. Aber ich kann das nicht herausfinden.

Frage: Wie kann ich die am häufigsten verwendeten Tags auswählen?

Zum Beispiel, wenn die folgenden Artikel mit den folgenden Tags haben:

Article: Tags 
0: A, B 
1: A 
2: C 
3: A, C 

Ausgabe

A // 3 times 
C // 2 times 
B // 1 time 
+0

Sie möchten alle Tags gruppieren und absteigend zählen und sortieren? –

+0

@Nicholas Ich bin mir nicht sicher, ob ich sie gruppieren möchte. Ich möchte sie absteigend nach der Anzahl der Vorkommen in den Artikelklasseninstanzen ordnen. – Tim

+0

da ist vermutlich irgendwo eine Join - Tabelle drin, weil ein MN ohne ein wenig sinnlos wäre –

Antwort

2

können Sie erreichen, was Sie so etwas wie

SELECT t FROM Tag t ORDER BY SIZE(t.articles) ASC 

wollen mit Das wäre bringen Sie die Liste der Tags nach Anzahl der Artikel sortiert.

+1

abgerufen haben. Ich würde 'desc' anstelle von' asc' und '.setMaxResults()' to verwenden Lassen Sie die beliebtesten Tags zuerst erscheinen –

+0

@SashaSalauyou Das ist es. :) – Desorder

1

Arbeiten Sie sich rückwärts auf diese Art von Problemen. Beginnen Sie mit der SQL-Abfrage:

select 
    count(t.name), t.name 
from article a 
    join article_tags ats 
    join tag t 
where 
    a.id=ats.article_id 
    and ats.tag_id = t.id 
group by 
    t.name 
order by 
    count(t.name) 
desc; 

Dann wird die JPQL sollte mehr oder weniger folgen aus, dass:

List<Tuple> t = em.createQuery("select t.name as name, count(t.name) as count from Article a join a.tags t group by (t.name) order by count(t.name) desc", Tuple.class).getResultList(); 
t.stream().forEach((tp)-> { 
    System.out.println("Count of " + tp.get("name") + " = " + tp.get("count")); 
}); 

Das gibt mir die folgende Ausgabe:

Hibernate: select tag2_.name as col_0_0_, count(tag2_.name) as col_1_0_ from Article article0_ inner join Tag_Article tags1_ on article0_.id=tags1_.articles_id inner join Tag tag2_ on tags1_.tags_id=tag2_.id group by tag2_.name order by count(tag2_.name) desc 
Count of A = 2 
Count of B = 1 
Count of C = 1 

UPDATE: Wenn Sie möchten, eine Liste von Tags, ändern Sie einfach das erste Element des Tupels als Tag. Und natürlich können Sie die Zählung ignorieren, wenn Sie wollen:

List<Tag> t = em.createQuery("select t from Article a join a.tags t group by (t.name) order by count(t.name) desc", Tag.class).getResultList(); 
t.stream().forEach((tag)-> { 
    System.out.println("Tag = " + tag.getName()); 
}); 

und erhalten die folgende Ausgabe:

Hibernate: select tag2_.id as id1_1_, tag2_.name as name2_1_ from Article article0_ inner join Tag_Article tags1_ on article0_.id=tags1_.articles_id inner join Tag tag2_ on tags1_.tags_id=tag2_.id group by tag2_.name order by count(tag2_.name) desc 
Tag = A 
Tag = B 
Tag = C 
+0

Super, aber wie bekomme ich die Liste der Tags effizient davon? – Tim

+0

Aber dann müsste ich alle Tags nach Namen abfragen, das wäre ineffizient. – Tim

+0

Ja, meine Ausgabe ist etwas verwirrend. Ich würde gerne eine "Liste " abrufen. Die Anzahl der Vorkommen interessiert mich nicht, sie müssen nur nach ihnen sortiert werden. Ich möchte nicht undankbar klingen, aber ich möchte, dass es performanter ist, ich kann nicht alle Tags wieder mit dem Namen (Id) abfragen. Ich hoffe, du kannst es auf diese Weise ändern! – Tim