Redis hash, tek bir anahtar altında alan ve değer çiftlerini tutan bir kayıt tipidir. Bir kullanıcıyı, ürünü ya da oturumu tek anahtarda saklamak için HSET ile alanları yazar, HGET ile tek alanı, HMGET ile birkaç alanı, HGETALL ile hepsini okursunuz. HINCRBY sayesinde aynı hash bir sayaç grubu olarak da çalışır. Nesneyi JSON metni olarak tek bir string'e gömmek yerine hash kullanmak, tek bir alanı güncellemek için bütün nesneyi okuyup yeniden yazma zorunluluğunu ortadan kaldırır.

Bu yazıda hash komutlarını resmî Redis belgelerindeki örneklerle ele alıyoruz: alan yazma ve okuma, sayaçlar, alan silme ve varlık kontrolü, rastgele alan seçimi, performans ve sınırlar, nesne modelleme önerileri ve Redis 8.10 ile gelen compact hash kodlaması ile HIMPORT. Alan bazında süre (TTL) vermek ayrı bir konu olduğu için hash alan süresi yazısında anlatılıyor. Redis'e genel bakış için Redis nedir, nasıl kullanılır, serinin tamamı için Redis öğrenme rehberi sayfasına bakabilirsiniz.

HSET ve HGET ile ilk hash

HSET ve HGET ile ilk hash

HSET bir veya daha fazla alan ve değer çiftini yazar. Anahtar yoksa yeni bir hash oluşturur; alan zaten varsa değerini üzerine yazar. Dönüş değeri, yazılan alanlardan kaç tanesinin yeni eklendiğidir; var olan bir alanı güncellemek bu sayıyı artırmaz. Belgelerdeki bisiklet örneği dört alanı tek komutla yazar:

text
> HSET bike:1 model Deimos brand Ergonom type 'Enduro bikes' price 4972
(integer) 4
> HGET bike:1 model
"Deimos"
> HGET bike:1 price
"4972"
> HGETALL bike:1
1) "model"
2) "Deimos"
3) "brand"
4) "Ergonom"
5) "type"
6) "Enduro bikes"
7) "price"
8) "4972"

Burada iki noktaya dikkat edin. Birincisi, price alanına sayı yazdığımız halde HGET onu "4972" olarak, yani string olarak döndürür. Hash değerleri her zaman string'dir; Redis yalnızca artırma komutlarında onları sayı gibi yorumlar. İkincisi, HGETALL yanıtında her alan adının hemen ardından değeri gelir; bu yüzden yanıtın uzunluğu alan sayısının iki katıdır. RESP3 protokolünde aynı komut bir map yanıtı döndürür ve çoğu istemci kütüphanesi bunu doğrudan sözlük ya da nesneye çevirir.

HGET alan yoksa ya da anahtar hiç yoksa nil döndürür. Var olmayan anahtarlar boş hash gibi ele alındığı için bu durumda hata almazsınız; bu, okuma kodunu basitleştirir ama yazım hatası yapılmış bir anahtar adını da sessizce gizleyebilir.

HMGET ile birkaç alanı tek seferde okumak

Bir nesnenin yalnızca birkaç alanına ihtiyacınız varsa HGETALL yerine HMGET kullanın. Komut istediğiniz sırada bir dizi döndürür ve bulunamayan her alan için nil koyar:

text
> HMGET bike:1 model price no-such-field
1) "Deimos"
2) "4972"
3) (nil)

Yanıt sırası istek sırasıyla aynı olduğu için istemci tarafında alan adını değerle eşleştirmek kolaydır. Anahtar hiç yoksa HMGET hata vermez, istenen alan sayısı kadar nil döndürür.

HINCRBY ve HINCRBYFLOAT ile sayaçlar

Hash alanları sayaç olarak kullanılabilir. HINCRBY alandaki tamsayıyı verdiğiniz miktar kadar artırır ve yeni değeri döndürür. Miktar işaretli olduğu için negatif değerle azaltma da yapılır. Alan yoksa önce 0 kabul edilir, anahtar yoksa yeni hash oluşturulur. Desteklenen aralık 64 bit işaretli tamsayılarla sınırlıdır.

text
> HINCRBY bike:1 price 100
(integer) 5072
> HINCRBY bike:1 price -100
(integer) 4972

Belgelerdeki daha pratik örnekte bir bisikletin kaç kez sürüldüğü, kaç kez kaza yaptığı ve kaç sahip değiştirdiği aynı hash içinde ayrı sayaçlarla tutulur. Önceden hiçbir alan yazmanız gerekmez:

