किसी भी वास्तविक समाधान को उन आवश्यकताओं को पूरा करने की आवश्यकता है, जो मूल प्रश्न में गायब हैं। मेरे पहले उत्तर ने एक छोटा डेटासेट मान लिया था, लेकिन यह दृष्टिकोण स्केल नहीं करता है क्योंकि कम से कम ओ (एन) में घनी रैंकिंग (उदाहरण के लिए लुआ के माध्यम से) की जाती है।
इसलिए, यह मानते हुए कि स्कोर के साथ बहुत सारे उपयोगकर्ता हैं, जिस दिशा में for_stack ने सुझाव दिया है वह बेहतर है, जिसमें कई डेटा संरचनाएं संयुक्त हैं। मेरा मानना है कि यह उनकी अंतिम टिप्पणी का सार है।
उपयोगकर्ताओं के स्कोर को स्टोर करने के लिए आप हैश का उपयोग कर सकते हैं। अवधारणात्मक रूप से आप सभी उपयोगकर्ताओं के स्कोर के हैश को स्टोर करने के लिए एक ही कुंजी का उपयोग कर सकते हैं, व्यावहारिक रूप से आप हैश को हैश करना चाहते हैं ताकि यह स्केल हो जाए। इस उदाहरण को सरल रखने के लिए, मैं हैश स्केलिंग पर ध्यान नहीं दूंगा।
इस प्रकार आप लुआ में उपयोगकर्ता के स्कोर को जोड़ (अपडेट) करेंगे:
local hscores_key = KEYS[1]
local user = ARGV[1]
local increment = ARGV[2]
local new_score = redis.call('HINCRBY', hscores_key, user, increment)
इसके बाद, हम प्रति असतत स्कोर मान के उपयोगकर्ताओं की वर्तमान संख्या को ट्रैक करना चाहते हैं ताकि हम उसके लिए एक और हैश रखें:
local old_score = new_score - increment
local hcounts_key = KEYS[2]
local old_count = redis.call('HINCRBY', hcounts_key, old_score, -1)
local new_count = redis.call('HINCRBY', hcounts_key, new_score, 1)
अब, आखिरी चीज जो हमें बनाए रखने की जरूरत है, वह है प्रति स्कोर रैंक, एक क्रमबद्ध सेट के साथ। प्रत्येक नया स्कोर zset में एक सदस्य के रूप में जोड़ा जाता है, और जिन स्कोरों में अधिक उपयोगकर्ता नहीं होते हैं उन्हें हटा दिया जाता है:
local zdranks_key = KEYS[3]
if new_count == 1 then
redis.call('ZADD', zdranks_key, new_score, new_score)
end
if old_count == 0 then
redis.call('ZREM', zdranks_key, old_score)
end
सॉर्ट किए गए सेट के उपयोग के कारण इस 3-पीस-स्क्रिप्ट की जटिलता O(logN) है, लेकिन ध्यान दें कि N सिस्टम में उपयोगकर्ता नहीं, असतत स्कोर मानों की संख्या है। उपयोगकर्ता की सघन रैंकिंग प्राप्त करना दूसरी, छोटी और सरल स्क्रिप्ट के माध्यम से किया जाता है:
local hscores_key = KEYS[1]
local zdranks_key = KEYS[2]
local user = ARGV[1]
local score = redis.call('HGET', hscores_key, user)
return redis.call('ZRANK', zdranks_key, score)