dot 快速的未来即将在您所在的城市举行活动。

加入我们参加 Redis 发布会

Redis OM Spring 的新功能?

Redis OM 项目进展顺利。经过六个月的努力,团队创建了一套可用的、稳定的 Redis Stack API。我们预计 Redis OM Spring 中的这 10 个新功能将简化和优化 Redis 支持的 Spring 应用程序。

2022 年 3 月 Redis Stack 的发布标志着 Redis 分发的分水岭时刻。Redis Stack 是第一个公开可用的 Redis 分发版,它集成了几个流行且经过实战检验的 Redis 模块。Redis Stack 包含一个 JSON 文档数据库、一个完整的搜索引擎、一个时间序列数据库、一个图数据库和概率数据结构。

Redis OM

Redis 对象映射 (OM) 库系列最初是为了为 Redis 支持的多个模块提供高级 API 而创建的。随着 Redis Stack 的发布,我们的工作重点已转移到 Stack 提供的模块和功能上。第一波功能集中在 JSON 文档数据库 (RedisJSON) 及其与搜索引擎 (RediSearch) 的集成上。

Redis OM Spring 中的最新功能

您可能已经知道,Redis OM Spring 是一个客户端库,可帮助您在 Spring 应用程序中对域进行建模并将数据持久化到 Redis。ROM(版本 0.6.0)的最新版本反映了我们对文档和搜索的关注(尽管我们在预览形式中加入了一些其他功能)。

那么,自 我们于 2021 年末宣布该项目 并发布了 Redis OM Spring 教程 以来,有哪些新功能呢?以下是亮点。

嵌套对象映射

Redis OM Spring 作为 Spring Data Redis 的扩展,以使用“持久化实体”为中心:“已添加注释的 Java 对象,以便可以将其序列化并存储在数据存储区中。Redis OM Spring 是首批提供 Java 实体的多模型持久性的 Spring 数据项目之一,例如 Redis 哈希和 Redis JSON 文档。在 GA 版本中,您现在可以使用 @Indexed 标记嵌套对象,并根据嵌套对象的属性进行搜索

@Document
public class Person {
  @Id private String id;
  //...
  @Indexed @NonNull private Address address;
}

通过这种映射,您可以例如在存储库中声明一个方法,以便在给定 Address 中的 City 的情况下搜索 Person

// Performing a tag search on city
Iterable<Person> findByAddress_City(String city);

或者,如果您想按 CityState 进行搜索,您可以声明类似这样的方法

// Performing a full-search on street
Iterable<Person> findByAddress_CityAndAddress_State(String city, String state);

“万能”搜索方法

如果您在实体中具有任何全文搜索方法,则只需声明名为“search”的方法,即可立即搜索所有字段

 // Performing a text search on all text fields:
 Iterable<Person> search(String text);

更精细地控制文本索引

IndexedSearchable 注释提供对底层搜索索引生成的完全控制

 @Searchable(sortable = true, nostem = true, weight = 20.0)
 private String buildingType;

能够将微调参数传递给底层 RediSearch 引擎,为更强大的查询打开了可能性。在示例中,buildingType 字段的定义包括 sortablenostemweight 参数。sortable 参数以牺牲一些额外内存为代价加快了按特定字段排序的速度;nostem 参数可以通过禁用字段词干提取来加快索引速度;最后,weight 参数是一个乘数,它会影响计算结果准确性时字段的重要性。

自定义 GSON 变换器集成

添加了几个实用程序类来控制对象的序列化方式。例如,假设您想将 SetStrings 存储为 JSON 文档中的逗号分隔字符串。您将使用带 Redis OM SetToStringAdapter 类的 @JsonAdapter GSON 注释

 @Indexed(separator = ",")
 @JsonAdapter(SetToStringAdapter.class)
 private Set<String> workType;

排序和分页查询

CrudRepository 之上,PagingAndSortingRepository 抽象添加了其他方法,以简化对实体的分页访问。RedisDocumentRepository 实现此接口,并允许将 Pageable 对象传递给任何声明的方法,以返回结果的“页面”。findAllByTitleStartingWith 方法检索标题以给定 prefix 开头的 MyDoc 实体的所有实例

Page<MyDoc> findAllByTitleStartingWith(String prefix, Pageable pageable);

此类查询可能会返回数百万个结果。在典型的 Web 应用程序中,我们可能更愿意显示一个最多包含数百个结果的页面。现在,使用页面请求,我们只需要求返回包含 100 条记录的第一页结果

Pageable pageRequest = PageRequest.of(0, 100);
Page<MyDoc> result = repository.findAllByTitleStartingWith("hel", pageRequest);

分页检索实体 ID

应用程序通常需要获取某种 ID 的列表:用户 ID、客户编号等。Redis OM Spring RedisDocumentRepository 提供了一个内置的 getIds 方法,该方法接受一个页面对象以有效地检索实体的 ID

Pageable pageRequest = PageRequest.of(0, 1);
Page<String> ids = repository.getIds(pageRequest);
ids = repository.getIds(pageRequest.next());

