spring-boot - Springboot:使用多个特征搜索实体列表的最佳方法是什么
问题描述
我正在 spring-boot 中开发一个 Web 应用程序,用户可以在其中使用搜索字段搜索用户。将根据用户名、名字和姓氏来查询正在搜索的用户(取决于输入字段中输入的值)。这是我的用户模型:
@Component
@Entity
@Table(name = "Users")
public class User extends DefaultEntity {
@Column(name = "FirstName")
@NotNull(message = "Enter a FirstName")
private String firstName;
@Column(name = "LastName")
@NotBlank(message = "Enter a LastName")
private String lastName;
@Column(unique = true,name = "UserName")
@NotBlank(message = "Enter a UserName")
private String userName;
@Column(unique = true, name = "Email")
@NotBlank(message = "Please enter an Email address")
@Email(message = "Enter a valid Email")
private String email;
@Column(name = "Password")
@NotBlank(message = "Enter a Password")
private String password;
@Enumerated(EnumType.STRING)
@Column(name = "Gender")
private Gender gender;
@Column(name = "Address")
@NotBlank(message = "Please enter your Home Address")
private String address;
@Column(name = "Country")
@NotBlank(message = "Please enter your Country")
private String country;
@Column(name = "Picture")
private String picture;
@Column(unique = true, name = "PhoneNumber") //make this accept only numbers
private String phoneNumber;
@Column(name = "Bio")
private String bio;
@Enumerated(EnumType.STRING)
@Column(name = "OnlineStatus")
private OnlineStatus onlineStatus;
@Enumerated(EnumType.STRING)
@Column(name = "UserType")
private UserType userType;
@Column(name = "Money")
private double money;
//@MapsId()
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumn(name = "playerstats")
private PlayerStats playerStats;
//columnDefinition = "tinyint default false"
@Column(name = "locked",columnDefinition = "BOOL default false")
private Boolean locked;
@Transient
private MultipartFile file;
public String getFirstName() {
return firstName;
}
public User setFirstName(String firstName) {
this.firstName = firstName;
return this;
}
public String getLastName() {
return lastName;
}
public User setLastName(String lastName) {
this.lastName = lastName;
return this;
}
public String getUserName() {
return userName;
}
public User setUserName(String userName) {
this.userName = userName;
return this;
}
public String getEmail() {
return email;
}
public User setEmail(String email) {
this.email = email;
return this;
}
public String getPassword() {
return password;
}
public User setPassword(String password) {
this.password = password;
return this;
}
public Enum.Gender getGender() {
return gender;
}
public User setGender(Enum.Gender gender) {
this.gender = gender;
return this;
}
public String getAddress() {
return address;
}
public User setAddress(String address) {
this.address = address;
return this;
}
public String getCountry() {
return country;
}
public User setCountry(String country) {
this.country = country;
return this;
}
public String getPicture() {
return picture;
}
public User setPicture(String picture) {
this.picture = picture;
return this;
}
public String getBio() {
return bio;
}
public User setBio(String bio) {
this.bio = bio;
return this;
}
public Enum.OnlineStatus getOnlineStatus() {
return onlineStatus;
}
public User setOnlineStatus(Enum.OnlineStatus onlineStatus) {
this.onlineStatus = onlineStatus;
return this;
}
public Enum.UserType getUserType() {
return userType;
}
public User setUserType(Enum.UserType userType) {
this.userType = userType;
return this;
}
public double getMoney() {
return money;
}
public User setMoney(double money) {
this.money = money;
return this;
}
public String getPhoneNumber() {
return phoneNumber;
}
public User setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
return this;
}
public MultipartFile getFile() {
return file;
}
public User setFile(MultipartFile file) {
this.file = file;
return this;
}
public PlayerStats getPlayerStats() {
return playerStats;
}
public User setPlayerStats(PlayerStats playerStats) {
this.playerStats = playerStats;
return this;
}
public Boolean getLocked() {
return locked;
}
public void setLocked(Boolean locked) {
this.locked = locked;
}
}
这是我在 UserRepository 中查询用户模型的方法:
@Repository
public interface UserRepository extends JpaRepository<User,Long> {
Page<User> findUsersByUserNameContainingOrFirstNameContainingOrLastNameContaining(String UserName, String FirstName, String LastName, Pageable pageable);
}
我的问题:有没有更好的方法或更有效的方法来实现查询用户实体?
解决方案
如评论中所述,您正在寻找的是模糊搜索。这不是您可以在数据库中轻松完成的事情,但是您可以使用单独的搜索引擎:
- Apache Solr(基于 Apache Lucene 的平台)
- 弹性搜索
- Hibernate Search(Hibernate 与 Apache Lucene 集成)
- ...
使用此类解决方案时,您还必须将实体索引到搜索引擎中。Spring Data 可以为您提供帮助,因为还有一个 Solr 库。
首先,您需要一个新类来表示您的实体在 Solr 中的外观。请注意,如果您有嵌套关系,您想要“展平”所有内容:
@Document
public class UserDocument {
@Id
@Indexed("id")
private String id;
@Indexed("firstName")
private String firstName;
@Indexed("lastName")
private String lastName;
@Indexed("userName")
private String userName;
// ...
}
之后,您可以像使用 Spring Data 一样编写存储库:
public interface UserDocumentRepository extends SolrCrudRepository<UserDocument, String> {
@Query("userName:?0 OR firstName:?0 OR lastName:?0")
List<UserDocument> findAll(String searchTerm);
}
之后,您可以执行以下操作:
public User create(User input) {
// Create user in database
documentRepository.save(new UserDocument(input.getFirstName(), input.getLastName(), input.getUserName());
}
您还可以使用存储库查询模糊搜索:
documentRepository.findAll("vickz~3");
这将使用我刚刚编写的查询,并将查找包含 vickz 的名字、姓氏或用户名。~3
末尾是一种特殊语法,表示名称可以与我刚刚使用的名称不同 3 个字符(= 编辑距离)。
但是,这将返回UserDocument
Solr 实体。如果要获取实体,还必须查找它们,这可以通过它们的用户名来完成:
List<String> usernames = documentRepository
.findAll("vickz~3")
.stream()
.map(UserDocument::getUserName)
.collect(Collectors.toList());
repository.findByUsername(usernames); // Look in database for users matching those usernames
推荐阅读
- html - 下载带有html超链接的excel
- apache-nifi - Apache NiFi 漏斗与同一处理器的多个连接
- python - 将配色方案标签更改为对数刻度而不更改 matplotlib 中的轴
- c++ - 检查 istream 中是否有待处理数据的简单方法
- google-cloud-platform - 您如何开始在非技术型公司中使用云?
- c++ - C++20 在 string/u8string 和 string_view/u8string_view 之间转换
- python - Unpickling 类会引发属性错误
- go - 编辑 Google 日历“发件人”和“组织者”
- javascript - Angular Dragula:拖放后如何在保存按钮上获取更新排序列表
- html - 从前端到后端的日期时间本地发送时间自动更改,并减去 2 小时