国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

redis范圍查詢應用

2019-11-08 20:43:41
字體:
來源:轉載
供稿:網友

需求

根據ip找到對應的城市

原來的解決方案

Oracle表(ip_country):

查詢IP對應的城市:

1.把a.b.c.d這樣格式的IP轉為一個數字,例如為把210.21.224.34轉為3524648994

2. select city from ip_country where ipstartdigital <= 3524648994 and 3524648994 <=ipenddigital

redis解決方案

我們先把上面的表簡化一下:

id	city	min	max1	P1	0	1002	P2	101	2003	P3	201	3004	P4	301	400

(注意:min/max組成的range之間不能有重疊)

主要思路就是用hmset存儲表的每一行,并為每一行建立一個id(作為key)

然后把ip_end按順序從小到大存儲在sorted set當中,score對應該行的id

查詢時,利用redis sorted set的范圍查詢特性,從sorted set中查詢到id,再根據id去hmget

實驗

//存儲表的每一行127.0.0.1:6379> hmset {ip}:1 city P1 min 0 max 100OK127.0.0.1:6379> hmset {ip}:2 city P2 min 101 max 200OK127.0.0.1:6379> hmset {ip}:3 city P3 min 201 max 300OK127.0.0.1:6379> hmset {ip}:4 city P4 min 301 max 400OK//建立sorted set(member-score)127.0.0.1:6379> zadd {ip}:end.asc 100 1 200 2 300 3 400 4(integer) 4127.0.0.1:6379> zrange {ip}:end.asc 0 -11) "1"2) "2"3) "3"4) "4"//查詢對應的區間(score)127.0.0.1:6379> zrangebyscore {ip}:end.asc 90 +inf LIMIT 0 11) "1"127.0.0.1:6379> zrangebyscore {ip}:end.asc 123 +inf LIMIT 0 11) "2"127.0.0.1:6379> zrangebyscore {ip}:end.asc 100 +inf LIMIT 0 11) "1"//解釋://zrangebyscore {ip}:end.asc 90 +inf LIMIT 0 1//表示查找大于等于90的第一個值。(+inf在Redis中表示正無窮大)//該語句返回值score=1,與hmset當中的id對應,因此可以通過hmget查找城市了://查找城市127.0.0.1:6379> hmget {ip}:1 city1) "P1"

注意在設計redis key時,采用了統一的前綴:{ip}

這是為了使得這些IP相關的數據都落在同一臺redis server中(我們的redis以集群形式部署且采取一致性哈希),往后數據遷移什么的會更方便

實操

數據庫中導出的得到的文本是這樣的(選取幾行為例子):

ipcountry_tab_orderby_end_asc.txt:

"IPSTART"	"IPSTARTDIGITAL"	"IPEND"	"IPENDDIGITAL"	"COUNTRY"	"CITY"	"TYPE"	"REGISTRY"	"ADRESS"	"PROVINCE""1.184.0.0"	28835840	"1.184.127.255"	28868607	"中國"	"廣州市"	""	""	""	"廣東省""1.184.128.0"	28868608	"1.184.255.255"	28901375	"中國"	"廣州市"	""	""	""	"廣東省""1.185.0.0"	28901376	"1.185.95.255"	28925951	"中國"	"南寧市"	""	""	""	"廣西省"

1.生成批量的hmset命令及zadd命令

寫個小程序來生成:

