Получить случайное/любое значение из хэша Redis

У меня есть Redis-Hash с миллионами элементов, постоянно добавляющих новые. В php я запускаю бесконечный цикл, чтобы получить, обработать и удалить один элемент за другим. Таким образом, мне нужно получить ключ любого существующего элемента (желательно первого вставленного в хеш, FiFo)

while($redis->hlen()) {
    $key = ???
    // process $key    
}

Хотя я знаю команду RANDOMKEY и SRANDMEMBER, я не нашел способа получить ключ хеша. HGETALL и HKEYS из-за размера хеша тоже не вариант. Мне нужна последовательная обработка. Помощь приветствуется.


person Zsolt Szilagyi    schedule 20.06.2013    source источник
comment
Не могли бы вы сохранить ключи в хэше дополнительно в списке? Затем, когда вам нужно получить случайный элемент хеша, вы просто выталкиваете элемент из списка, а затем извлекаете этот элемент из хэша?   -  person Adam    schedule 20.06.2013


Ответы (1)


Нет никакой хитрости, чтобы получить доступ к случайному элементу (или первому, или последнему) данного хеш-объекта.

Если вам нужно перебрать хеш-объекты, у вас есть несколько возможностей:

  • первый — дополнить хэш другой структурой данных, которую вы можете нарезать (например, списком или zset). Если вы только добавляете элементы в хэш (и выполняете итерацию для их удаления), списка достаточно. Если вы можете добавлять/удалять/обновлять элементы (и выполнять итерацию для их удаления), то требуется zset (поставьте метку времени в качестве оценки). Оба списка zset можно нарезать (lrange, zrange, zrangebyscore), поэтому их легко перебирать по частям и поддерживать синхронизацию обеих структур данных.

  • второй — дополнить хеш другой структурой данных, поддерживающей всплывающие операции, такой как список или набор (lpop, rpop, spop). Вместо повторения хэш-объекта вы можете извлечь все объекты из вторичной структуры и соответствующим образом поддерживать хеш-объект. Опять же, обе структуры данных должны быть синхронизированы.

  • третий — разделить хеш-объект на множество частей. Это на самом деле эффективно использует память, потому что ваши ключи сохраняются только один раз, а Redis может использовать оптимизацию памяти ziplist.

Итак, вместо того, чтобы хранить ваш хэш как:

myobject -> { key1:xxxx, key2:yyyyy, key3:zzzz }

вы можете хранить:

myobject:<hashcode1> -> { key1:xxxx, key3:zzzz }
myobject:<hashcode2> -> { key2:yyyy }
...

Чтобы вычислить дополнительный хэш-код, вы можете применить к своим ключам любую хеш-функцию, которая предлагает хорошее распределение. В приведенном выше примере мы предполагаем, что key1 и key3 имеют одинаковое значение hashcode1, а key2 имеет значение hashcode2.

Вы можете найти больше информации об этом типе структур данных здесь:

Redis использует в 10 раз больше памяти, чем данных

Выходная кардинальность хеш-функции должна быть рассчитана таким образом, чтобы количество элементов на хеш-объект ограничивалось заданным значением. Например, если мы решим иметь 100 элементов для каждого хеш-объекта и нам нужно хранить 1 миллион элементов, нам потребуется кардинальность 10 КБ. Чтобы ограничить количество элементов, достаточно просто использовать операцию по модулю над общей хеш-функцией.

Преимущество в том, что он будет компактным в памяти (используется ziplist), и вы можете легко выполнять деструктивную итерацию по хэш-объектам, конвейеризируя hgetall+del для всех из них:

hgetall myobject:0
... at most 100 items will be returned, process them ...
del myobject:0
hgetall myobject:1
... at most 100 items will be returned, process them ...
del myobject:1
...

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

person Didier Spezia    schedule 20.06.2013