Maison  >  Questions et réponses  >  le corps du texte

【redis存储结构设计】存储坐标点及其多维度点击数

我现在有个需求

需要记录页面点击数据,上游吐到redis中,

上游怎么吐到redis中对我们来说是透明的,

我们只用关心redis中如何存储就好。


查询需求:

  1. 查询某天某页面下所有点击数,即有效点击总数+无效点击总数

  2. 查询某天某页面某分辨率下 所有有效点击总数无效点击总数

  3. 查询某天某页面某分辨率下所有的坐标点及点击数

  4. 框选查询(相当于范围查询) 查询某天某页面某分辨率下 某个范围(比如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.

使用4个zset来实现需求。

一个 zset 记录某天某页面某分辨率的数据
key 为 date_pageid_分辨率 member为: 有效OR无效_ 浏览器_ 地区
score 为点击数
举例key : 20140908_0001_1000
member: 0_1_1 0对应无效点击,1对应浏览器表中的QQ浏览器,1对应地区表中的上海
score:10


每个坐标点相关数据都用一个对应的zset记录
key为 date_pageid_分辨率_ 横坐标_ 纵坐标
member为: 有效OR无效浏览器地区
score为点击数
举例key : 20140908_0001_1000_23_478
member: 0_1_2 0对应无效点击,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的辅助查询zet
key为: date_pageid_分辨率y eg.20140908_0001_1000_y
member: 为 ​date_pageid
分辨率_ 横坐标 _纵坐标 eg.20140908_0001_1000_23_478
score为:横坐标y的值​ eg.478

x的辅助查询zet
key为: date_pageid_分辨率x eg.20140908_0001_1000_x
member: 为 ​date_pageid
分辨率_ 横坐标 _纵坐标 eg.20140908_0001_1000_23_478
score为:横坐标X的值​ eg.23


当前实现存在的问题

查询速度太慢

举例比如我想一次取出某天某页面某分辨率下所有的点
可能需要一次查询几万个key eg. 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慢查询问题。


不知道大家针对我现在的实现方案有什么更好的优化策略
或者针对查询需求有没有什么更好的设计方案
新人第一次发帖,感谢@暗雨西喧对排版的提醒。
请大家多指教。

伊谢尔伦伊谢尔伦2736 Il y a quelques jours805

répondre à tous(2)je répondrai

  • PHPz

    PHPz2017-04-22 09:01:44

    C'est-à-dire que lorsqu'il y a beaucoup de clés, la vitesse de requête est très lente

    L'interrogation avec de nombreuses clés est lente. Cela fait-il référence au zset réellement cliqué lors de la dernière requête ?

    Je ne sais pas combien de résolutions il y aura ? Vous pouvez modifier la clé de zset non pas pour avoir une résolution, mais pour avoir une résolution en valeur. Cela peut réduire beaucoup de clés. Si vos conditions de recherche ont une résolution, vous pouvez effectuer un filtrage après avoir recherché une valeur, et la vitesse devrait être très élevée. rapide.

    Mais le comportement de sélection de la boîte est dû au fait que la plage est variable
    Requête de sélection de cadre (équivalent à la requête de plage) Requête sur un certain jour, une certaine page, une certaine résolution
    Nombre total de clics valides et nombre total de clics incorrects aux points de coordonnées dans une certaine plage (par exemple 100<x<1 000,30<y<600).

    C'est comme demander à l'utilisateur de dessiner manuellement une zone de recherche. Pouvez-vous envisager de modifier cette condition pour inclure l'image entière ? Découpé en 10 parties (100 parties, 10 000 parties). Chaque partie est un carré. La condition ne peut sélectionner qu'un certain carré, plutôt que de simplement le dessiner au hasard. De cette manière, les données de chaque carré peuvent être « résumées » de manière prévisible. .

    Parlons-en d'abord et voyons si cela aide. Si vous avez encore besoin de l'optimiser, vous pouvez modifier la description de la requête dans la question. Il y a certains endroits que vous pouvez rattraper, mais je ne sais pas si vous le pouvez. Je veux exprimer cela, je vais donc vous en donner un simple. Veuillez écrire l'exemple en détail et utiliser la composition, cela a l'air très fatiguant


    Je les ai écrits séparément. Voici la réponse après avoir corrigé la question

    Tout d'abord, vous n'utilisez pas l'essence de zset, qui trie automatiquement l'index selon scop. Il semble que vous ne devez pas comprendre la résolution que j'ai mentionnée ci-dessus lorsque vous la mettez en valeur. exemple

    Un zset enregistre les données d'une certaine page et d'une certaine résolution un certain jour
    La clé est date_pageid_resolution et le membre est : valide OU invalid_browser_region
    le score est le nombre de clics
    Exemple : clé : 20140908_0001_1000
    membre : 0_1_1 0 correspond à un clic invalide, 1 correspond au navigateur QQ dans la table du navigateur, 1 correspond à Shanghai dans la table des régions
    note : 10

    Supposons qu'il y ait 3 résolutions : A, B, C
    D'après ce que vous avez dit, la clé ressemblera à ceci
    20140908_0001_A
    20140908_0001_B
    20140908_0001_C
    La méthode de stockage dont je parle est
    clé :20140908_0001
    membre : validORinvalid_browser_region_number de clics
    score:résolution

    Lors d'une recherche comme celle-ci, il vous suffit en fait d'obtenir la page 0001 du jour 20140908 (juste 1 clé), puis de sélectionner la résolution A et de regarder ses membres. Ce n'est pas utile car ce n'est pas agréable à distinguer. Cela ne sert à rien de mettre le taux ici. L'utilisation de zset pose des problèmes dans ce cas.

    Ce qui précède n'est qu'un exemple ! En fait, ne faites pas ça. Il existe une meilleure façon. Après avoir révisé la question et compris les exigences, j'ai proposé une nouvelle approche.

    zset:ensemble de données
    clé : date-page-résolution
    score : coordonnées (pensez à transformer x et y en nombre)
    membre : navigateur-région-nombre de clics valides-nombre de clics invalides

    Si la date devient une plage facultative, cet ensemble est nécessaire pour stocker la date spécifiquement. Nous l'appelons : ensemble de dates
    . clé:page
    score :date
    membre : clé de l'ensemble de données
    Le but de l'ensemble de dates est d'indexer la clé de l'ensemble de données. Votre méthode d'utilisation de key() est très lente car elle effectuera une recherche complète. Votre exemple est un certain jour. Je comprends qu'il peut n'y avoir pas de plage de dates, donc le jeu de dates peut être inutile. De même, s'il y a trop de résolutions et qu'il est impossible de le maîtriser, vous pouvez également imiter cet ensemble pour créer une collection. de clés !

    Les deux coordonnées suivantes sont zset. Je ne les ai pas regardées attentivement. Réfléchissons bien à l'utilisation de zset.

    Vous avez donné 4 exemples de requêtes ci-dessous

    A interroge le nombre de clics sur une certaine page un certain jour, c'est-à-dire le nombre total de clics valides + le nombre total de clics invalides

    B Interroger le nombre total de clics valides et le nombre total de clics invalides sur une certaine page et une certaine résolution un certain jour

    C Interroger tous les points de coordonnées et le nombre de clics sur une certaine page et une certaine résolution un certain jour

    Requête de sélection de cadre D (équivalent à la requête de plage) Interrogez le nombre total de clics valides et le nombre total de clics invalides de points de coordonnées dans une certaine plage (telle que 100<x<1000,30<y<600) à une certaine résolution un certain jour

    A : Vous avez dit qu'il y avait 3 résolutions, puis ajoutez 3 résolutions après la clé, les plages 0 et -1 sont toutes incluses
    20150415-page1-1380,20150415-page1-1190,20150415-page1-1000

    B : C'est génial. Cochez simplement une touche et obtenez la plage 0 et -1
    20150415-page1-1380

    C : D'accord, les deux premiers peuvent aussi obtenir les coordonnées, mais vous n'avez pas de spectacle

    D : Après avoir utilisé votre ensemble de coordonnées pour obtenir la clé, vérifiez les coordonnées de la plage de l'ensemble de données

    Après avoir tout écrit, j'ai trouvé un petit problème lors de la vérification des fautes de frappe. Il semble que vous deviez enregistrer les navigateurs valides et invalides dans chaque région ? Si cela n'est pas nécessaire, les membres de l'ensemble de données peuvent simplement enregistrer des numéros valides et invalides. Si cela est nécessaire, la conception doit être prise en compte en fonction du nombre de navigateurs dans la région. Votre question ne semble pas introduire cet aspect. .

    répondre
    0
  • PHP中文网

    PHP中文网2017-04-22 09:01:44

    Peut-être que ma compréhension de Redis est différente de celle de la personne qui pose la question. Selon mon idée, atteindre les exigences ci-dessus peut être

    .

    N'oubliez pas le journal, etl transfère les données

    Enfin disponible

    répondre
    0
  • Annulerrépondre