text
> HINCRBY bike:1:stats rides 1
(integer) 1
> HINCRBY bike:1:stats rides 1
(integer) 2
> HINCRBY bike:1:stats rides 1
(integer) 3
> HINCRBY bike:1:stats crashes 1
(integer) 1
> HINCRBY bike:1:stats owners 1
(integer) 1
> HGET bike:1:stats rides
"3"
> HMGET bike:1:stats owners crashes
1) "1"
2) "1"

Bu desen, her sayaç için ayrı bir string anahtar açmaya göre daha düzenlidir: ilgili sayaçlar tek anahtar altında toplanır, hepsini tek komutla okuyabilir ya da tek DEL ile silebilirsiniz. Her artırma işlemi atomiktir; aynı alanı aynı anda artıran iki istemci birbirinin artışını ezmez.

Ondalıklı sayılar için HINCRBYFLOAT vardır. Davranışı string tipindeki INCRBYFLOAT ile aynıdır ve yanıtı bulk string olarak döner. Belgeler, komutun replikasyon bağlantısına ve AOF dosyasına bir HSET olarak yazıldığını belirtir; böylece farklı makinelerdeki kayan nokta hesaplama farkları tutarsızlığa yol açmaz.

text
> HSET mykey field 10.50
(integer) 1
> HINCRBYFLOAT mykey field 0.1
"10.6"
> HINCRBYFLOAT mykey field -5
"5.6"
> HSET mykey field 5.0e3
(integer) 0
> HINCRBYFLOAT mykey field 2.0e2
"5200"

Son iki satıra dikkat edin: 5.0e3 gibi üslü yazım kabul edilir ve sonuç "5200" olarak döner. Ayrıca var olan bir alanı HSET ile güncellemek (integer) 0 döndürür, çünkü yeni alan eklenmemiştir. Alandaki değer ya da verdiğiniz artış ondalıklı sayı olarak okunamazsa HINCRBYFLOAT hata verir; bu tür sayı hatalarının genel açıklaması belgelerin Redis: ERR value is not an integer or out of range sayfasındadır.

Alan silme ve varlık kontrolü

HDEL bir veya daha fazla alanı siler ve gerçekten silinen alan sayısını döndürür; hash'te olmayan alanlar sayılmaz. Son alan da silinirse hash anahtarı otomatik olarak silinir. HEXISTS bir alanın var olup olmadığını 1 ya da 0 ile söyler.

text
> HSET myhash field1 "foo"
(integer) 1
> HDEL myhash field1
(integer) 1
> HDEL myhash field2
(integer) 0

Alan yalnızca yoksa yazılsın istiyorsanız HSETNX kullanın. Alan zaten varsa komut hiçbir şey yapmaz ve 0 döndürür; bu, varsayılan değer atamak ya da "ilk yazan kazanır" mantığı kurmak için uygundur.

text
> HSETNX myhash field "Hello"
(integer) 1
> HSETNX myhash field "World"
(integer) 0
> HGET myhash field
"Hello"

HSTRLEN bir alandaki değerin uzunluğunu döndürür; anahtar ya da alan yoksa sonuç 0'dır. Değeri çekmeden boyutunu öğrenmek için kullanışlıdır. Belgelerdeki örnekte HelloWorld için 10, 99 için 2, -256 için 4 döner; yani sayılar da string uzunluğuyla ölçülür.

Bütün alanlar: HKEYS, HVALS, HLEN ve HRANDFIELD

HKEYS yalnızca alan adlarını, HVALS yalnızca değerleri, HLEN alan sayısını döndürür. Anahtar yoksa ilk ikisi boş liste, HLEN ise 0 verir.

text
> HSET myhash field1 "Hello"
(integer) 1
> HSET myhash field2 "World"
(integer) 1
> HKEYS myhash
1) "field1"
2) "field2"
> HLEN myhash
(integer) 2

HRANDFIELD rastgele alan seçer. Yalnızca anahtarla çağrılırsa tek alan döner. Pozitif count ile birbirinden farklı alanlardan oluşan bir dizi gelir; count alan sayısından büyükse bütün hash döner ve yanıt sırası gerçekten rastgele değildir. Negatif count ile aynı alan birden çok kez gelebilir, ama tam olarak istenen sayıda eleman döner ve sıra gerçekten rastgeledir. WITHVALUES değerleri de ekler ve yalnızca count ile birlikte kullanılabilir. Belgelerdeki örneklerde rastgele sonuçlar gösterilmediği için burada da çıktı vermiyoruz; komutun dönüş biçimi yukarıda anlattığımız gibidir.

