背景
通过IP地址查询ip地址所属省市,存在这样的数据
3748137472,3748137727,223.104.10.0,223.104.10.255,中国,江西,,,移动,330000,,城域网 3748137728,3748137983,223.104.11.0,223.104.11.255,中国,陕西,,,移动,710000,,移动网络 3748137984,3748138239,223.104.12.0,223.104.12.255,中国,云南,,,移动,650000,,移动网络 3748138240,3748138495,223.104.13.0,223.104.13.255,中国,河北,,,移动,050000,,移动网络 3748138496,3748138751,223.104.14.0,223.104.14.255,中国,山西,,,移动,030000,,移动网络 3748138752,3748138815,223.104.15.0,223.104.15.63,中国,内蒙古,,,移动,010000,,移动网络 3748138816,3748138847,223.104.15.64,223.104.15.95,中国,内蒙古,,,移动,020000,,移动网络
通过将IP地址翻译成数字比较数字所属区间找到对应的省市信息,单个或多个查询都没问题,如果批量查询上万个,对oracle的性能是很大的考验,于是想到了缓存,但是普通的map结构似乎不能满足,于是想到了二叉树,基本逻辑是用二分法将数据排序,取中间的为根节点,向左向右取中间节点为左右子节点构建大树,然后按照二叉树逻辑检索,测试了一下性能还可以,记录一下。
package org.example.util;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;
public class CacheRange {
public static void main(String[] args) {
Date begin = new Date();
long max = 4294967296l;
long min =0;
Random random = new Random();
List<Node> nodes = new ArrayList<>();
while(min < max){
int increment = random.nextInt(1000);
Node node = new Node(min,min+increment);
nodes.add(node);
min = min+increment;
}
Date now = new Date();
System.out.println(nodes.size()+" cost "+(now.getTime()-begin.getTime()));
int maxSize = nodes.size()-1;
int minSize = 0;
int curSize = (maxSize-minSize)/2;
Node root = nodes.get(curSize);
root.setLeft(getMidNode(nodes,curSize,minSize,true));
root.setRight(getMidNode(nodes,maxSize,curSize,false));
System.out.println(root);
now = new Date();
System.out.println("setMidNode cost "+(now.getTime()-begin.getTime()));
long idx = 29496729l;
for(int i=0;i<100;i++){
Node node = root.indexNode(idx);
System.out.println(idx+"@node is "+node);
idx = idx + random.nextInt(1000);
}
now = new Date();
System.out.println(nodes.size()+" cost "+(now.getTime()-begin.getTime()));
}
public static Node getMidNode(List<Node> nodes, int maxSize, int minSize,boolean isleft){
int curSize = (maxSize-minSize)/2+minSize;
Node root;
if(maxSize-minSize <= 1){//这里考虑2个元素、1个元素情况
if(isleft){
root = nodes.get(minSize);
}else{
root = nodes.get(maxSize);
}
if(root.isExist){
return null;
}
return root;
}else{
root = nodes.get(curSize);
if(null == root || root.isExist){
return null;
}
root.setLeft(getMidNode(nodes,curSize,minSize,true));
root.setRight(getMidNode(nodes,maxSize,curSize,false));
return root;
}
}
static class Node{
long begin = 0;
long end = 0;
Node left;
Node right;
boolean isExist =false;
public Node(long begin,long end){
this.begin=begin;
this.end = end;
}
public void setLeft(Node left){
this.left=left;
}
public Node getLeft(){
return this.left;
}
public void setRight(Node right){
this.right=right;
}
public Node getRight(){
return this.right;
}
public void setIsExist(){
this.isExist = true;
}
public Node indexNode(long index){
if(this.begin <= index && this.end >= index){
return this;
}
if(this.begin > index){
return this.left.indexNode(index);
}
if(this.end < index){
return this.right.indexNode(index);
}
return null;
}
@Override
public String toString(){
return this.begin+" - "+this.end;
}
}
}
测试的结果如下:
8597917 cost 2347
2146951032 - 2146951635
setMidNode cost 2461
29496729@node is 29496411 - 29497393
29497062@node is 29496411 - 29497393
29497953@node is 29497466 - 29498096......
29544412@node is 29544398 - 29544647
29545207@node is 29544647 - 29545591
8597917 cost 2462Process finished with exit code 0
树结构