【redis存储结构设计】存储坐标点及其多维度点击数
伊谢尔伦
伊谢尔伦 2017-04-22 08:59:44
0
2
868

我现在有个需求

需要记录页面点击数据,上游吐到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慢查询问题。


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

伊谢尔伦
伊谢尔伦

小伙看你根骨奇佳,潜力无限,来学PHP伐。

全員に返信(2)
PHPzhong

つまり、キーの数が多い場合、クエリ速度は非常に遅くなります

主要なクエリの多くが遅い これは、最後のクエリで実際にクリックされた zset が使用されていることを意味しますか?

解像度がいくつあるかわからないですか? zset のキーを変更して、値に解像度を含めることができます。これにより、検索条件に解像度が含まれる場合、値の検索後にフィルタリングを行うことができ、速度が大幅に向上します。速い。

ただし、ボックスの選択動作は範囲が可変であるためです
フレーム選択クエリ(範囲クエリに相当) 特定の日、特定のページ、特定の解像度のクエリ
特定の範囲 (100

これは、ユーザーに検索用の領域を手動で描画するように依頼するようなものです。画像全体を含めるようにこの条件を変更することを検討していただけますか? 10 個の部分 (100 個の部分、10,000 個の部分) に切り分けます。このようにして、各部分はランダムに描画されるのではなく、特定の正方形のみを選択できます。 。

まずはこれらについて話しましょう。役立つかどうかを確認してください。まだ最適化する必要がある場合は、質問内のクエリの説明を変更できます。あなたの脳で補足できる部分がいくつかありますが、必要かどうかはわかりません。これを表現するには、より簡単な例を示します。詳しく書いて、組版を使用すると、非常に面倒になります


別々に書きましたが、質問を修正した後の回答です

まず、scopに従って自動的にインデックスをソートするというzsetの本質を使用していないようです。valueに入れるときに上記の解決策を理解していないといけないようです

zsetは、特定の日の特定のページと特定の解像度のデータを記録します
キーは date_pageid_resolution で、メンバーは valid または valid_browser_region です
スコアはクリック数です
例: キー: 20140908_0001_1000
member: 0_1_1 0は無効なクリックに対応し、1はブラウザテーブルのQQブラウザに対応し、1は地域テーブルの上海に対応します
スコア:10

A、B、C の 3 つの解決策があるとします
言われた通りにキーを保存するとこんな感じになります
20140908_0001_A
20140908_0001_B
20140908_0001_C
私がお話している保存方法は
キー:20140908_0001
メンバー:有効または無効な_browser_region_クリック数
スコア:解像度

このように検索する場合、20140908 日の 0001 ページ (キー 1 つだけ) を取得し、範囲 A の解像度を表示してそのメンバーを確認するだけで済みます。これは、適切な解像度が表示されないため、使いにくいです。この場合、zset の使用には問題があります。

上記はほんの一例です。実際には、これを行わないでください。質問を修正して要件を理解した後、新しいアプローチを思いつきました。

zset:データセット
キー:日付ページ解像度
スコア: 座標 (x と y を数値に変換することを考えてください)
メンバー: ブラウザ-地域-有効なクリック数-無効なクリック数

日付がオプションの範囲になる場合、このセットは日付を特別に保存するために必要です: date set
キー:ページ
スコア:日付
メンバー:データセットキー
日付セットの目的は、データ セット キーにインデックスを付けることです。 key() を使用する方法は、すべての検索を実行するため、非常に時間がかかります。あなたの例は特定の日です。日付の範囲がない場合もあるので、同様に、解像度が多すぎて使いこなすことができない場合は、このセットを模倣してコレクションを作成することもできます。鍵の!

次に、zset の使い方をよく見ていませんが、2 つの座標があります。

以下に 4 つのクエリ例を示しました

A 特定の日の特定のページのすべてのクリック数、つまり有効なクリックの合計数 + 無効なクリックの合計数をクエリします

B 特定の日の特定のページおよび特定の解像度での有効なクリックの合計数と無効なクリックの合計数をクエリします

C 特定の日の特定のページおよび特定の解像度のすべての座標点とクリック数をクエリします

D Box 選択クエリ (範囲クエリに相当) 特定の日の特定の範囲 (100

A: 3 つの解像度があると言いましたが、キー、範囲 0 と -1 がすべて取得された後に 3 つの解像度を追加します
20150415-page1-1380,20150415-page1-1190,20150415-page1-1000

B: これは素晴らしいですね。1 つのキーをチェックするだけで、すべての範囲の 0 と -1 を取得できます
20150415-page1-1380

C: わかりました、最初の 2 つの座標も取得できますが、ショーはありません

D: 座標セットを使用してキーを取得した後、データセットの範囲座標を確認します

書き終えましたが、タイプミスをチェックするときに小さな問題を発見しました。各地域で有効なブラウザと無効なブラウザを記録する必要があるようです。必要がない場合は、データセット内のメンバーは有効な数値と無効な数値を記録するだけで済みます。必要な場合は、その領域内のブラウザーの数に基づいて設計を検討する必要があります。あなたの質問ではこの側面が紹介されていないようです。 。

いいねを押す +0
Ty80

私の redis に対する理解は質問者とは異なるかもしれませんが、私の考えによれば、上記の要件を達成するには

となります。

ログを記憶、ETL転送データ

ついにお問い合わせ可能になりました

いいねを押す +0
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート