‘select * from users where user.location="shanghai"’
這樣的查詢,在Redis是沒辦法通過value進行比較得出結果的。但是可以通過不同的數據結構類型來做到這壹點。比如如下的數據定義
users:1 {name:Jack,age:28,location:shanghai}
users:2 {name:Frank,age:30,location:beijing}
users:location:shanghai [1]
其中users:1 users:2 分別定義了兩個用戶信息,通過Redis中的hash數據結構,而users:location:shanghai 記錄了所有上海的用戶id,通過集合數據結構實現。這樣通過兩次簡單的Redis命令調用就可以實現我們上面的查詢。
Jedis jedis = jedisPool.getResource();
Set<String> shanghaiIDs = jedis.smembers("users:location:shanghai");
//遍歷該set
//...
//通過hgetall獲取對應的user信息
jedis.hgetAll("users:" + shanghaiIDs[0]);
通過諸如以上的設計,可以實現簡單的條件查詢。但是這樣的問題也很多,首先需要多維護壹個ID索引的集合,其次對於壹些復雜查詢無能為力(當然也不能期望Redis實現像關系數據庫那樣的查詢,Redis不是幹這的)。
但是Redis2.6集成了Lua腳本,可以通過eval命令,直接在RedisServer環境中執行Lua腳本,並且可以在Lua腳本中調用Redis命令。其實,就是說可以讓妳用Lua這種腳本語言,對Redis中存儲的key value進行操作,這個意義就大了,甚至可以將妳們系統所需的各種業務寫成壹個個lua腳本,提前加載進入Redis,然後對於請求的響應,只需要調用壹個個lua腳本就行。當然這樣說有點誇張,但是意思就是這樣的。
比如,現在我們要實現壹個‘所有age大於28歲的user’這樣壹個查詢,那麽通過以下的Lua腳本就可以實現
public static final String SCRIPT =
"local resultKeys={};"
+ "for k,v in ipairs(KEYS) do "
+ " local tmp = redis.call('hget', v, 'age');"
+ " if tmp > ARGV[1] then "
+ " table.insert(resultKeys,v);"
+ " end;"
+ "end;"
+ "return resultKeys;";
執行腳本代碼
Jedis jedis = jedisPool.getResource();
jedis.auth(auth);
List<String> keys = Arrays.asList(allUserKeys);
List<String> args = new ArrayList<>();
args.add("28");
List<String> resultKeys = (List<String>)jedis.evalsha(funcKey, keys, args);
return resultKeys;
註意,以上的代碼中使用的是evalsha命令,該命令參數的不是直接Lua腳本字符串,而是提前已經加載到Redis中的函數的壹個SHA索引,通過以下的代碼將系統中所有需要執行的函數提前加載到Redis中,我們的系統維護壹個函數哈希表,後續需要實現什麽功能,就從函數表中獲取對應功能的SHA索引,通過evalsha調用就行。
String shaFuncKey = jedis.scriptLoad(SCRIPT);//加載腳本,獲取sha索引
funcTable.put(funcName_age, shaFuncKey);//添加到函數表中
通過以上的方法,便可以使較為復雜的查詢放到Redis中去執行,提高效率。