如何创建用于查找带有标签的电影的 Hibernate 搜索查询?

Posted

技术标签:

【中文标题】如何创建用于查找带有标签的电影的 Hibernate 搜索查询?【英文标题】:How to Create a Hibernate Search Query for finding Movies with Tags? 【发布时间】:2021-10-06 18:58:15 【问题描述】:

我有 3 个表,分别名为“Movies”、“Tags”、“MoviesAndTags”。

我的桌子:

movie table:
    +---------+---------+
    | Id      |  Name   |
    +---------+---------+
    | 1       | movie1   |
    | 2       | movie2   |
    | 3       | movie3   |
    +---------+---------+

tag table:
    +---------+---------+
    | Id      | Name    |
    +---------+---------+
    | 10      | tag1    |
    | 20      | tag2    |
    | 30      | tag3    |
    | 40      | tag4    |
    +---------+---------+

movieandtag table:
    +---------+---------+
    | MovieId  |  TagId  |
    +---------+---------+
    | 1       | 10      |
    | 1       | 20      |
    | 1       | 30      |
    | 1       | 40      |
    | 2       | 10      |
    | 2       | 20      |
    | 3       | 10      |
    | 3       | 40      |
    +---------+---------+

我想使用一堆标签查找任何电影,但所有标签都必须包含在列出的电影中。比如我想找一些有“tag1”和“tag2”的电影,那么申请结果就是“movie1”和“movie2”。

我尝试了这段代码来获得结果,但它不像我想要的那样工作。

    public List<MovieAndTag> findByTag(List<Tag> tags) 
        Session currentSession = entityManager.unwrap(Session.class);
        Query theQuery = currentSession.createQuery("from MovieAndTag where tag_id in :tag_id", MovieAndTag.class);
        theQuery.setParameterList("tag_id", tags.stream().map(Tag::getId).collect(Collectors.toList()));
        List<MovieAndTag> resultList = theQuery.getResultList();
        return (resultList.isEmpty()) ? new ArrayList<MovieAndTag>() : resultList;
    

有什么建议吗?谢谢。

编辑1:

这个原生 SQL 命令解决了我的问题,但我无法将其转换为休眠模式。我被困在这里,有人可以帮忙吗?

SELECT mt.id, mt.movie_id, mt.tag_id
FROM movie m
LEFT JOIN movie_and_tag mt
ON mt.movie_id=m.id
WHERE mt.tag_id IN (4, 7)
GROUP BY m.id
HAVING COUNT(*) = 2

4 和 7 个标签 ID 示例,以及 2 个 ID 大小。

【问题讨论】:

所以您正在寻找标签的and,而不是or,对吧? 我不知道哪个对解决我的问题有好处或有用。 【参考方案1】:

如果你想加入两个表movietag,我建议使用@JoinedTable注解。如果您像这样在 Movie 类中定义连接表:

 @ManyToMany
    @JoinTable(
            name = "movieandtag",
            joinColumns = @JoinColumn(name = "movie_id"),
            inverseJoinColumns = @JoinColumn(name = "tag_id"))
    private Set<Tag> tags;

您可以在 Tag 类中设置双向电影引用(这不是强制性的),如下所示():

    @ManyToMany(mappedBy = "tags")
    private Set<Movie> movies;

要检索结果列表,只需连接两个表即可;

        List<Tag> tags = new ArrayList<>(); // initialize here
        CriteriaBuilder builder = entityManager.getCriteriaBuilder();
        CriteriaQuery<Movie> criteriaQuery = builder.createQuery(Movie.class);
        Root<Movie> movieRoot = criteriaQuery.from(Movie.class);
        movieRoot.alias("movies"); // gives alias to movie table

        Predicate tagPredicate = movieRoot
                .join("tags").get("id")
                .in(tags
                        .stream()
                        .map(Tag::getId)
                        .collect(Collectors.toList())
                );

        criteriaQuery.where(tagPredicate).distinct(true);

        // generates typed query:
        // select distinct movies 
        // from Movie as movies inner join movies.tags as generatedAlias0
        // where generatedAlias0.id in (30, 40)
        TypedQuery<Movie> query = entityManager.createQuery(criteriaQuery);

        query.getResultList();

【讨论】:

以上是关于如何创建用于查找带有标签的电影的 Hibernate 搜索查询?的主要内容,如果未能解决你的问题,请参考以下文章

从带有搜索栏的表格单元格创建模式视图时,无法在导航栏中创建后退按钮

如何将 mp4 电影嵌入到我的 html 中?

存储来自多个查找表的用户配置文件数据。如何?

ggplot2用于带有两个相同刻度标签的条形图

如何在两个 TFS 标签之间查找变更集(用于发行说明/变更日志)

如何将对象添加到类中的静态向量