import java.io.File;import java.io.IOException;import java.io.UnsupportedEncodingException;import java.util.ArrayList;import java.util.List;import org.apache.commons.io.FileUtils;import org.apache.commons.lang3.StringUtils;public class IpCountryRedisImport {		public static void main(String[] args) throws IOException {		File file = new File("E:/doc/ipcountry_tab_orderby_end_asc.txt");		File hmsetFile = new File("E:/doc/ip_country_redis_cmd.txt");		File zaddFile = new File("E:/doc/ip_country_redis_zadd.txt");				List<String> lines = FileUtils.readLines(file);		int i = 0;		StringBuilder rows = new StringBuilder();		StringBuilder ends = new StringBuilder();		for (String str : lines) {			if (StringUtils.isEmpty(str)) {				continue;			}						//skip first line			if (i == 0) {				i++;				continue;			}						i++;						//"IPSTART"	"IPSTARTDIGITAL"	"IPEND"	"IPENDDIGITAL"	"COUNTRY"	"CITY"	"TYPE"	"REGISTRY"	"ADRESS"	"PROVINCE"			//0               1                2         3              4          5       6         7         8            9 			String[] parts = str.split("/t");			String start = parts[1];			String end = parts[3];			String country = parts[4];			String city = parts[5];			String type = parts[6];			String registry = parts[7];			String address = parts[8];			String province = parts[9];						//String cmd = "hmset {ip}:" + (i++) + " start " + start + " end " + end + " country " + country + " city " + city + " type " + type + " registry " + registry + " address " + address + " province " + province;						rows.append("*18/r/n");						rows.append(format("hmset"));						rows.append(format("{ip}:" + i));						rows.append(format("start"));			rows.append(format(start));						rows.append(format("end"));			rows.append(format(end));						rows.append(format("country"));			rows.append(format(country));						rows.append(format("city"));			rows.append(format(city));						rows.append(format("type"));			rows.append(format(type));						rows.append(format("registry"));			rows.append(format(registry));						rows.append(format("address"));			rows.append(format(address));						rows.append(format("province"));			rows.append(format(province));									//zadd {ip}:end.asc 1234 1			ends.append("*4/r/n");			ends.append(format("zadd"));			ends.append(format("{ip}:end.asc"));			ends.append(format(end));			ends.append(format("" + i));					}		FileUtils.writeStringToFile(hmsetFile, rows.toString(), "UTF-8");		FileUtils.writeStringToFile(zaddFile, ends.toString(), "UTF-8");		System.out.println(1);	}		private static String format(String value) throws UnsupportedEncodingException {		String trimValue = value.replace("/"", "");		return "$" + trimValue.getBytes("UTF-8").length+ "/r/n" + trimValue + "/r/n";	}}

需要注意的是,format方法里面,值的長度不是字符串的長度,而是字符串轉化為字節之后的長度

生成hmset結果舉例(ip_country_redis_cmd.txt,每一行都是以/r/n結尾):

*18$5hmset$8{ip}:645$5start$828835840$3end$828868607$7country$6中國$4city$9廣州市$4type$0$8registry$0$7address$0$8province$9廣東省

生成的zadd命令舉例(ip_country_redis_zadd.txt):

*4$4zadd$12{ip}:end.asc$816777471$12

需要注意的是,txt文件通過SecureCRT上傳到linux后,/r/n可能就只剩/n了,可以替換一下:

perl -pi -e 's//n//r/n/' ip_country_redis_cmd.txt perl -pi -e 's//n//r/n/' ip_country_redis_zadd.txt

2.導入redis

文件生成完畢后,執行以下命令導入:

cat ip_country_redis_cmd.txt | redis-cli –pipecat ip_country_redis_zadd.txt | redis-cli --pipe

40萬行的數據,花費時間不到一分鐘,redis的mass insertion還是很強大的

在這里要提一下的是,redis文檔中關于批量導入的說明可能會有誤導:

文檔是這樣的:

SET Key0 Value0SET Key1 Value1...SET KeyN ValueN

我剛開始以為像上面那樣,只要把批量redis命令寫在同一個文本文件,然后直接導入就可以了:

cat cmd.txt | redis-cli –pipe

實際上不是的,要符合redis protocol才可以

protocol語法:

*<args><cr><lf>$<len><cr><lf><arg0><cr><lf><arg1><cr><lf>...<argN><cr><lf>

舉例:

*3<cr><lf>$3<cr><lf>SET<cr><lf>$3<cr><lf>key<cr><lf>$5<cr><lf>value<cr><lf>

說明:

*后面的數字表示該條redis命令有多少參數,

例如:

set ab 1234參數個數是3

hmset name google.com 1 baidu.com 2的參數個數是6

接下來就是命令的每一部分(空格分隔),先是長度,后是值:

以“set ab 1234”為例:

set的長度是3,ab的長度是2,1234的長度是4,因此最終內容為:

*3$3set$2ab$41234

注意每一行都是以<cr><lf>(也就是/r/n)結尾

3.查詢

使用spring redis

關鍵代碼:

long min = ip;	//轉換成數字的IP			long max = Long.MAX_VALUE;			long offset = 0;			long count = 1;			Set<String> result = redisTemplate.opsForZSet().rangeByScore(zSetName, min, max, offset, count);final String ipKey = redisIprowPrefix + score;				String city = redisTemplate.execute(new RedisCallback<String>(){					@Override					public String doInRedis(RedisConnection connection)							throws DataaccessException {						byte[] key = redisTemplate.getStringSerializer().serialize(  			                    ipKey);  			            if (connection.exists(key)) {  			                List<byte[]> value = connection.hMGet(  			                        key,  			                        redisTemplate.getStringSerializer().serialize(  			                                "city")			                        );  			                String city = redisTemplate.getStringSerializer()  			                        .deserialize(value.get(0));  			                return city;			            }			            return null;					}									});

redisTemplate需要配置序列化相關的property:

<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"		p:connection-factory-ref="jedisConnFactory">		<property name="valueSerializer">			<bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />		</property>		<property name="keySerializer">			<bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />		</property> </bean>
上一篇:MySql常用函數

下一篇:SQL性能優化

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 房山区| 永州市| 崇仁县| 太谷县| 广宗县| 繁昌县| 清原| 大冶市| 特克斯县| 泽库县| 平原县| 班玛县| 武宁县| 霸州市| 钦州市| 正阳县| 石棉县| 绥中县| 衡阳市| 延吉市| 蓬安县| 抚顺县| 邮箱| 庄河市| 瑞丽市| 望城县| 新昌县| 灵台县| 金秀| 怀集县| 新丰县| 宜川县| 黄石市| 榆社县| 威信县| 南川市| 南华县| 自治县| 潼南县| 竹山县| 呈贡县|