Redis Zadd данных весны с ключом типа Long не работает - PullRequest
0 голосов
/ 07 июля 2019

Я пытаюсь изучить 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");
    }
}

Спасибо за вашу помощь.

1 Ответ

0 голосов
/ 10 июля 2019

Я в основном справился с этим, используя Redisson клиента с их StringCodec

        DriverLocationEntity driverLocationEntity = new DriverLocationEntity();
        driverLocationEntity.setDriverId(messageEntity.getDriverId());
        driverLocationEntity.setPoint(new Point(messageEntity.getLongitude(), messageEntity.getLatitude()));
        driverLocationEntity.setUpdatedAt(new Date(now));
        driverLocationEntity.setId(UUID.randomUUID().toString());

        // add hash_id into geoset for distance calculations
        redissonClient.getGeo(GEO_SET_KEY_NAME, new StringCodec()).add(messageEntity.getLongitude(), messageEntity.getLatitude(), HASH_ID_PREFIX + driverLocationEntity.getId());
...