text
> HSET coin heads obverse tails reverse edge null
(integer) 3
> HRANDFIELD coin
> HRANDFIELD coin -5 WITHVALUES

Performans ve sınırlar

Performans ve sınırlar: HSET, HGET, HDEL, HINCRBY, HGETALL, HKEYS, HVALS, HSCAN

Hash komutlarının çoğu O(1)'dir. HKEYS, HVALS, HGETALL ve süreyle ilgili komutların çoğu ise alan sayısıyla orantılı, yani O(n) çalışır. Bir hash en fazla 4.294.967.295 (2^32 - 1) alan tutabilir; pratikte sınırı sunucunun belleği belirler. Belgeler ayrıca az sayıda ve küçük değerli alan içeren hash'lerin bellekte özel ve çok verimli bir biçimde kodlandığını belirtir.

KomutKarmaşıklıkNot
HSET, HGET, HDEL, HINCRBYO(1)Alan başına sabit iş
HGETALL, HKEYS, HVALSO(n)Büyük hash için dikkat
HSCANParça parçaBüyük hash'i adım adım dolaşır

Hash ile nesne modelleme

Hash ile nesne modelleme: Az sayıda düz alanlı nesne, İç içe nesne ve dizi, Alan bazında süre (TTL), İç yapısı uygulamaca yönetilen blob

Belgeler hash'i, iç içe olmayan ve az sayıda alandan oluşan nesneler için önerir. Tipik bir düzende her nesne için bir anahtar açılır ve anahtar adı nesne tipini ve kimliğini içerir: user:1, bike:1, bike:1:stats. Böylece aynı nesnenin sabit bilgileri ile sık değişen sayaçlarını ayrı hash'lerde tutabilirsiniz. Bu ayrımın pratik faydası da vardır: profil bilgilerini okuyan bir sayfa sayaç hash'ini hiç çekmez, sayaçları güncelleyen kod da profil alanlarına dokunmaz. Anahtar adlarında hangi ayırıcıyı ve hangi sırayı kullanacağınıza dair öneriler anahtar isimlendirme ve keyspace yazısında yer alıyor.

Hash değerleri düz string olduğu için iç içe yapıları doğrudan modelleyemezsiniz. Alt nesneler, diziler ya da yol ifadeleriyle sorgulama gerekiyorsa JSON tipi daha uygundur; belgeler JSON'un bellek ve işlem maliyetinin hash'ten yüksek olduğunu da not eder. Alan bazında süre gerekiyorsa hash tek seçenektir, çünkü belgelerin karşılaştırma sayfasına göre alan düzeyinde verimli erişim ve süre desteği yalnızca hash'te vardır. Hash ve JSON belgeleri Redis Search ile indekslenip sorgulanabilir.

İhtiyaçUygun tip
Az sayıda düz alanlı nesneHash
İç içe nesne ve diziJSON
Alan bazında süre (TTL)Hash
İç yapısı uygulamaca yönetilen blobString

Bu kararın ayrıntıları için Redis veri tipi seçimi, Redis JSON komutları ve Redis Search ile FT.CREATE yazılarına bakabilirsiniz.

Compact hash ve HIMPORT (Redis 8.10)

Redis 8.10 ile gelen compact hash, aynı alan adlarını paylaşan çok sayıda hash için bellek kullanımını azaltan bir iç kodlamadır; bu bölümdeki özellikler en az Redis 8.10 gerektirir. Örneğin her kullanıcı için name, email ve age alanlı bir hash tutuyorsanız, Redis bu ortak alan adı kümesini bir kez saklayıp her anahtarda yalnızca değerleri ve kümeye küçük bir referansı tutabilir. Kodlama iç ayrıntıdır: bütün hash komutları aynı anlamla ve aynı yanıtlarla çalışmaya devam eder.

Belgeler compact hash'in ne zaman işe yaradığını açıkça ayırır. Çok sayıda anahtar aynı ve büyük ölçüde sabit alan kümesini paylaşıyorsa kazanç büyür; okuma ve var olan alanın değerini güncelleme normal hash kadar hızlıdır. Alan adları sık değişiyorsa, her anahtarın alanları farklıysa ya da hash'ler çok büyükse uygun değildir. HSET ile yeni alan eklemek ya da HDEL ile alan silmek anahtarı ortak kümeden koparıp yeni bir kümeye bağlar. Bir hash bir kez compact olduktan sonra anahtar yaşadığı sürece normal hash'e geri dönmez.

