Spring Redis:范围查询“大于”字段

问题描述

我正在使用 Redis 存储一些数据,然后查询它并使用最新信息更新它。

考虑一个例子:

我收到文件数据,其中包含有关文件和该文件的物理存储位置的信息。

  • 一个架子有多个架子,每个架子可以有多个文件
  • 每个文件都有一个版本字段,当对文件执行操作时,它会更新(递增)。

我打算如何存储?

  • 我需要根据“shelfID + rack ID”进行查询——获取所有文件
  • 我需要根据“shelfID + rack ID + version > XX”进行查询 -- 获取版本超过指定的所有文件

现在,可以在 Spring Data Redis获取属于架子和机架的所有文件。 我创建了 2 个 ID 的组合键,然后基于此键进行查询

  private <T> void save(String id,T entity) {
    redistemplate.opsForValue().set(id,entity);
  }

但是,我如何查询版本字段? 我将“版本”字段保留为 @Indexed,但 Spring 存储库查询不起作用。

@RedisHash("shelves")
public class ShelfEntity {

  @Indexed
  @Id
  private String id;

  @Indexed
  private String shelfId;

  @Indexed
  private String rackId;

  @Indexed
  private String fileId;

  @Indexed
  private Integer version;

  private String fileName;    

  // and other updatable fields
}         

存储库方法

List<ShefEntity> findAllByShelfIdAndRackIdAndVersionGreaterThan(String centerCd,String floorCd,int version);

以上,给出错误

java.lang.IllegalArgumentException: GREATER_THAN (1): [IsGreaterThan,GreaterThan]不支持 redis 查询派生

  • 问。如何根据版本大于查询
  • 问。甚至可以使用 Spring Data Redis 吗?
  • 问。如果可能,我应该如何对数据进行建模(采用何种数据结构),以便进行此类查询
  • 问。如果不使用Spring,如何使用redis-cli和数据结构在Redis中做到这一点?

可能是这样的:


我不确定如何在 Redis 中对此进行建模?


更新 2: 一个架子可以有 N 个机架。 一个机架可以有 N 个文件。 每个文件对象都有一个版本。 此版本已更新 (o -> 1 -> 2....)

我只想存储文件的最新版本。 所以,如果我们有 1 个文件对象 货架 ID - 1 机架 ID - 1 文件 ID - 1 版本 - 0 .... 在版本更新时...我们仍然应该有 1 个文件对象。 版本 - 1

我尝试在散列数据结构中将密钥保留为shelfId + rackId 的MD5 散列。 但无法查询版本。

我也尝试过使用 ZSet。

像这样保存:

  private void saveSet(List<ShelfEntity> shelfInfo) {
    for (ShelfEntity item : shelfInfo) {
      redistemplate.opsForZSet()
          .add(item.getId(),item,item.getVersion());
    }
  }

因此,版本成为分数。

但问题是我们无法更新集合的项目。 所以对于一个fileId,有多个版本。 当我查询时,我得到了重复项。

获取代码

Set<ShelfEntity> objects = (Set<ShelfEntity>) (Object) redistemplate.opsForZSet()
        .rangeByscore(generateMd5Hash("-",shelfId,rackId),startVersion,Double.MAX_VALUE);

现在,这是模仿版本的尝试> XX

解决方法

为每个 shelfIdrackId 组合创建 ZSET

使用两种方法在Redis中保存和更新记录

// this methods stores all shelf info in db
public void save(List<ShelfEntity> shelfInfo) {
    for (ShelfEntity item : shelfInfo) {
      redisTemplate.opsForZSet()
          .add(item.getId(),clonedItem,item.getVersion());
    }
}

使用update删除旧的插入新的,Redis不支持key update,因为它是一张表,所以你需要删除现有的并添加一条新记录

public void update(List<ShelfEntity> oldRecords,List<ShelfEntity> newRecords) {
    if (oldRecords.size() != newRecords.size()){
       throw new IlleagalArgumentException("old and new records must have same number of entries");
    }
    for (int i=0;i<oldRecords.size();i++) {
      ShelfEntity oldItem = oldRecords.get(i);
      ShelfEntity newItem = newRecords.get(i);
      redisTemplate.opsForZSet().remove(oldItem.getId(),oldItem); 
      redisTemplate.opsForZSet()
          .add(newItem.getId(),newItem,newItem.getVersion());
    }
}

使用分数从 ZSET 读取项目。

List<ShefEntity> findAllByShelfIdAndRackIdAndVersionGreaterThan(String shelfId,String rackId,int version){
    Set<TypedTuple<ShelfEntity>> objects = (Set<TypedTuple<ShelfEntity>>)  redisTemplate.opsForZSet()
        .rangeWithScores(generateMd5Hash("-",shelfId,rackId),new Double(version),Double.MAX_VALUE);


    List<ShelfEntity> shelfEntities = new ArrayList<>();
    for (TypedTuple<ShelfEntity> entry:  objects) {
      shelfEntities.add(entry.getValue().setVersion( entry.getScore().intValue()));
    }
    return shelfEntities;
  }