【问题标题】:NamedQuery for most used tags最常用标签的 NamedQuery
【发布时间】:2016-07-11 04:05:38
【问题描述】:

假设我有以下 2 个类:

@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;
}

现在我想创建一个命名查询来选择最常用的标签。

所以这需要一个joincount和一个order by。但我似乎无法弄清楚这一点。

问题: 如何选择最常用的标签?

例如,如果以下文章具有以下标签:

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

输出

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

【问题讨论】:

  • 您想对所有标签进行分组并获得计数和降序排列吗?
  • @Nicholas 我不确定是否要将它们分组。我想按文章类实例中出现的次数降序排列它们。
  • 那里大概有一个连接表,因为没有一个 M-N 会有点没有意义
  • 顺便说一句:我知道你想要标签表中的唯一标签,但你应该在标签表中放置一个约束并有一个整数或长 id 否则性能会很差。

标签: java sql jpa jpql


【解决方案1】:

在这类问题上倒退。从 SQL 查询开始:

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;

那么 JPQL 应该或多或少地遵循这一点:

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"));
}); 

这给了我以下输出:

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

更新:如果你想要一个标签列表,只需将元组的第一个元素更改为标签。当然,如果你愿意,你可以忽略计数:

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());
}); 

并得到以下输出:

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

【讨论】:

  • 太棒了,但是如何有效地从中获取标签列表?
  • 但是我需要按名称查询所有标签,这将是低效的。
  • 是的,我的输出有点混乱。我想检索List&lt;Tag&gt;。我并不真正关心出现的次数,它只需要按它们排序。我不想听起来不感恩,但我希望它更高效,我不能再按名称 (Id) 查询所有标签。我希望你能这样改变它!
  • 查看更新以获得完整的可能性。你可以选择任何你想要的。
  • 你为什么不直接from Tag t order by size(t.articles) descsetMaxResults()
【解决方案2】:

你可以使用类似的东西来实现你想要的

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

这将为您带来按文章数量排序的标签列表。

【讨论】:

  • 我会使用desc 而不是asc.setMaxResults() 让最流行的标签首先出现
  • @SashaSalauyou 就是这样。 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-20
  • 2011-05-11
  • 1970-01-01
  • 2011-02-04
  • 2021-11-20
  • 1970-01-01
相关资源
最近更新 更多