Я пытаюсь изучить Redis здесь, используя несколько примеров. У меня есть объект с именем DriverLocation
, где у него есть отметка времени с именем updatedAt
, которая представляет собой эпоху с представлением в миллисекундах. Дело в том, что я хочу иметь SortedSet, чтобы я мог выполнять zrangebyscore
запросов, чтобы отсортировать последние N записей по их отметке времени.
sortedset будет в основном иметь структуру timestamp --> hash_id
. Если я хочу добавить записи за последние 10 минут, я сделаю запрос zrangebyscore
, чтобы получить все hash_ids в отсортированном виде. А затем используйте hmget
с hash_ids для получения всех хеш-объектов.
Вот очень простая рабочая демонстрация на redis-cli, где вы можете предположить, что я использовал 3-значные числа вместо миллисекунд.
localhost:6379> zadd locations_0 213 hash_id_1
(integer) 1
localhost:6379> zadd locations_0 214 hash_id_2
(integer) 1
localhost:6379> zadd locations_0 215 hash_id_3
(integer) 1
localhost:6379> zrangebyscore locations_0 212 214
1) "hash_id_1"
2) "hash_id_2"
Все отлично работает на Redis Cli. Однако со стороны весны я не могу достичь того, ради чего я готов.
DriverLocation.java
@RedisHash("driverLocation")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class DriverLocationEntity {
@Id
private Long id;
@Indexed
private Long driverId;
@GeoIndexed
private Point point;
private Date updatedAt;
}
RedisConfiguration.java
@Configuration
@EnableRedisRepositories
public class RedisConfiguration {
@Value("${spring.redis.host}")
private String redisHost;
@Value("${spring.redis.port}")
private int redisPort;
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(redisHost, redisPort);
}
@Bean
public RedisTemplate<Object, Object> redisTemplate() {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory());
return template;
}
@Bean
public RedisAtomicLong redisAtomicLong() {
RedisAtomicLong redisAtomicLong = new RedisAtomicLong("DriverLocationIdCounter", redisConnectionFactory(), 0L);
return redisAtomicLong;
}
}
Controller.java
@RestController
@RequestMapping("/drivers")
@Slf4j
public class DriverLocationController {
@Autowired
private DriverLocationRepository driverLocationRepository;
@Autowired
private RedisTemplate<Object, Object> redisTemplate;
@Autowired
private RedisAtomicLong redisAtomicLong;
@Autowired
private ObjectMapper objectMapper;
@RequestMapping("/{id}")
public ResponseEntity<List<DriverLocationEntity>> getDriver(@PathVariable("id") Long driverId) {
long now = Instant.now().getEpochSecond();
Set<Object> ids = redisTemplate.opsForZSet().rangeByScore(
"locations_" + driverId,
Instant.ofEpochSecond(now).minusSeconds(300).toEpochMilli(),
Instant.ofEpochSecond(now).toEpochMilli());
List<Object> driverLocations = redisTemplate.opsForHash().multiGet("driverLocations", ids.stream().map(id -> (Long) id).collect(Collectors.toList()));
return ResponseEntity.status(HttpStatus.OK).body(driverLocations.stream().map(dLoc -> (DriverLocationEntity) dLoc).collect(Collectors.toList()));
}
@RequestMapping(value = "/{id}", method = RequestMethod.POST)
public ResponseEntity<String> addDriverLocation(@RequestBody DriverLocationMessageEntity messageEntity,
@PathVariable("id") Long driverId) throws JsonProcessingException {
long now = Instant.now().toEpochMilli();
DriverLocationEntity driverLocationEntity = new DriverLocationEntity();
driverLocationEntity.setDriverId(driverId);
driverLocationEntity.setPoint(new Point(messageEntity.getLongitude(), messageEntity.getLatitude()));
driverLocationEntity.setUpdatedAt(new Date(now));
driverLocationEntity.setId(redisAtomicLong.getAndIncrement());
String strVal = objectMapper.writeValueAsString(driverLocationEntity);
// save driver location entity
driverLocationRepository.save(driverLocationEntity);
// save timestamp -> hash_id
redisTemplate.opsForZSet().add("locations_" + driverLocationEntity.getDriverId(), now, driverLocationEntity.getId());
return ResponseEntity.status(HttpStatus.OK).body("done");
}
}
Спасибо за вашу помощь.