最佳Hashtags JPA实体模型

时间:2018-07-10 11:55:30

标签: java mysql hibernate jpa

我需要为我的应用程序中的hashtag设计一个JPA实体模型,类似于Instagram,twitter和Stack Overflow。我的应用程序。以下是我们的应用程序使用的特定于架构的点

  • 标签应属于一个问题
  • 标签是特定于用户的。
  • 每个用户都可以使用相同的主题标签来标记他们的问题

目前,针对上述架构,我有两个JPA模型

适用于两种型号的公用表

表格:问题

列:ID,问题,描述等,

表:用户

列:ID,名称,角色,组等,

模型1

表格:question_hash_tags

列:id,question_id,user_id,hashtag_text

模型2

表:#标签

列:id,hastag_text

表:user_hashtags

列:user_id,hashtag_id,question_id

即使用户之间的主题标签相同,模型1也会有每一行。

模型2将具有唯一的井号标签行,并且使用user_hashtags在用户之间进行引用。

我希望这两个模型之外的模型更好,更标准。

注意:可以根据主题标签和用户搜索问题

2 个答案:

答案 0 :(得分:4)

我们这里有三个“事物”:用户,问题和标签。在您的示例中,我会避​​免使用模型#1,主要是因为它不灵活。当产品负责人以后决定为标签添加描述时,会发生什么?如果产品所有者下周希望用户仅从现有资源池中选择标签,会发生什么情况?虽然您的域要求不完整且不清楚,但是更灵活的解决方案允许在模型之上实现将来的功能,而无需进行重大重构。话虽如此,我绝对会认为Hashtag是其自己的独立实体。

在第二个模型中,USER_HASHTAGS表中表示的三级关系似乎假设用户和问题之间是可选的多对多关系。如果确实您的域要求许多用户可以编写相同的问题,那么我认为2号模型将满足您的需求。您的要求更有可能明确限制多个用户编写单个特定问题的能力。如果是这样,则应在模型中容纳此类约束。另外,如果用户决定用5个不同的标签标记问题,则在user_hashtags表中每个标签将在用户与问题之间建立一对多关系5次。一个简单的查询来显示用户提出的问题将涉及使用DISTINCT,这应立即引起有关设计的警钟。

假设用户和问题之间是一对多的关系,我将从“ USER_HASHTAGS”表中删除USER_ID,而是将USER_ID作为外键放入QUESTIONS表中。然后将您的USER_HASHTAGS表重命名为QUESTION_HASHTAGS。这使它既简单又高效,因为现在您只需查询单个表即可获取由特定USER_ID编写的问题,而无需加入并添加数据库需要过滤的许多重复知识。现在还支持以下可能性:用户选择不为其问题添加主题标签(无空白外键)。

注意:

有许多因素会影响数据库的物理设计-不仅是“选择”访问模式,而且甚至有可能影响每种访问模式的相对频率。数据库写入与读取之间的比率,可更新的内容以及与其他更新相关的频率等也可能影响最终构建表的方式。因此,没有“确定的”答案,仅是基于一些假设和问题中提供的有限信息的答案。

答案 1 :(得分:2)

标签已经是一种ID,因此不需要专用的表。您只需要questions表:

create table questions (
    id bigint not null constraint questions_pkey primary key,
    user_id bigint constraint fk_questions_users references users,
    question text not null;
)

和具有questions_hashtags字段索引的hashtag关系表:

create table questions_hashtags (
    question_id bigint not null fk_questions_hashtags_questions references questions,
    hashtag text not null,
    constraint uk_questions_hashtags unique (question_id, hashtag)
);

create index index_questions_hashtags_hashtag on questions_hashtags(hashtag);

(这是PostgreSQL的方言。)

这些表简单映射到single(!)实体(不考虑User实体):

@Entity
@Table(name = "questions")
public class Question {
    @Id
    @GeneratedValue
    private Long id;

    @Column(nullable = false)
    private String question;

    @ManyToOne(optional = false)
    private User user;

    @CollectionTable(name = "questions_hashtags", joinColumns = @JoinColumn(name = "question_id"))
    @Column(name = "hashtag")
    @ElementCollection(fetch = FetchType.EAGER)
    @BatchSize(size = 20)
    private Set<String> hashtags = new HashSet<>();

    public Question(User user, String question) {
        this.user = user;
        this.question = question;
    }

    private Set<String> extractHashtags() {
      // extract hashtags from question to Set...
    }

    @PrePersist
    @PreUpdate
    private void populateHashtags() {
        hashtags.clear();
        hashtags.addAll(extractHashtags());
    }

    // other stuff
}

这是一个非常方便的模型。要创建并保存带有主题标签的问题,您只需执行以下操作即可:

questionRepo.save(new Question(user, question));

要获取所有主题标签,可以使用questionRepo的以下查询方法:

@Query("select distinct h as hashtag from Question q join q.hashtags h")
List<String> getAllHashtags();

要查找与特定主题标签相关的所有问题,可以使用以下查询方法:

@Query("select q from Question q join q.hashtags h where h = ?1")
List<Question> getQuestionsByHashtag(String hashtag);

要通过几个标签查找问题,可以使用以下方法:

@Query("select q from Question q join q.hashtags h where h in (?1)")
List<Question> getQuestionsByHashtag(Set<String> hashtags);

要查找与给定标签相关的用户,可以使用以下方法:

@Query("select distinct u from Question q join q.user u join q.hashtags h where h in (?1)")
List<User> getUsersByHashtag(Set<String> hashtags);

请参阅我的主题标签用法的REST服务示例 sb-hashtag-usage-example

1) POST /users -创建新用户

{
    "name": "user1"
}

2) POST /questions -创建新问题

{
    "question": "How implement best JPA #entity #model for Hashtags?",
    "user": "/user/1"
}

3) GET /hashtags -获取所有主题标签

4) GET/questions/search/by_hashtag ?hashtag=%23model-通过一个主题标签获取问题

5) GET /questions/search/by_hashtags ?hashtags=%23entity,%23model-通过几个主题标签来提问

6) GET /users/search/by_hashtags ?hashtags=%23entity-通过多个主题标签吸引用户

(也可以使用PATCH,DELETE等其他方法。)