更新单个 JSON 字段,而不检索整个文档

在实际应用程序中,JSON 文档可能会变得非常大。检索整个文档可能会变成一项昂贵且耗时的操作。

假设您使用 RedisDocumentRepository 保存了一个对象。您现在可以使用 updateField 方法和实体元模型类有效地更新单个字段

Company redisInc = repository.save( //
   Company.of(
     "RedisInc", 
     2011, 
     new Point(-122.066540, 37.377690), 
     "stack@redis.com"
   )
 );
 repository.updateField(redisInc, Company$.NAME, "Redis");

审核字段

Redis OM Spring 提供了精密的支持,可以透明地跟踪实体发生变化的时间。您必须为实体类配备审核元数据,才能从该功能中受益。您可以使用 @CreatedAt 注释定义它们;用于存储创建实体的时间,以及 @LastModifiedDate;用于存储实体上次修改的时间

 @CreatedDate
 private Date createdDate;
 @LastModifiedDate
 private Date lastModifiedDate;

检索所有不同的集合值

如果您在实体中有一个索引的集合,例如

 @Indexed
 private Set<String> colors = new HashSet<String>();

您可以在存储库中声明一个类似这样的方法

Iterable<String> getAllColors();

它可以有效地返回所有文档中该集合的所有不同值。

自动完成

RediSearch 提供了 Suggestions/Autocomplete API。此 API 通过 @AutoComplete 和 @AutoCompletePayload 注释在 Redis OM Spring 中公开。

例如,假设您有一个实体表示 Airports,其中包含机场名称、代码和州

@Document
 public class Airport {
   @Id 
   private String id;

   @AutoComplete
   private String name;

   @AutoCompletePayload("name")
   private String code;

   @AutoCompletePayload("name")
   private String state;
}

您可以声明以“"autoComplete*”开头的,例如,用于“name”属性的方法,如下所示

public interface AirportsRepository extends RedisDocumentRepository<Airport, String> {
 List<Suggestion> autoCompleteName(String query);
 List<Suggestion> autoCompleteName(String query, AutoCompleteOptions options);
}

并根据查询字符串获取建议/自动完成的列表:

@Test
 public void testGetAutocompleteSuggestions() {
   List<Suggestion> suggestions = repository.autoCompleteName("col");
   List<String> suggestionsString = suggestions.stream().map(Suggestion::getString).collect(Collectors.toList());
   assertThat(suggestionsString).containsAll(List.of("Columbia", "Columbus", "Colorado Springs"));
}

此外,如果您传递一个“AutoCompleteOptions”,则可以控制搜索执行的方式(模糊或不模糊),并将任何标记有 @AutoCompletePayload 注释的字段包含在有效负载中

@Test
 public void testGetAutocompleteSuggestionsWithPayload() {
   String columbusPayload = "{\"code\":\"CMH\",\"state\":\"OH\"}";
   String columbiaPayload = "{\"code\":\"CAE\",\"state\":\"SC\"}";
   String coloradoSpringsPayload = "{\"code\":\"COS\",\"state\":\"CO\"}";

   List<Suggestion> suggestions = repository.autoCompleteName("col", AutoCompleteOptions.get().withPayload());

   List<String> suggestionsString = suggestions.stream().map(Suggestion::getString).collect(Collectors.toList());

   List<Object> payloads = suggestions.stream().map(Suggestion::getPayload).collect(Collectors.toList());

   assertThat(suggestionsString) //
     .containsAll(List.of("Columbia", "Columbus", "Colorado Springs"));

   assertThat(payloads) //
     .containsAll( //
       List.of(columbusPayload,columbiaPayload,coloradoSpringsPayload)
   );
 }

布隆过滤器

Redis Stack 的一项强大功能是 RedisBloom 模块,它提供了一组概率数据结构。布隆过滤器是一种概率数据结构,它提供了一种有效的方式来验证条目是否肯定不在集合中。此功能非常适合在昂贵的资源上搜索项目,尤其是在您拥有非常大的数据集合时很有用。

假设您有一个 SaaS 应用程序的用户列表,并且您已达到 FAANG 级别的用户,比如超过 1 亿。恭喜!在早期,检查电子邮件地址是否已在系统中使用非常容易,因为您只需查询一个包含数千条记录的数据集,而不是数亿条。但现在情况发生了变化。

RedisBloom 功能使此过程变得更容易。使用 @Bloom 注释为电子邮件属性创建和维护一个布隆过滤器

 @Bloom(name = "bf_person_email", capacity = 100000, errorRate = 0.001)
 String email;

在过滤器到位后,将“存在”查询添加到存储库中

 boolean existsByEmail(String email);

查询以线性时间运行,确保为您的客户提供一致且响应迅速的 UI。

我们的目标

这是一个旅程的开始,我们将努力使 Redis Stack 对跨多种语言和平台的开发人员有用且易于使用。此版本将在 JSON/Search 方面保持相当稳定;我们预计对当前 API 会进行一些小的更改。我们已经开始研究剩余的模块和 API,并对接下来将要发生的事情感到兴奋。