当前项目中的优惠促销信息需要和地图位置相关起来,所以就用到了google map。根据需求,要做一个在地图上显示郑州地区所有优惠促销信息的页面。首先对这个需求进行了分析,郑州的优惠促销信息是非常多的,如何在地图上将所有的信息显示出来?如果全部显示出来,将会出现信息的压盖和信息将地图压盖起来,用户看不到地图,也看不清楚信息。所以就需要一定的处理。
网上通行的做法就是对地图上显示的信息进行分页展示,这样在页面上显示的信息就不会很多,用可以很清晰的看到地图和地图上所展示的信息。如google map
其它的都是同样的方式,只是显示的样式有所不同。
Google map还提供了另一种方式,
将所有的信息都呈现在地图上,google map所呈现的所有信息点是绘制在图片上的,也就是说,google map的开发人员利用api有开发和制作了一个图层,和影像、纹理是同一级别的图片索引集合,数据传送到本地浏览器,这样数据不用做显示,提高了浏览器的速度,也完成了信息的查询。如果利用google map提供的marker来做,显然数据量是非常巨大的,浏览器无法承受如此多的marker对象的绘制。所以google map才用了静态图片来实现。
我们也想在地图上显示所有的数据,但是我们没有google那么强大的实力,说以就仿照了google 高考2009地图:
将信息聚合显示在地图之上,也就是说在某一位置,告诉用户这个地方有多少优惠促销信息,你可以放大或点击进入进行查看。
目标有了之后就开始研究如何实现。我的测试数据是100万条优惠促销信息。
初始实现方法:根据查询,将所有符合条件的数据读取出来,通过ajax发送到前台,然后在前台进行相交压盖判断。
试验结果是一次读取的数据量太大,消耗太多的时间,另一个就是数据读取完成之后发送到前台占用大量的带宽。再有就是前台浏览器运算压盖消耗太多的时间。
经过试验,不可行,需要进行改进,不过流程上没有太大的问题。所以感觉的思路如下:
1、 减少数据库中读取出来的数据进行。
2、 在前台建立格网索引,加快计算压盖速度。
经过分析,如果减少数据库读取出来的数据,那就没有在地图上显示或提示出网站所有的优惠促销信息,在前台建立格网索引,依然需要将大量的数据传送到前台,那为什么不在后台建立格网索引呢。分析过后,将格网索引放在后台进行处理。经过改进,是比第一次有所提高,但还不够。
经过一系列的试验分析思考之后,得出了解决方案。
将格网索引放置在数据库中,一个查询就可聚合分组查询出所以优惠促销。减少数据的读取和网络间的传送,简化前台开发(oracle 有支持地理实体的组件,Oracle Spatial,但是对于这个需求并不实用)。
具体方法如下:
1、 对google map区域的建立格网
因为google map的缩放分级,所以,建立格网时需要根据不同的级别进行创建。当前所做的指真对郑州地图,所以格网重12级到19级。如图:
12级为16*16的格网
13级为32*32的格网
….
格网的递增为四叉树。因为从12级开始就需要显示丰富的信息,说以第一级不是一个2*2的网格,而是一个15*15的网格。
格网个2维的数组,将其转换为1维数组,即12级格网号顺序从1开始到256结束。第一排从1到16,第二排从17-32以次类推,最终完成格网的模型创建。
下边开始对数据库进行设计。
创建数据表。
字段 | 类型描述 |
信息id | 关联的信息id |
Lev12 | 整型格网号 |
Lev13 | 整型格网号 |
Lev14 | 整型格网号 |
Lev15 | 整型格网号 |
Lev16 | 整型格网号 |
Lev17 | 整型格网号 |
Lev18 | 整型格网号 |
Lev19 | 整型格网号 |
通过计算,将二维的点状信息转换为相应级别下的格网好
insert into shopindex (shopid) values (sid);
--更新索引
update shopindex s
set (lev12, lev13, lev14, lev15, lev16, lev17, lev18, lev19) = (select GetGirdNo(px,
py,
12 - 12) lev12,
GetGirdNo(px,
py,
13 - 12) lev13,
GetGirdNo(px,
py,
14 - 12) lev14,
GetGirdNo(px,
py,
15 - 12) lev15,
GetGirdNo(px,
py,
16 - 12) lev16,
GetGirdNo(px,
py,
17 - 12) lev17,
GetGirdNo(px,
py,
18 - 12) lev18,
GetGirdNo(px,
py,
19 - 12) lev19
from ooshop f
where s.shopid = f.id)
where s.shopid = sid;
根据x,y,lev获取格网号函数
create or replace function GETGIRDNO(x in integer,
y in integer,
lev in integer)
return integer is
girdnum INT := 15;
width INT := 110866;
height INT := 77900;
gnum INT;
stpwidth int;
stpheight int;
xmin int := 40869800;
ymin int := 12467548;
col int;
row int;
res int;
BEGIN
gnum := girdnum * POWER(2, lev);
stpwidth := width / gnum;
stpheight := height / gnum;
col := (x - xmin) / stpwidth;
row := (y - ymin) / stpheight;
res := col + row * gnum;
if res < 0 or res >girdnum*girdnum * POWER(4, lev) then
res := 0;
end if;
return res;
END GetGirdNo;
信息如图
有了这个索引表之后,就可以用oracle的分组查询,一个查询将给定范围的数据进行分组查询出来,分组的依据就个格网,这样查询出的数据就是在这个格网下有多少条优惠促销信息。
如
获取12级的分组数据
select lev12,count(shopid) from shopindex t group by lev12
真正的查询要比这复杂点,要根据给定的地图范围进行查询,这样就需要一个函数,即根据地图范围获取这个范围下的所有格网。函数如下:
create or replace function GETGIRDNOS(stcol in integer,
strow in integer,
encol in integer,
enrow in integer,
lev in integer)
RETURN colrows IS
gnum int;
i int;
j int;
girdnum INT := 15;
colrow colrows := colrows();
BEGIN
i := strow;
gnum := girdnum * POWER(2, lev);
while (i <= enrow) loop
j := stcol;
while (j <= encol) loop
colrow.EXTEND;
colrow(colrow.COUNT) := j + i * gnum;
j := j + 1;
end loop;
i := i + 1;
end loop;
RETURN colrow;
END GetGirdNos;
数据的读取
var result = new Collection<ooBFeature>();
while (reader.Read())
{
ooBFeature gm = new ooBFeature(1);
gm.I = reader.GetInt32(0);
gm.N = reader.GetValue(1).ToString();
int row = (int)(gm.I / grid.GNum);
int col = (int)(gm.I % grid.GNum);
gm.X = col * grid.StpWidth + grid.StpWidth / 2 + ooGridModel.x;
gm.Y = row * grid.StpHeight + grid.StpHeight / 2 + ooGridModel.y;
result.Add(gm);
}
return result;
根据读取出的格网计算出地图上的坐标。以上就是用oracle建立地理信息索引的方法,如有问题,可进行交流。
梦开始的地方---图帮网www.map85.com