使用ClickHouse实现,累计用户计算模型

简介: 问题描述:根据用户标识和历史库的匹配结果,识别是否是新增用户,单位:天要求:历史库每天累加更新,要考录用户历史数据库的幂等性及回补数据策略输出:用户pushidpushid对应的uid(如果当天没有没有登录就没有对应的pushid则从历史库中匹配)pushid当天和uid是否有对应关系用户新增时间用户历史所有投资次数当天用户投资次数用户每次投资时间(rechargeTime) 说明:用户标识有两个 pushid、uid,pushid表示用户的注册id,登录的时候才会存在,uid是用户访问的cookie(会频繁变化)。

问题描述:根据用户标识和历史库的匹配结果,识别是否是新增用户,单位:天

要求:历史库每天累加更新,要考录用户历史数据库的幂等性及回补数据策略

输出:

  • 用户pushid
  • pushid对应的uid(如果当天没有没有登录就没有对应的pushid则从历史库中匹配)
  • pushid当天和uid是否有对应关系
  • 用户新增时间
  • 用户历史所有投资次数
  • 当天用户投资次数
  • 用户每次投资时间(rechargeTime)

 

说明:

用户标识有两个 pushid、uid,pushid表示用户的注册id,登录的时候才会存在,uid是用户访问的cookie(会频繁变化)。

因此在业务中要关联两者之间的关系。

 

创建历史库:

CREATE TABLE IF NOT EXISTS `db_name`.`table_name` (
    partition Date DEFAULT '1970-01-01',
    pushid String DEFAULT '',
    opTime DateTime DEFAULT 0,
    rechargeTime DateTime DEFAULT 0, # rechargeTime如果不是默认值则表示用户发生投资时间
    appkey String DEFAULT '',
    uid String DEFAULT '',
    ver UInt64 DEFAULT 0
)
ENGINE = ReplacingMergeTree(partition, (pushid, rechargeTime), 8192, ver)

利用ReplacingMergeTree实现数据幂等性,当重复入库数据时会去除重复项,保证数据执行多次时数据不重复。

ver表示版本号,当数据重复时,会以最大的版本号为准,版本号可以是一个递增的数字,业务中数据的版本号是插入的时的时间戳。

*其中:(pushid, rechargeTime)中的rechargeTime表示用户复投时间,如果业务中没有对用户发生某一个行为特殊要求则可以删除。

 

历史库更新代码(每天更新):

INSERT INTO db_name.table_name SELECT 
    partition, 
    pushid, 
    opTime, 
    rechargeTime, 
    appkey, 
    uid, 
    ver
FROM 
(
    SELECT 
        partition, 
        jhd_pushid AS pushid, 
        jhd_opTime AS opTime, 
        jhd_opTime AS rechargeTime, 
        jhd_datatype AS appkey, 
        jhd_userkey AS uid, 
        CAST(835664 AS UInt64) AS ver
    FROM ncf_h5.userevent 
    WHERE (partition = toDate('2017-03-28')) AND (jhd_pushid != '') AND (jhd_opType = 'page') AND (visitParamExtractString(jhd_map, 'uri') LIKE '%/pay_result%')
    UNION ALL 
    SELECT 
        partition, 
        jhd_pushid AS pushid, 
        min(jhd_opTime) AS opTime, 
        toDateTime('1970-01-01 00:00:00') AS rechargeTime, 
        jhd_datatype AS appkey, 
        jhd_userkey AS uid, 
        CAST(835664 AS UInt64) AS ver
    FROM ncf_h5.userevent 
    WHERE (partition = toDate('2017-03-28')) AND (jhd_pushid != '')
    GROUP BY 
        jhd_datatype, 
        partition, 
        pushid, 
        jhd_userkey
    UNION ALL 
    SELECT 
        partition, 
        jhd_pushid AS pushid, 
        jhd_opTime AS opTime, 
        jhd_opTime AS rechargeTime, 
        jhd_datatype AS appkey, 
        jhd_userkey AS uid, 
        CAST(835664 AS UInt64) AS ver
    FROM ncf_ws.userevent 
    WHERE (partition = toDate('2017-03-28')) AND (jhd_pushid != '') AND (jhd_opType = 'page') AND (visitParamExtractString(jhd_map, 'uri') LIKE '%/success%')
    UNION ALL 
    SELECT 
        partition, 
        jhd_pushid AS pushid, 
        min(jhd_opTime) AS opTime, 
        toDateTime('1970-01-01 00:00:00') AS rechargeTime, 
        jhd_datatype AS appkey, 
        jhd_userkey AS uid, 
        CAST(835664 AS UInt64) AS ver
    FROM ncf_ws.userevent 
    WHERE (partition = toDate('2017-03-28')) AND (jhd_pushid != '')
    GROUP BY 
        jhd_datatype, 
        partition, 
        pushid, 
        jhd_userkey
)

