我现在有个需求
需要记录页面点击数据,上游吐到redis中,
上游怎么吐到redis中对我们来说是透明的,
我们只用关心redis中如何存储就好。
查询某天某页面下所有点击数,即有效点击总数
+无效点击总数
查询某天某页面某分辨率下 所有有效点击总数
和无效点击总数
查询某天某页面某分辨率下所有的坐标点及点击数
框选查询(相当于范围查询) 查询某天某页面某分辨率下 某个范围(比如100<x<1000,30<y<600
)坐标点的有效点击总数
和无效点击总数
。
同时还有各种维度的有效点击数和无效点击数
关于有效点击和无效点击:我们进行存储时可以用0和1区分,至于前端如何定义有效或者无效,对我们透明。
关于分辨率:按宽度区分共有三种:比如1380 1190 1000; 根据现有实现:有了分辨率可以将zset切割的小一些,比如没有分辨率可能有共10w个key 的zset,有了分辨率我一次最多查询某个分辨率下 可能只有3w个key 的zset
。
关于框选: 就是用鼠标在页面上从左上到右下划出一个框, 我们会查询这个选择框范围(如100<x<1000,30<y<600
)内所有的点相关的数据。
关于维度: 就是点击这个点的用户 所在地区
, 所使用浏览器
上游吐过来的点经过处理存入redis,
x,y都经过
Math.ceil(realx / 4.0) * 4;
Math.ceil(realy / 4.0) * 4;
处理,即相当于4个点为一个点
存储到redis.
zset
来实现需求。一个 zset 记录某天某页面某分辨率的数据
key
为 date_pageid_分辨率 member为: 有效OR无效_ 浏览器_ 地区score
为点击数
举例:key
: 20140908_0001_1000member
: 0_1_10对应无效点击,1对应浏览器表中的QQ浏览器,1对应地区表中的上海
score
:10
每个坐标点相关数据都用一个对应的
zset
记录key
为 date_pageid_分辨率_ 横坐标_ 纵坐标member
为: 有效OR无效浏览器地区score
为点击数
举例:key
: 20140908_0001_1000_23_478member
: 0_1_20对应无效点击,1对应浏览器表中的QQ浏览器,2对应地区表中的北京
score
:12
这样可以理解为,坐标为(23,478)
这个点,在20140908
这一天,pageid
为0001的页面上,分辨率
为1000的时候,来自北京地区的,使用QQ浏览器,进行的无效点击数
为12
两个zset 做辅助范围查询
通过zrangebyscore 分别获得x,y范围(如
100<x<1000,30<y<600
)对应的key集然后取交集获得需要查询的真正key集
y的辅助查询zetkey
为: date_pageid_分辨率yeg.20140908_0001_1000_y
member
: 为 date_pageid分辨率_ 横坐标 _纵坐标eg.20140908_0001_1000_23_478
score
为:横坐标y的值eg.478
x的辅助查询zet
key
为: date_pageid_分辨率xeg.20140908_0001_1000_x
member
: 为 date_pageid分辨率_ 横坐标 _纵坐标eg.20140908_0001_1000_23_478
score
为:横坐标X的值eg.23
查询速度太慢
举例 :比如我想一次取出某天某页面某分辨率下所有的点,
可能需要一次查询几万个keyeg. keys("20140908_0001_1000_*");
获得查询的key集之后 ,还需要使用zrange(key)
得到每个key下的member集,然后再使用zscore(key,member)
获得对应的key和 member下的score值
可以看到这个操作:
串行化执行,不容易改成并行化。
暂时的解决方案:可以利用异步任务执行 ,进行缓存以优化查询速度,
但是有可能引起redis慢查询问题。
框选行为
举例:查询范围(如100<x<1000,30<y<600
)
使用
zrangeByScore(key, 100, 1000)``zrangeByScore(key, 30, 600)
查出x,y在各自范围分别对应的key集,然后
取交集
获得最终需要查询的key集
获得查询的key集之后 ,还需要使用
zrange(key)
得到每个key下的member集,
然后再使用
zscore(key,member)
获得对应的key和 member下的score值
缺点:因为查询范围不定,所以无法进行缓存,当查询范围很大时,即key很多的时候,查询速度很慢。和上面查询坐标点一样
串行化执行,不容易改成并行化。有可能引起redis慢查询问题。
不知道大家针对我
现在的实现方案有什么更好的优化策略
或者针对查询需求有没有什么更好的设计方案
,
新人第一次发帖,感谢@暗雨西喧
对排版的提醒。
请大家多指教。
PHPz2017-04-22 09:01:44
即key很多的时候,查询速度很慢
key很多查询慢,指的是拿最后查询实际点击的zset做的事情吗?
不太清楚分辨率会有多少种?可以修改zset的key不带分辨率,而是在value中带分辨率,这样能减少很多的key,如果你搜索条件有分辨率可以在search出value后做一下过滤速度应该很快。
但是框选行为 因为范围不定
框选查询(相当于范围查询) 查询某天某页面某分辨率下
某个范围(比如100<x<1000,30<y<600)坐标点的有效点击总数和无效点击总数。
就好像是让用户手动划一片区域出来做搜索,可以考虑更改这个条件,把整个图片?切割成10份(100份,10000份)每一份就是一个方格,条件只能选取某一个方格,而不是随便划,这样可以预测的把每个方格中的数据先“汇总”下。
先说这些,你看看有没有帮助,如果还是需要再优化,你修改一下问题中的查询描述,有些地方可以脑补,但不知道你是不是要表达这个意思,所以举个简单点的例子写的详细点,用用排版,这样看着很累
我分开写,这下面是你改过问题后的
首先说你没有使用出zset的精华,根据scop自动排序索引,看来我上面说的分辨率放到value里面你肯定没看懂,我举个例子
一个 zset 记录某天某页面某分辨率的数据
key 为 date_pageid_分辨率 member为: 有效OR无效_ 浏览器_ 地区
score 为点击数
举例: key : 20140908_0001_1000
member: 0_1_1 0对应无效点击,1对应浏览器表中的QQ浏览器,1对应地区表中的上海
score:10
假设有3种分辨率:A,B,C
按照你说的存key会是这样
20140908_0001_A
20140908_0001_B
20140908_0001_C
我说的存法是
key:20140908_0001
member:有效OR无效_ 浏览器_ 地区_ 点击数
score:分辨率
这样search时,其实只需要先拿到20140908这天的0001页面(只是1个key),然后再rang A分辨率,看它的member就可以了,这样用不好,因为不nice分辨率放在这里没啥意思,这个case用zset本身就有问题。
以上只是举了个例子!实际别这么做了有更好的办法,你修改问题后了解了需求我想到了一种新的做法。
zset:data set
key:日期-page-分辨率
score:坐标(想一下把x,y变成一个数字)
member:浏览器-地区-有效点击数-无效点击数
如果日期变成可选的范围需要这个set,专门存日期,我们把它叫做:date set
key:page
score:日期
member:data set key
date set的目的是用来索引data set key,你使用key()这种做法本身就特别慢,因为它会去all search。你的例子是某天,我理解可能没有日期区间,所以date set可以不用了,同样如果分辨率过多,不可能掌握的话,也可以模仿这个set做一下key的合集!
再来是2个坐标zset,我没有仔细看,用zset好不好的斟酌一下吧。
以下你举了4个查询例子
A查询某天某页面下所有点击数,即有效点击总数+无效点击总数
B查询某天某页面某分辨率下 所有有效点击总数和无效点击总数
C查询某天某页面某分辨率下所有的坐标点及点击数
D框选查询(相当于范围查询) 查询某天某页面某分辨率下 某个范围(比如100<x<1000,30<y<600)坐标点的有效点击总数和无效点击总数
A:你说有3种分辨率,那么就在key后面加上3种分辨率吧,range 0,-1全拿
20150415-page1-1380,20150415-page1-1190,20150415-page1-1000
B:这个好啊,就查一个key的,range 0,-1全拿
20150415-page1-1380
C:好吧,前2个也能拿到坐标的,只不过你没有show而已
D:用你的坐标set拿到key后,再查data set range 坐标
都写完,检查错字时发现个小问题,貌似你需要记录每个地区浏览器的有效和无效?如果不是必须的data set中的member只是记录有效无效数字即可,如果是必须的需要看地区浏览器的数量来考虑设计了,这方面你问题中好像没怎么介绍。