Bu kodlamaya iki yoldan geçilir. Birincisi HIMPORT komut ailesidir: alan adlarını HIMPORT PREPARE ile bir kez tanımlar, sonra her anahtarı HIMPORT SET ile yalnızca değerleri göndererek oluşturursunuz.

text
> HIMPORT PREPARE user name email age
OK
> HIMPORT SET user:1 user Alice alice@example.com 34
OK
> HIMPORT SET user:2 user Bob bob@example.com 41
OK
> HIMPORT SET user:3 user Carol carol@example.com 29
OK
> HGETALL user:2
1) "age"
2) "41"
3) "name"
4) "Bob"
5) "email"
6) "bob@example.com"

Örnekteki HGETALL çıktısı alanları tanımladığınız sıradan farklı bir sırayla döndürüyor; belgeler bunun olabileceğini özellikle belirtir. Ayrıca HIMPORT SET var olan bir anahtarla birleştirme yapmaz, onu tamamen değiştirir. Tanımlanan alan kümesi (fieldset) yalnızca onu tanımlayan bağlantıya aittir; bağlantı kapandığında ya da RESET çağrıldığında silinir. Çok sayıda hash yüklerken komutları pipeline ile göndermeniz önerilir; ayrıntı için Redis pipelining yazısına bakın.

İkinci yol otomatik dönüştürmedir. hash-min-template-entries ve hash-max-template-entries ayarları, normal komutlarla yazılan hash'lerin bir sonraki yazmada compact hash'e çevrilmesini sağlar; RDB yüklenirken dönüştürme için de ayrı ayarlar vardır. Hepsinin varsayılanı 0, yani kapalıdır ve çalışırken CONFIG SET ile değiştirilebilir. Alan süresi kullanan bir hash, alan sayısı eşiği karşılasa bile dönüştürülmez. Canlı sunucuda ayar değiştirmeden önce CONFIG GET ve CONFIG SET yazısını okumanızı öneririz.

Sık yapılan hatalar

  • Değerin sayı olarak geleceğini sanmak: HGET her zaman string döndürür; istemci tarafında dönüştürmeyi siz yapmalısınız.
  • HSET dönüşünü yanlış okumak: Dönen sayı güncellenen değil, yeni eklenen alan sayısıdır. Var olan alanı değiştirmek 0 döndürür.
  • Büyük hash'te HGETALL: Bütün içerik tek yanıtta gelir; gerekirse HMGET ya da HSCAN kullanın.
  • Anahtar tipi çakışması: Aynı anahtarda string tutup sonra HSET çağırmak WRONGTYPE hatası verir.
  • Her anahtarda farklı alan adları ile compact hash beklemek: Ortak alan kümesi paylaşılmıyorsa kazanç olmaz, hatta az paylaşılan küme normal hash'ten fazla yer tutabilir.
  • Süreyi anahtara vermek: EXPIRE bütün hash'i siler. Tek alanın süresi için HEXPIRE gerekir.

Sık Sorulan Sorular

Bir hash'e kaç alan koyabilirim?

En fazla 4.294.967.295 alan. Ancak belgeler hash'i az sayıda alanlı nesneler için önerir; çok büyük hash'ler hem O(n) komutları yavaşlatır hem de compact hash kazancını azaltır.

Tek bir hash alanına süre verebilir miyim?

Evet, Redis 7.4 ile alan bazında süre geldi. HEXPIRE, HTTL, HPERSIST ve Redis 8.0 ile gelen HSETEX/HGETEX için hash alan süresi yazısına bakın.

HINCRBY ile HINCRBYFLOAT arasındaki fark nedir?

HINCRBY 64 bit işaretli tamsayılarla çalışır ve tamsayı yanıt döndürür. HINCRBYFLOAT ondalıklı sayılarla çalışır, sonucu string olarak döndürür ve replikasyona HSET olarak yazılır.

Compact hash için uygulama kodunu değiştirmem gerekir mi?

Zorunlu değil. Otomatik dönüştürme ayarlarıyla mevcut HSET kodunuz da kazanç sağlayabilir. HIMPORT ise toplu yükleme için ağ trafiğini de azaltır. Belgelere göre çoğu istemci kütüphanesi HIMPORT desteğini deneysel olarak işaretliyor.

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: Redis öğrenme rehberi · Hash alan süresi · Redis JSON · Redis Search · Bellek kullanımı · Redis nedir, nasıl kullanılır