数据导出代码:

数据格式:

pushid、是否当天登录、uid、新增时间、用户历史所有投资次数、当天用户投资次数、用户每次投资时间

 

SELECT 
    pushid, 
    1 AS isfind, 
    uids, 
    earliest, 
    recharge_n, 
    recharge_today, 
    recharge_arr
FROM 
(
    SELECT 
        pushid, 
        CAST(earliest AS String) AS earliest, 
        recharge_n, 
        recharge_today, 
        arrayMap(lambda(tuple(x), CAST(x AS String)), arrayFilter(lambda(tuple(x), x != '1970-01-01 00:00:00'), recharge_arr)) AS recharge_arr, 
        arrayFilter(lambda(tuple(x), x != ''), uids) AS uids
    FROM 
    (
        SELECT pushid, groupUniqArray(uid) AS uids
        FROM ncf_common.user_pushid 
        WHERE partition = toDate('2017-04-04')
        GROUP BY pushid
    ) 
    ANY LEFT JOIN 
    (
        SELECT 
            pushid, 
            min(opTime) AS earliest, 
            sumIf(1, rechargeTime != '1970-01-01 00:00:00') AS recharge_n, 
            sumIf(1, toDate(rechargeTime) = toDate('2017-04-04')) AS recharge_today, 
            groupArray(rechargeTime) AS recharge_arr
        FROM ncf_common.user_pushid 
        WHERE (partition <= toDate('2017-04-04')) AND (partition >= (toDate('2017-04-04') - 365))
        GROUP BY pushid
    ) USING (pushid)
) 
ARRAY JOIN uids
UNION ALL 
SELECT 
    pushid, 
    0 AS isfind, 
    uids, 
    CAST(earliest AS String) AS earliest, 
    recharge_n, 
    recharge_today, 
    arrayMap(lambda(tuple(x), CAST(x AS String)), arrayFilter(lambda(tuple(x), x != '1970-01-01 00:00:00'), recharge_arr)) AS recharge_arr
FROM 
(
    SELECT 
        pushid, 
        groupUniqArray(uid) AS uids, 
        min(opTime) AS earliest, 
        sumIf(1, rechargeTime != '1970-01-01 00:00:00') AS recharge_n, 
        sumIf(1, toDate(rechargeTime) = toDate('2017-04-04')) AS recharge_today, 
        arrayFilter(lambda(tuple(x), x != '1970-01-01 00:00:00'), groupArray(rechargeTime)) AS recharge_arr
    FROM 
    (
        SELECT 
            pushid, 
            uid, 
            opTime, 
            rechargeTime
        FROM 
        (
            SELECT 
                jhd_userkey AS uid, 
                groupUniqArray(jhd_pushid) AS pushids, 
                'ncf_ws' AS appkey
            FROM ncf_ws.userevent 
            WHERE partition = toDate('2017-04-04')
            GROUP BY jhd_userkey
            HAVING (length(pushids) = 1) AND has(pushids, '')
            UNION ALL 
            SELECT 
                jhd_userkey AS uid, 
                groupUniqArray(jhd_pushid) AS pushids, 
                'ncf_h5' AS appkey
            FROM ncf_h5.userevent 
            WHERE partition = toDate('2017-04-04')
            GROUP BY jhd_userkey
            HAVING (length(pushids) = 1) AND has(pushids, '')
        ) 
        ALL INNER JOIN 
        (
            SELECT 
                pushid, 
                uid, 
                opTime, 
                rechargeTime, 
                appkey
            FROM ncf_common.user_pushid 
            WHERE partition < toDate('2017-04-04')
        ) USING (uid)
    ) 
    GROUP BY pushid
) 
ARRAY JOIN uids

 

