2013-04-16 57 views
0

我在尋找儘可能高效的redis密鑰列表。我們可以在redis服務器上對此進行建模,但我們很喜歡這樣做,因爲這是解決問題的正確方法。讓我描述一下情況。如何在Redis中相交併找到不同的密鑰

假設一大組以Redis形式存儲爲「字符串」的「客戶」。

customer__100000 
customer__100001 
customer__100002 

每個客戶都有不少屬性。那些將是他們居住的城市。每個城市也存儲在Redis中。

city__New York 
city__San Francisco 
city__Washington DC 

通過不同的理線我會在最後一組客戶密鑰(相交集預過濾器)。一旦我有這些密鑰我需要找出我有內那些不同城市顧客。我的最終目標是獲得城市的名字,但是如果我可以得到鑰匙,那麼我可以把城市名稱也放在這裏。

爲了給出一個我在這裏談論的規模的想法,假設我們正在處理大約70個屬性(城市就是其中之一)的200-300k個客戶,並且每個屬性都在50-100000之間。我想盡可能保持高效。

回答

2

不應將客戶存儲爲字符串,而應將其存儲爲散列。 Redis對哈希的ziplist編碼非常節省空間。如果您要存儲超過70個元素,則應考慮提高redis.conf中的hash-max-ziplist-entries限制。當您使用Redis散列時,可以使用SORT做有趣的事情。通過使用SORTGETSTORE,您可以從客戶那裏獲取所有城市,並將它們存儲爲列表(不是獨特的)。您可以通過在列表中調用lpopsadd將列表轉換爲集。

下面是一個例子Redis的Lua的腳本:

-- a key which holds a set of customer keys 
local set_of_customer_keys = KEYS[1] 
-- a maybe-existing key which will hold the set of cities 
local distinct_set = ARGV[1] 
-- attribute to get (defaults to city) 
local attribute = ARGV[2] or 'city' 
-- remove current set of distinct_cities 
redis.call("DEL", distinct_set) 
-- use SORT to build a list out of customer hash values for `attribute` 
local cities = redis.call("SORT", set_of_customer_keys, "BY", "nosort", "GET", "*->"..attribute) 
-- loop through all cities in the list and add them to the distinct cities set 
for i, city in pairs(cities) do 
    redis.call("SADD", distinct_set, city) 
end 
-- return the distinct cities 
return redis.call("SMEMBERS", distinct_set) 

你也可以保持customer__100000__cities組永久隨着客戶的屬性存儲和使用sinter *customer_cities_keys獲得一組不同的城市,但是這將是更少的內存效率。

+0

有趣的想法。儘管我們最終將5萬個城市拉下來,然後有效地將所有50,000個添加到一個可能最終有100個條目的集合中,但給定一組50,000個客戶。我對這條路線的性能感到好奇,因爲管道已經關閉,數據備份了。 –

+0

當然你可能指的是執行Lua腳本服務器端。 –

+0

是的,絕對是使用Redis EVAL調用的Lua腳本。我估計即使有5萬個參賽作品也會很快。你可能想在if語句中用'EXPIRE'和'TTL'來記憶'distinct_set'鍵。我已經更新了Lua腳本,因此它使用Lua表格代替Redis列表中的城市。我認爲現在更容易理解。 – lastcanal