工作中需要用到定位,现在用到经纬度查询高德的逆地址编码接口,可是领导嫌太贵,只能想办法做优化。
我想到之前和黑客对抗的经历,那时候黑客老是攻击我们的发短信接口,造成前公司白花花的银子白白浪费掉了,可气的是专门挑国外贵的地区发,后来我和黑客斗志斗勇,在我离职前我胜利了,当然这一段经历得写另一篇故事了。嘿,又跑题了。
刚开始,我们是采取了ip定位,把那些最贵的地区加入黑名单,当然这有一定的误伤。虽然没解决攻击的问题,但是给这次的问题提供了思路,看,人生的事谁说的准呢,也许不定什么时候就有用了。
我已经记不清当时用了什么库,我大约知道就是在本地保存一个地址文件,然后通过接口查询就可以得到地区国家城市啥的。
我在github上找了一个start最多的库,包含有go的客户端,也有nodejs的,问题解决。
但我觉得应该更进一步,了解了解原理。
1.查询原理:有IP地区元数据文件,最终查询的文件并不是这个,而是经过处理元数据文件后生成的文件,我们把这个文件叫查询文件,也就是我们需要下载下来放在项目目录下的文件,那么这个文件和元数据文件有什么不同呢?这个文件包含了查询相关的索引,对,没错,就是跟mysql数据库里的索引查不多的索引,作用也一样。查询原理可以理解为根据ip地址和索引树来查询地区相关信息,如果不考虑查询性能,不用建什么索引也能查出来,关键问题是需要快速查询,快速查询的原理与下面它的存储原理有关
2.存储原理:存储原理分为存储结构和存储方式
存储结构:二进制文件分为四个部分,第一部分是Header 段,header 段主要是记载一些头信息,最重要的是二分索引的起始地址和结束地址,这个段固定占据 256B的空间,目前只用了16B;第二部分是Vector 索引段,是二分索引的索引,也是固定大小512KB,第三个部分是二分索引,不固定大小,根据元数据大小而变化,保存了ip段和元数据指针,通过这个指针可以找到第四部分,第四部分是地域信息段,保存了国家地区等信息
存储方式:ip段优化,相邻的ip地区相同,因此二分索引保存也是一个ip范围,而不是一个具体的ip;相同的地区可能对应不同的ip,在第四部分地域信息段只保存一份数据,比如两个ip都对应了一个地区,那么这个地区只保存一份;ip地址转化为整型进行存储,减少存储空间,这是三个维度的优化使得二进制查询文件大大减小,从而提高查询效率
3.二进制查询文件生成过程:
header段 -> 地域信息段->vector索引段->二分索引段
索引段必须基于数据地域信息段来生成,vector索引是二分索引的索引
4.快速搜索
二分搜索:直接对二分索引进行二分搜索,不断读取查询文件
b+tree:先查vector索引,再查询二分索引
基于内存的二分索引:将整个查询文件载入内存中,查询效率最快
(感觉还需要个基于内存的b+tree的搜索哈,但是没有,大胆猜测一下,可能是文件都载入内存了,二分搜索和b+tree区别不大)
个人感想:
这个存储和查询逻辑和mysql 区别不大,不知道为什么不直接把这个ip导入mysql中....
这个元数据文件不能自动更新很不方便,虽然也提供了自己编辑的编辑器,但总不能手动去维护吧,至少也要搞个半年更新一次,一年更新一次,我没贡献过什么,而且还是免费的,我还是闭嘴吧
网友评论