目录
相关文章
|
3月前
|
存储 关系型数据库 数据库
【DDIA笔记】【ch2】 数据模型和查询语言 -- 多对一和多对多
【6月更文挑战第7天】该文探讨数据模型,比较了“多对一”和“多对多”关系。通过使用ID而不是纯文本(如region_id代替&quot;Greater Seattle Area&quot;),可以实现统一、避免歧义、简化修改、支持本地化及优化搜索。在数据库设计中,需权衡冗余和范式。文档型数据库适合一对多但处理多对多复杂,若无Join,需应用程序处理。关系型数据库则通过外键和JOIN处理这些关系。文章还提及文档模型与70年代层次模型的相似性,层次模型以树形结构限制了多对多关系处理。为克服层次模型局限,发展出了关系模型和网状模型。
44 6
|
3月前
|
SQL 人工智能 关系型数据库
【DDIA笔记】【ch2】 数据模型和查询语言 -- 文档模型中Schema的灵活性
【6月更文挑战第8天】网状模型是层次模型的扩展,允许节点有多重父节点,但导航复杂,需要预知数据库结构。关系模型将数据组织为元组和关系,强调声明式查询,解耦查询语句与执行路径,简化了访问并通过查询优化器提高效率。文档型数据库适合树形结构数据,提供弱模式灵活性,但在Join支持和访问局部性上不如关系型。关系型数据库通过外键和Join处理多对多关系,适合高度关联数据。文档型数据库的模式灵活性体现在schema-on-read,写入时不校验,读取时解析,牺牲性能换取灵活性。适用于不同类型或结构变化的数据场景。
36 0
|
3月前
|
SQL JSON NoSQL
【DDIA笔记】【ch2】 数据模型和查询语言 -- 关系模型与文档模型
【6月更文挑战第6天】关系模型是主流数据库模型,以二维表形式展示数据,支持关系算子。分为事务型、分析型和混合型。尽管有其他模型挑战,如网状和层次模型,但关系模型仍占主导。然而,随着大数据增长和NoSQL的出现(如MongoDB、Redis),强调伸缩性、专业化查询和表达力,关系模型的局限性显现。面向对象编程与SQL的不匹配导致“阻抗不匹配”问题,ORM框架缓解但未完全解决。文档模型(如JSON)提供更自然的嵌套结构,适合表示复杂关系,具备模式灵活性和更好的数据局部性。
39 0
|
搜索推荐 BI OLAP
Clickhouse在画像场景如何快速计算人群的年龄分布
在画像场景场景中,对不同年龄段的人群进行计数是一个常见的操作,如何使用Clickhouse快速的计算出人群的年龄分布情况呢?
1571 1
Clickhouse在画像场景如何快速计算人群的年龄分布
ClickHouse执行模型
ClickHouse执行模型
84 0
|
算法 计算机视觉
《Learning OpenCV3》ch18:相机模型与标定
省赛期间用到双目视觉的时候,只是很粗浅地调用了下API,毕竟初学而且时间紧迫。最近打算跟一个硕士生再做一个相关项目,而且也想用Stereo Vision作为毕业设计,所以很有必要了解一下其中的原理。
3127 0
|
3月前
|
XML NoSQL 数据库
【DDIA笔记】【ch2】 数据模型和查询语言 -- 概念 + 数据模型
【6月更文挑战第5天】本文探讨了数据模型的分析,关注点包括数据元素、关系及不同类型的模型(关系、文档、图)与Schema模式。查询语言的考量涉及与数据模型的关联及声明式与命令式编程。数据模型从应用开发者到硬件工程师的各抽象层次中起着简化复杂性的关键作用,理想模型应具备简洁直观和可组合性。
29 2
|
3月前
|
敏捷开发 存储 缓存
【DDIA笔记】【ch1】 可靠性、可扩展性和可维护性 -- 可维护性
【6月更文挑战第4天】本文探讨了Twitter面临的一次发推文引发的巨大写入压力问题,指出用户粉丝数分布是决定系统扩展性的关键因素。为解决此问题,Twitter采用混合策略,大部分用户推文扇出至粉丝主页时间线,而少数名人推文则单独处理。性能指标包括吞吐量、响应时间和延迟,其中高百分位响应时间对用户体验至关重要。应对负载的方法分为纵向和横向扩展,以及自动和手动调整。文章强调了可维护性的重要性,包括可操作性、简单性和可演化性,以减轻维护负担和适应变化。此外,良好设计应减少复杂性,提供预测性行为,并支持未来改动。
45 0
|
3月前
|
缓存 关系型数据库 数据库
【DDIA笔记】【ch1】 可靠性、可扩展性和可维护性 -- 可扩展性
【6月更文挑战第3天】可扩展性关乎系统应对负载增长的能力,但在产品初期过度设计可能导致失败。理解基本概念以应对可能的负载增长是必要的。衡量负载的关键指标包括日活、请求频率、数据库读写比例等。推特的扩展性挑战在于&quot;扇出&quot;,即用户关注网络的广度。两种策略包括拉取(按需查询数据库)和推送(预计算feed流)。推送方法在推特案例中更为有效,因为它减少了高流量时的实时计算压力。
39 0