Spring Data REDIS - хеш-ключи со странными префиксами, а HSCAN неправильно возвращает результаты - PullRequest
1 голос
/ 03 мая 2019

Я использую пружинную загрузку (не имеет значения) с spring-data-redis: jar: 2.0.9, который использует салат для подключения к моему REDIS.Я использую хеш-структуру, которая содержит около 100 ключей.Под этими ключами я помещаю некоторые объекты, тип которых также не имеет значения:

private static final String HASH_KEY_NAME = "myspecialhashes:somekey";

@Autowired
private RedisTemplate<String, MyDto> myDtoRedisTemplate;

Теперь я просто помещаю список своих объектов в хеш, используя их идентификатор в качестве ключа:

myDtoRedisTemplate.opsForHash().put(HASH_KEY_NAME, dto.getId(), dto);

Это работает нормально, и извлечение всех элементов из хеша в порядке, а также получение только ключей

List allDtosRaw = myDtoRedisTemplate.opsForHash().values(HASH_KEY_NAME);

Также при перечислении ключей:

myDtoRedisTemplate.boundHashOps(HASH_KEY_NAME).keys()

это выглядит нормально, ивозвращаемый набор ключей начинается с:

(java.util.LinkedHashSet<E>) [fakeservicetest:dummy3:write, fakesingle:dummy:sub1:write, ....

Поскольку существует много ключей, я хотел иметь возможность фильтровать список объектов STARTING с токеном, используя HSCAN вместо получения всех ключей ифильтруя их в моем приложении Java.Итак, вот как я сделал HSCAN, чтобы получить все хеш-записи, начинающиеся с «fake»

List filteredDtosRaw = new LinkedList<>();
ScanOptions scanOptions = ScanOptions.scanOptions().match("fake*").count(10000).build();
Cursor cursor = myDtoRedisTemplate.boundHashOps(HASH_KEY_NAME).scan(scanOptions);
        cursor.forEachRemaining(filteredDtosRaw ::add);

К сожалению, это возвращает ноль результатов.Я пытался различными способами исправить это и получить некоторые результаты.В конце концов, я обратился к командной строке redis, чтобы посмотреть, что REDIS думает обо всех этих

redis-cli HSCAN "myspecialhashes:somekey" 0 MATCH "fake*" COUNT 1000

нулевых результатах.Следующим шагом было просмотреть все ключи в том, что есть, и посмотреть, что на самом деле находится в хэше

redis-cli HGETALL "myspecialhashes:somekey"

Результат выглядит так:

1) "0"
2)  1) "\xac\xed\x00\x05t\x00\x1cfakeservicetest:dummy3:write"
    2) "{\"@class\":\"
.....

Таким образом, кажется, что ключи содержатпрефикс, который является некоторыми символами Unicode.Вероятно, это связано с сериализацией строк (я проверил строки перед их отправкой в ​​REDIS с помощью отладчика, и они не содержат никаких невидимых символов в начале).Так что теперь у меня есть обходной путь, который работает: я могу искать «* fake *», и он работает как в REDIS CLI, так и в Spring Data Redis.И так как я хочу, чтобы только те, которые начинались с «подделки», я могу отфильтровать это в своем Java-приложении, используя String.startsWith.Но так как мне не нравятся обходные пути, я хотел бы знать, неправильно ли я использую данные redis, или есть некоторая несогласованность при сериализации строки для помещения в REDIS и для тех, которые используются в SCAN?

1 Ответ

0 голосов
/ 03 мая 2019

Хорошо, теперь я знаю. Я настроил сериализатор redis для строкового сериализатора, но похоже, что для хеш-ключей необходимо иметь сериализатор для хеш-ключей, устанавливаемых отдельно. Эти "странные символы Unicode" являются результатом JdkSerializer

@Bean
public RedisTemplate<String, MyDto> redisTemplateMyDto() {
    final RedisTemplate<String, MyDto> template = new RedisTemplate<String, MyDto>();
    template.setConnectionFactory(redisConnectionFactory);
    template.setKeySerializer(new StringRedisSerializer());
    template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
    template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
    return template;
}

Изменено на

@Bean
public RedisTemplate<String, MyDto> redisTemplateMyDto() {
    final RedisTemplate<String, MyDto> template = new RedisTemplate<String, MyDto>();
    template.setConnectionFactory(redisConnectionFactory);
    template.setHashKeySerializer(new StringRedisSerializer());
    template.setKeySerializer(new StringRedisSerializer());
    template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
    template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
    return template;
}
...