当前位置: 首页 > 面试题库 >

如何在JPA(Spring Data JPA)中实现简单的全文本搜索?

郁高韵
2023-03-14
问题内容

我正在使用JPA 2.1(将Hibernate 4作为实现)和Spring Data JPA 1.9.0。如何实现全文搜索?

我的情况如下。我有一个User实体,在UI上有一个表,其中显示了大多数用户属性,我希望用户在文本框中输入搜索词并搜索所有属性。

我看到2个选项可以做到这一点:

  1. 从数据库加载所有用户用户并使用Java过滤用户
  2. 写了许多JPQL查询ORsLIKE % :searchString %

选项1 的性能不好,但是写起来很不错。

选项2 是高性能的,因为在DB端执行但编写起来很麻烦。

现在我正在使用选项1,因为我需要将boolean转换为"yes"/"no"并且还需要一个配置文件枚举,我想在其中按字段描述而不是实际枚举值进行搜索。

在User实体中,我有一个方法,该方法返回要搜索的所有字段,并用空格分隔:

   public String getSearchString(){
      return StringUtils.join(
              Arrays.asList(
                      login, 
                      firstName, 
                      lastName, 
                      email, 
                      active ? "yes" : "no", 
                      profile.getDescription())
              , " ");
   }

我在一项服务中从DB加载所有用户,并通过此搜索字符串进行过滤:

   @Override
   public List<User> getUsers(final String searchText) {
      final List<User> users = getUsers();
      if(StringUtils.isBlank(searchText)){
         return users;
      }
      CollectionUtils.filter(users, new Predicate<User>() {
         @Override
         public boolean evaluate(User object) {
            return StringUtils.containsIgnoreCase(object.getSearchString(), searchText);
         }
      });
      return users;
   }

在JPQL的另一端,我最终遇到这样的查询,我认为这不是实现此功能的最好,最简单的方法。将布尔值转换为“是”和“否”也存在问题。

@Query("SELECT r FROM User r WHERE "
        + "r.firstname LIKE '%' || :searchString || '%' "
        + "OR r.lastname LIKE '%' || :searchString || '%' "
        + "OR r.login LIKE '%' || :searchString || '%' "
        + "OR r.profile.description LIKE '%' || :searchString || '%' "
        + "OR r.active LIKE '%' || :searchString || '%' "
        + "OR r.email LIKE '%' || :searchString || '%'")
List<User> selectUsers(@Param("searchString")String searchString, Pageable page);

有没有更好的解决方案来解决这个问题?


问题答案:

通过在每个持久存储上保存搜索字符串并更新到数据库来解决此问题。首先为searchString创建一列:

   @Column(name = "SEARCH_STRING", length = 1000)
   private String searchString;

存储很便宜,DB上的开销并不大。

然后保存更新并继续:

   @PreUpdate
   @PrePersist
   void updateSearchString() {
      final String fullSearchString = StringUtils.join(Arrays.asList(
              login,
              firstName,
              lastName,
              email,
              Boolean.TRUE.equals(active) ? "tak" : "nie",
              profile.getDescription()),
              " ");
      this.searchString = StringUtils.substring(fullSearchString, 0, 999);
   }

然后我可以使用以下常规JPQL查询LIKE

SELECT u FROM User u WHERE u.searchString LIKE '%' || :text || '%'

或使用示例查询:

  ExampleMatcher matcher = ExampleMatcher.matching().
          withMatcher("searchString", ExampleMatcher.GenericPropertyMatcher.of(ExampleMatcher.StringMatcher.CONTAINING).ignoreCase());


 类似资料:
  • Rails 实现全文搜索 ElasticSearch 初次使用小结,一起学习进步哈~ MongoDB + Rails 有什么好的全文搜索的办法吗? Sunspot 学习笔记 做了一个脚本,方便大家用 Sunpot 做中文全文索引 How search and index works (Ruby 语言描述)

  • 本文向大家介绍javascript实现简单搜索功能,包括了javascript实现简单搜索功能的使用技巧和注意事项,需要的朋友参考一下 本文实例为大家分享了javascript实现简单搜索功能的具体代码,供大家参考,具体内容如下 注意事项: A.search(B)可以在A中搜索B的位置,返回B出现的位置 A.split(B)将A以B划分为几部分,并返回数组,相当于分词操作 运行结果如下: 更多搜索

  • 问题内容: 现在,我有一个通过KeyReleased事件实现的搜索textField,当我开始键入“ Andrew”中的“ An”时,并在我准确键入(caseSensitive)我要输入的名称后,找不到/更新jTable。找。 因此,我想要从该站点实现Filtering方法,但是我遇到了很大的问题。在执行以下操作并删除了“旧的” KeyReleased事件之后,当我在文本字段“ txt_searc

  • 问题内容: 我正在创建一个允许用户提交报价的网站。如何创建返回最相关引号的(相对简单?)搜索? 例如,如果搜索词是“土耳其”,那么我将返回引号,其中单词“土耳其”出现两次,而引号则只出现一次。 (我会添加一些其他规则来帮助过滤掉不相关的结果,但是我主要担心的是。) 问题答案: 每个人都建议使用MySQL全文搜索,但是您应该注意一个巨大的警告。全文搜索引擎仅适用于MyISAM引擎(不适用于InnoD

  • 我得到一个错误: CORS策略阻止了在“https://api.example.com/graphql”从来源“chrome-search://local-ntp”获取:对飞行前请求的响应没有通过访问控制检查:请求的资源上没有“access-control-allog-orgin”标头。如果一个不透明的响应满足您的需要,请将请求的模式设置为“no-cors”,以便在禁用CORS的情况下获取资源。

  • 问题内容: 我第一次使用Postgresql,并且试图在我的网站中创建一个搜索引擎。我有这张桌子: 然后我为表的每个字段创建了一个索引(这是正确的方法吗?或者我可以为所有字段创建一个索引?): 现在,如果我想在每个索引中搜索一个单词,SQL查询是什么? 我尝试了这个,它的工作原理: 是否存在更好的方法来做到这一点?我可以搜索多个吗?我的一个朋友提出了一个解决方案,但这是针对MySQL数据库的: P