【问题标题】:Multi-Field Querying on Redis Using Redis Spring使用 Redis Spring 在 Redis 上进行多字段查询
【发布时间】:2020-05-10 01:59:04
【问题描述】:

这将是一个非常简单的问题,因为我是 Spring-Redis 的新手

我目前正在学习 Redis 数据库,并且正在优先开发一项功能,我不得不使用 Redis 来实现此功能。 在下面的挑战/查询中。

现在我们有一个如下的DataModel:

@RedisHash("Org_Work")
public class OrgWork {

   private @Id @Indexed UUID id;
   private @Indexed String CorpDetails;
   private @Indexed String ContractType;
   private @Indexed String ContractAssigned;
   private @Indexed String State;
   private @Indexed String Country; 

}
public interface OrgWorkRepository extends CrudRepository<HoopCalendar, String> {

List<OrgWork> findByCorpDetailsAndContractTypeAndStateAndCountry(String CorpDetails, String ContractType, String ContractAssigned, String State, String Country);

}

我们正在开发一个 API 来查询上述数据模型,前端将向我们发送 CorpDetails 、ContractType、ContractAssigned、State 和 Country 字段,我们必须根据 Redis 数据库查询这些并返回 DurationOfWork 对象。

在这种情况下,我的负载约为。每分钟 100000 次调用。

请让我知道这是否是正确的方法以及一些关于改进响应时间的建议。

***更新了查询

【问题讨论】:

  • 查询“CorpDetails ,ContractType, ContractAssigned, State and Country”是否只返回一个结果?我的意思是,我们可以将其视为复合主键吗?或者您的意思是查询这些字段的任意组合?
  • 我们希望查询有多个记录。 (查询在 OrdWorkRepository 接口中提到)

标签: java spring-boot redis response-time


【解决方案1】:

请参阅Spring Data Redis - 8.5. Secondary Indexes 和:

  • 8.6。按例查询
  • 8.10。查询和查询方法

注解@Indexed 指示Spring Data Redis (SDR) 创建一个二级索引作为set 来索引散列的字段。

这意味着当你插入数据时,SDR 会向 Redis 运行七个命令:

HMSET "OrgWork:19315449-cda2-4f5c-b696-9cb8018fa1f9" "_class" "OrgWork" 
    "id" "19315449-cda2-4f5c-b696-9cb8018fa1f9" 
    "CorpDetails" "CorpDetailsValueHere" "ContractType" "ContractTypeValueHere" 
    ... "Country" "Costa Rica"
SADD  "OrgWork" "19315449-cda2-4f5c-b696-9cb8018fa1f9"                           
SADD  "OrgWork:CorpDetails:CorpDetailsValueHere" "19315449-cda2-4f5c-b696-9cb8018fa1f9"
SADD  "OrgWork:ContractType:ContractTypeValueHere" "19315449-cda2-4f5c-b696-9cb8018fa1f9"
...
SADD  "OrgWork:Country:Costa Rica" "19315449-cda2-4f5c-b696-9cb8018fa1f9"

通过示例使用查询:

你想创建一个repository

interface OrgWorkRepository extends QueryByExampleExecutor<OrgWork> {
}

然后按照下面的示例服务实现查询:

class OrgWorkService {

  @Autowired OrgWorkRepository orgWorkRepository;

  List<OrgWork> findOrgWorks(OrgWork probe) {
    return orgWorkRepository.findAll(Example.of(probe));
  }
}

并用作:

OrgWork orgWorkExample = new OrgWork();                          
orgWorkExample.setCorpDetails("CorpDetailsValueHere"); 
orgWorkExample.setContractType("ContractTypeValueHere");
...
List<OrgWork> results = orgWorkService.findOrgWorks(orgWorkExample);

在幕后,SDR 将使用 SINTERHGETALL 的组合将其转换为 Redis 命令以获取您的数据:

SINTER   …:CorpDetails:CorpDetailsValueHere   …:ContractType:ContractTypeValueHere   ...
HGETALL "OrgWork:d70091b5-0b9a-4c0a-9551-519e61bc9ef3" 
HGETALL ...

这是一个两步过程:

  1. 获取二级索引交集中包含的键,使用SINTER
  2. 使用HGETALL单独获取返回的每个键

假设您拥有优质的服务器、合理的数据集大小并且查询平均而言有些具体,那么 Redis 应该可以管理每分钟 100,000 次的工作负载。

SINTER 的时间复杂度为 O(N*M) 最坏情况,其中 N 是最小集合的基数,M 是集合的数量。您的查询中的每个维度都有一组。

HGETALL 是 O(N),其中 N 是散列的大小,在您的情况下为 7。

与往常一样,建议您进行一些基准测试以测试您是否获得了所需的性能并在需要时进行调整。

【讨论】:

  • 非常感谢@LeoMurillo 的解释。我还有一个问题..查询您在下面解释的方式有什么好处? List&lt;OrgWork&gt; findByCorpDetailsAndContractTypeAndStateAndCountry(String CorpDetails, String ContractType, String ContractAssigned, String State, String Country) 我在问题第二部分提到的方式?
  • 只有代码的味道,关于如何构建查询。我想你已经有了一个,想展示另一个。我发现 QBE 更面向对象,CrudRepository 上的自动派生有点长参数的味道;另外,如果重命名字段,则需要重命名函数,我看到那里存在可维护性风险,不确定在这种情况下是否会收到编译错误或警告或什么也没有。口味问题。在幕后,两者都应该到达发送到 Redis 的相同命令并表现出相同的性能
  • 对了,注意方法名少了AndContractAssigned,名字挺长的:-)
  • 是的,Leo,我什至想用你刚才所说的方式替换查询,因为它看起来更 OO。
  • 如果支持它对我来说是新闻,我认为不是 - 它可能值得另一个 SO 问题 :-)
猜你喜欢
  • 2021-04-25
  • 1970-01-01
  • 2018-09-27
  • 2018-08-07
  • 2020-05-10
  • 1970-01-01
  • 2011-07-20
  • 2015-12-18
  • 2017-01-23
相关资源
最近更新 更多