热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

c#怎样从bitmap初始化image类_高效大数据开发之bitmap思想的应用

作者:xmxiong,PCG运营开发工程师数据仓库的数据统计,可以归纳为三类:增量类、累计类、留存类。而累计类又分为历史至今

624b43e387191e332e41e6e15e15f8f2.gif

作者:xmxiong,PCG 运营开发工程师

数据仓库的数据统计,可以归纳为三类:增量类、累计类、留存类。而累计类又分为历史至今的累计与最近一段时间内的累计(比如滚动月活跃天,滚动周活跃天,最近 N 天消费情况等),借助 bitmap 思想统计的模型表可以快速统计最近一段时间内的累计类与留存类。

一、背景

数据仓库的数据统计,可以归纳为三类:增量类、累计类、留存类。而累计类又分为历史至今的累计与最近一段时间内的累计(比如滚动月活跃天,滚动周活跃天,最近 N 天消费情况等),借助 bitmap 思想统计的模型表可以快速统计最近一段时间内的累计类与留存类。

二、业务场景

我们先来看几个最近一段时间内的累计类与留存类的具体业务问题,作为做大数据的你建议先不要急着往下阅读,认真思考一下你的实现方案:

1.统计最近 30 天用户的累计活跃天(每个用户在 30 天里有 N 天使用微视 app,N 为 1-30,然后将月活跃用户的 N 天加总)?

2.统计最近 7 天的用户累计使用时长?

3.统计最近 30 天有播放的累计用户数?

4.统计最近 30 天活跃用户有多少在最近 30 天里有连续 3 天及以上活跃?

5.统计 28 天前活跃用户的 1、3、7、14、28 天留存率?

三、传统解决方案

在进入本文真正主题之前,我们先来看看常规的解决思路:1.统计最近 30 天用户的累计活跃天?

--用dau表(用户ID唯一),取最近30天分区,sum(活跃日期)。
select
    sum(imp_date) active_date
  from
    weishi_dau_active_table
  where
    imp_date>=20200701
    and imp_date<&#61;20200730

2.统计最近 7 天的用户累计使用时长&#xff1f;

--用dau表(用户ID唯一)&#xff0c;取最近7天分区&#xff0c;sum(使用时长)。
select
    sum(log_time) log_time
  from
    weishi_dau_active_table
  where
    imp_date>&#61;20200701
    and imp_date<&#61;20200707

3.统计最近 30 天有播放的累计用户数&#xff1f;

--用用户播放表(用户ID唯一)&#xff0c;取最近30天分区&#xff0c;count(distinct if(播放次数>0,用户ID,null))。
select
    count(distinct if(play_vv_begin>0,qimei,null)) play_user
  from
    weishi_play_active_table
  where
    imp_date>&#61;20200701
    and imp_date<&#61;20200730

4.统计最近 30 天活跃用户有多少在最近 30 天里有连续 3 天及以上活跃&#xff1f;

--用dau表(用户ID唯一)&#xff0c;取最近30天分区&#xff0c;关联两次最近30天分区&#xff0c;关联条件右表分别为imp_date-1&#xff0c;imp_date-2。
select
    count(distinct a.qimei) active_num
  from
  ( select
        imp_date
        ,qimei
      from
        weishi_dau_active_table
      where
        imp_date>&#61;20200701
        and imp_date<&#61;20200730
   )a
  join --第一次join&#xff0c;先取出连续2天的用户&#xff0c;因为7月1日用户与7月2号-1天关联得上&#xff0c;表示一个用户在1号和2号都活跃
  ( select
        date_sub(imp_date,1) imp_date
        ,qimei
      from
        weishi_dau_active_table
      where
        imp_date>&#61;20200701
        and imp_date<&#61;20200730
   )b
   on
    a.imp_date&#61;b.imp_date
    and a.qimei&#61;b.qimei
  join --第二次join&#xff0c;取出连续3天的用户&#xff0c;因为第一次join已经取出连续两天活跃的用户了&#xff0c;再拿这些7月1日用户关联7月3日-2天关联得上&#xff0c;表示一个用户在1号和3号都活跃&#xff0c;结合第一步join得出用户至少3天连续活跃了
  ( select
        date_sub(imp_date,2) imp_date
        ,qimei
      from
        weishi_dau_active_table
      where
        imp_date>&#61;20200701
        and imp_date<&#61;20200730
   )c
   on
    a.imp_date&#61;c.imp_date
    and a.qimei&#61;c.qimei

当然这里也可以用窗口函数 lead 来实现&#xff0c;通过求每个用户后 1 条日期与后 2 条日期&#xff0c;再拿这两个日期分布 datediff 当前日期是否为日期相差 1 且相差 2 来判断是否 3 天以上活跃&#xff0c;但是这个方法也还是避免不了拿 30 天分区统计&#xff0c;统计更多天连续活跃时的扩展性不好的情况 5.统计 28 天前活跃用户的 1、3、7、14、28 天留存率&#xff1f;

--用dau表(用户ID唯一)&#xff0c;取统计天的活跃用户 left join 1、3、7、14、28天后的活跃用户&#xff0c;关联得上则说明对应天有留存。
select
    &#39;20200701&#39; imp_date
    ,count(distinct if(date_sub&#61;1,b.qimei,null))/count(distinct a.qimei) 1d_retain_rate
    ,count(distinct if(date_sub&#61;3,b.qimei,null))/count(distinct a.qimei) 3d_retain_rate
    ,count(distinct if(date_sub&#61;7,b.qimei,null))/count(distinct a.qimei) 7d_retain_rate
    ,count(distinct if(date_sub&#61;14,b.qimei,null))/count(distinct a.qimei) 14d_retain_rate
    ,count(distinct if(date_sub&#61;28,b.qimei,null))/count(distinct a.qimei) 28d_retain_rate
  from
    weishi_dau_active_table partition (p_20200701)a
  left join
  ( select
        datediff(imp_date,&#39;20200701&#39;) date_sub
        ,qimei
      from
        weishi_dau_active_table
      where
        datediff(imp_date,&#39;20200701&#39;) in (1,3,7,14,28)
   )b
   on
    a.qimeib&#61;b.qimei

四、传统解决方案存在的问题

1.每天大量中间数据重复计算&#xff0c;比如昨天最近 30 天是 8 月 1 日&#xff5e; 8 月 30 日&#xff0c;今天最近 30 天为 8 月 2 日&#xff5e; 8 月 31 日&#xff0c;中间 8 月 2 日&#xff5e; 8 月 30 日就重复计算了。

2.统计逻辑复杂&#xff0c;类似业务场景 4&#xff0c;困难点在于统计每一天活跃的用户第二天是否还继续活跃。

3.耗费集群资源大&#xff0c;场景 4 和场景 5 都用到了 join 操作&#xff0c;场景 4 还不止一个 join&#xff0c;join 操作涉及 shuffle 操作&#xff0c;shuffle 操作需要大量的网络 IO 操作&#xff0c;因此在集群中是比较耗性能的&#xff0c;我们应该尽量避免执行这样的操作。

4.以上统计逻辑可扩展性差&#xff0c;由于数据分析经常进行探索性分析&#xff0c;上面传统方案能解决上面几个问题&#xff0c;但是数据分析稍微改变一下需求&#xff0c;就得重新开发&#xff0c;例如增加一个 15 天留存&#xff0c;或者统计最近 2 周的活跃天等。

五、bitmap 原理

上面的业务场景能否在一个模型表很简单就能统计出&#xff0c;且不需要数据重复计算&#xff0c;也不需要 join 操作&#xff0c;还能满足数据分析更多指标探索分析呢&#xff1f;答案是肯定的&#xff0c;可以借助 bitmap 思想。

何为 bitmap&#xff1f;bitmap 就是用一个 bit 位来标记某个元素&#xff0c;而数组下标是该元素&#xff0c;该元素是否存在时用 bit 位的 1,0 表示。比如 10 亿个 int 类型的数&#xff0c;如果用 int 数组存储的话&#xff0c;那么需要大约 4G 内存&#xff0c;当我们用 int 类型来模拟 bitmap 时&#xff0c;一个 int 4 个字节共 4*8 &#61; 32 位&#xff0c;可以表示 32 个数&#xff0c;原来 10 亿个 int 类型的数用 bitmap 只需要 4GB / 32 &#61; 128 MB 的内存。

c6acca27a5d0c83b9b2ae6993bc497c1.png

六、具体实现过程

大数据开发参考 bitmap 思想&#xff0c;就是参考其通过数组下标表示该元素的思想&#xff0c;将最近 31 天活跃用户是否活跃用逗号分隔的 0 1 串存储下来&#xff0c;将最近 31 天的播放 vv、赞转评等消费数也用逗号分隔的具体数值存储下来&#xff0c;形成一个字符数组&#xff0c;数组每一个下标表示距离最新一天数据的天数差值&#xff0c;第一位下标为 0&#xff0c;表示距离今天最新一天数据间隔为 0 天&#xff0c;如下所示&#xff1a;

7a47aeb8519444719b62e1cf35918020.png

active_date_set 表示 31 天活跃集&#xff0c;0 表示对应下标(距离今天的 N 天前)不活跃&#xff0c;1 表示活跃&#xff1b;这个数据是 8 月 23 日统计的&#xff0c;1,0,0,1,…… 即用户在 8 月 23 日&#xff0c;8 月 20 日有活跃&#xff0c;8 月 22 日&#xff0c;8 月 21 日并没有活跃。play_vv_begin_set 表示 31 天播放 vv 集&#xff0c;0 表示对应下标(距离今天的 N 天前)没有播放视频&#xff0c;正整数表示当天的播放视频次数&#xff1b;这里用户虽然在 8 月 23 日&#xff0c;8 月 20 日有活跃&#xff0c;但是该用户一天只播放了一次视频就离开微视了。这样做的好处一方面也是大大压缩了存储&#xff0c;极端状态下用户 31 天都来&#xff0c;那么就可以将 31 行记录压缩在一行存储。

假如 1 天活跃用户 1 亿&#xff0c;且这些用户 31 天都活跃&#xff0c;那么就可以将 31 亿行记录压缩在 1 亿行里&#xff0c;当然实际不会出现这样的情况&#xff0c;因为会有一部分老用户流失&#xff0c;一部分新用户加入&#xff0c;按照目前微视的统计可以节省 80%多的存储&#xff1b;另一方面可以更简单快捷地统计每个用户最近一个月在微视的活跃与播放、消费(赞转评)等情况。

该模型表的详细实现过程如下&#xff1a; 

1.该模型表的前 31 天需要初始化一个集合&#xff0c;将第一天的数据写到该表&#xff0c;然后一天一天滚动垒起来&#xff0c;累计 31 天之后就得到这个可用的集合表了&#xff0c;也就可以例行化跑下去。

2.最新一天需要统计时&#xff0c;需要拿前一天的集合表&#xff0c;剔除掉相对今天来说第 31 天前的数据&#xff0c;然后每个集合字段将最后一位删除掉 。

3.拿最新一天的增量数据(下面用 A 表替代) full join 第 2 步处理后的前一天表(下面用 B 表替代)关联。

这里有三种情况需要处理&#xff1a;

a.既出现在 A 表&#xff0c;也出现在 B 表&#xff0c;这种情况&#xff0c;只需直接拼接 A 表的最新值与 B 表的数组集即可(在微视里就是最近 30 天用户有活跃&#xff0c;且在最新一天有留存)&#xff1b;

b.只出现在 B 表(在微视里是最近 30 天活跃的用户在最新一天没留存)&#xff0c;这时需要拿 “0,” 拼接一个 B 表的数组集&#xff0c;“0,” 放在第一位&#xff1b;

c.只出现在 A 表(在微视里是新用户或者 31 天前活跃的回流用户)&#xff0c;这时需要拿 “1,”拼接一个 30 位长的默认数组集 “0,0,0,…,0,0” &#xff0c;“1,” 放在第一位。经过如此几步&#xff0c;就可以生成最新一天的集合表了&#xff0c;具体脱敏代码如下&#xff1a;

select
    20200823 imp_date
    ,nvl(a.qimei,b.qimei) qimei
    ,case
       when a.qimei&#61;b.qimei then concat(b.active_date_set,&#39;,&#39;,a.active_date_set)
       when b.qimei is null then concat(&#39;0,&#39;,a.active_date_set)
       when a.qimei is null then concat(b.active_date_set,&#39;,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0&#39;)
      end active_date_set
    ,case
       when a.qimei&#61;b.qimei then concat(b.log_num_set,&#39;,&#39;,a.log_num_set)
       when b.qimei is null then concat(&#39;0,&#39;,a.log_num_set)
       when a.qimei is null then concat(b.log_num_set,&#39;,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0&#39;)
      end log_num_set
    ,case
       when a.qimei&#61;b.qimei then concat(b.log_time_set,&#39;,&#39;,a.log_time_set)
       when b.qimei is null then concat(&#39;0,&#39;,a.log_time_set)
       when a.qimei is null then concat(b.log_time_set,&#39;,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0&#39;)
      end log_time_set
    ,case
       when a.qimei&#61;b.qimei then concat(b.play_vv_begin_set,&#39;,&#39;,a.play_vv_begin_set)
       when b.qimei is null then concat(&#39;0,&#39;,a.play_vv_begin_set)
       when a.qimei is null then concat(b.play_vv_begin_set,&#39;,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0&#39;)
      end play_vv_begin_set
  from
  ( select
        qimei
        ,substr(active_date_set,1,instr(active_date_set,&#39;,&#39;,1,30)-1) active_date_set
        ,substr(log_num_set,1,instr(log_num_set,&#39;,&#39;,1,30)-1) log_num_set
        ,substr(log_time_set,1,instr(log_time_set,&#39;,&#39;,1,30)-1) log_time_set
        ,substr(play_vv_begin_set,1,instr(play_vv_begin_set,&#39;,&#39;,1,30)-1) play_vv_begin_set
      from
        weishi_31d_active_set_table partition(p_20200822)a
      where
        last_time>&#61;20200723
   )a
  full join
  ( select
        qimei
        ,&#39;1&#39; active_date_set
        ,cast(log_num as string) log_num_set
        ,cast(log_time as string) log_time_set
        ,cast(play_vv_begin as string) play_vv_begin_set
      from
        weishi_dau_active_table partition(p_20200823)a
   )b
   on
    a.qimei&#61;b.qimei

初始化集合代码相对简单&#xff0c;只需保留第一位为实际数值&#xff0c;然后拼接一个 30 位的默认值 0 串&#xff0c;初始化脱敏代码如下&#xff1a;

select
    20200823 imp_date
    ,qimei
    ,&#39;1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0&#39; active_date_set
    ,concat(cast(log_num as string),&#39;,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0&#39;) log_num_set
    ,concat(cast(log_time as string),&#39;,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0&#39;) log_time_set
    ,concat(cast(play_vv_begin as string),&#39;,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0&#39;) play_vv_begin_set
  from
    weishi_dau_active_table partition(p_20200823)a

七、具体使用案例

在 hive 里对这些 0 1 集合串的使用是比较困难的&#xff0c;为了让这个模型表的可用性更高&#xff0c;因此写了几个 UDF 函数来直接对数组集合进行简单地运算&#xff0c;目前写了如下几个&#xff1a;str_sum()、str_count()、str_min()、str_max()&#xff0c;其中 str_sum、str_min、str_max 这几个函数的参数一样&#xff0c;第一个传入一个数组集合字符串&#xff0c;第二位传入一个整数&#xff0c;代表要计算最近 N 天的结果&#xff0c;第三个参数是传入一个分隔符&#xff0c;在本模型里分隔符均为逗号“,”。

这几个函数都是返回一个 int 值&#xff0c;str_sum 返回来的是最近 N 天的数值加总&#xff0c;str_min 返回该数组集合元素里最小的值&#xff0c;str_max 返回该数组集合元素里最大的值&#xff1b;str_count 前 3 个参数与前面三个函数一样&#xff0c;第 4 个参数是传入要统计的值&#xff0c;返回来的也是 int 值&#xff0c;返回传入的统计值在数组集合出现的次数&#xff0c;具体使用方法如下&#xff0c;由于是自定义函数&#xff0c;在 tdw 集群跑的 sql 前面需加&#64;pyspark&#xff1a;

83e6ce8abfe13eb047d0a3c51e37ebde.png

以上函数的具体使用案例脱敏代码如下&#xff1a;

&#64;pysparkselect
    qimei
    ,str_sum(active_date_set,30,&#39;,&#39;) active_date_num  --每个用户最近30天活跃天数
    ,str_sum(play_vv_begin_set,30,&#39;,&#39;) play_vv_begin  --每个用户最近30天播放视频次数
    ,30 - str_count(interact_num_set,30,&#39;,&#39;,&#39;0&#39;) interact_date_num  --每个用户最近30天有互动的天数&#xff0c;通过 30 - 互动天数为0 统计得到
  from
    weishi_31d_active_set_table partition(p_20200823)a
  where
    last_time>20200724

当然除了上面几种 udf 统计所需指标之外&#xff0c;也可以通过正则表达式进行使用&#xff0c;比如统计活跃天可以这样统计&#xff1a;

--将数组集合里的&#39;0&#39;和&#39;,&#39;用正则表达式匹配去掉再来看剩下1的个数即可。
select
    count(qimei) --月活
    ,sum(length(regexp_replace(substr(active_date_set,1,60),&#39;0|,&#39;,&#39;&#39;))) active_date_num  --月活跃天
  from
    weishi_31d_active_set_table partition(p_20200823)a
  where
    last_time>20200724

开篇前的几个业务场景&#xff0c;也可以通过该表快速统计&#xff1a;1.统计最近 30 天用户的累计活跃天&#xff1f;

&#64;pyspark
select
    sum(active_date_num) active_date_num  --滚动月活跃天
    ,count(1) uv  --滚动月活
  from
  ( select
        qimei
        ,str_sum(active_date_set,30,&#39;,&#39;) active_date_num
      from
        weishi_31d_active_set_table partition(p_20200823)a
      where
        last_time>20200724
   )a

2.统计最近 7 天的用户累计使用时长&#xff1f;

&#64;pyspark
select
    sum(log_time) log_time  --滚动周活跃天
    ,count(1) uv  --滚动周活
  from
  ( select
        qimei
        ,str_sum(log_time_set,7,&#39;,&#39;) log_time
      from
        weishi_31d_active_set_table partition(p_20200823)a
      where
        last_time>20200817
   )a

3.统计最近 30 天有播放的累计用户数&#xff1f;

&#64;pyspark
select
    count(1) uv  --播放次数>0
  from
  ( select
        qimei
        ,str_sum(play_vv_begin_set,30,&#39;,&#39;,&#39;0&#39;) play_vv_begin
      from
        weishi_31d_active_set_table partition(p_20200823)a
      where
        last_time>20200724
   )a
  where
    play_vv_begin>0

4.统计最近 30 天活跃用户有多少在最近 30 天里有连续 3 天及以上活跃&#xff1f;

--只是判断活跃集合里面有连续3位 1,1,1, 即可select
    count(if(substr(active_date_set,1,60) like &#39;%1,1,1,%&#39;,qimei,null)) active_date_num
  from
    weishi_31d_active_set_table partition(p_20200823)a
  where
    last_time>20200724

5.统计 28 天前活跃用户的 1、3、7、14、28 天留存率&#xff1f;

--不需要join操作&#xff0c;只需找到活跃日期集对应位是否1即可select
    &#39;20200723&#39; imp_date
    ,count(if(split(active_date_set,&#39;,&#39;)[&#39;29&#39;]&#61;&#39;1&#39;,qimei,null))/count(1) 1d_retain_rate
    ,count(if(split(active_date_set,&#39;,&#39;)[&#39;27&#39;]&#61;&#39;1&#39;,qimei,null))/count(1) 3d_retain_rate
    ,count(if(split(active_date_set,&#39;,&#39;)[&#39;23&#39;]&#61;&#39;1&#39;,qimei,null))/count(1) 7d_retain_rate
    ,count(if(split(active_date_set,&#39;,&#39;)[&#39;16&#39;]&#61;&#39;1&#39;,qimei,null))/count(1) 14d_retain_rate
    ,count(if(split(active_date_set,&#39;,&#39;)[&#39;2&#39;]&#61;&#39;1&#39;,qimei,null))/count(1) 28d_retain_rate
  from
    weishi_31d_active_set_table partition(p_20200823)a
  where
    last_time>20200723
    and split(active_date_set,&#39;,&#39;)[&#39;30&#39;]&#61;&#39;1&#39;

八、总结

从上面 5 个业务场景可以看出来&#xff0c;只要有这样一个借助 bitmap 思想统计的模型表&#xff0c;不管统计最近一段时间的累计(月活跃天、月播放用户等)与统计 1 个月内的留存&#xff0c;都可以一条简单语句即可统计&#xff0c;不需要 join 操作&#xff0c;每天例行化跑时不需要重复跑接近一个月的分区&#xff0c;1 个月内可以支持任意统计&#xff0c;比如只需最近 2 周的活跃天等&#xff0c;因此这样的模型相对通用&#xff0c;另外如果业务需要用到 2 个月的数据&#xff0c;也可以将模型从 31 位扩展到 61 位。

当然任何事情不可能只有优点&#xff0c;而不存在缺点的情况&#xff0c;这里这个优化的模型只是参考了 bitmap 思想&#xff0c;并不是 bitmap 方案实现&#xff0c;虽然可以将 31 天活跃用户压缩 80%多存储&#xff0c;但是每天都存储 31 天活跃用户的压缩数据&#xff0c;因此相比之前只保留天增量表来说&#xff0c;还是增加了实际存储空间&#xff0c;但是这个以存储换计算的方案是符合数仓设计原则的&#xff0c;因为计算是用成本昂贵的 cpu 和内存资源&#xff0c;存储是用成本低廉的磁盘资源&#xff0c;因此有涉及最近 N 天累计或者留存计算需求的朋友可以借鉴这样的思路。

9073f4ec7b52367684db97ec5c0cc7dc.gif●数据挖掘原理与实战(一)--关联规则Apriori算法

●Spark原理与实战--数据抽象DataFrame(五)

●Spark原理与实战--数据抽象RDD(四)

●Spark原理与实战--GraphX图查询(三)

●Spark原理与实战--SparkStreaming流处理(二)

●Spark原理与实战--环境搭建及WordCount(一)

●Spark数据倾斜解决方案实战(二)

●Spark数据倾斜解决方案实战(一)

●大数据计算生态之数据计算(二)

●大数据计算生态之数据计算(一)

●大数据计算生态之数据存储

36c6a48b77689acf869e17c77c971686.png

文章都看完了69449f93ba26b8ae41a15cb7f5e1cdea.gif不点个90ec5d7ed0ef6320f8eac5ed957dc466.png 吗

欢迎    点赞、在看、分享  三连哦&#xff5e;&#xff5e;




推荐阅读
  • 探索偶数次幂二项式系数的求和方法及其数学意义 ... [详细]
  • 利用Python进行学生学业表现评估与成绩预测分析
    利用Python进行学生学业表现评估与成绩预测分析 ... [详细]
  • Ihavetwomethodsofgeneratingmdistinctrandomnumbersintherange[0..n-1]我有两种方法在范围[0.n-1]中生 ... [详细]
  • 单片微机原理P3:80C51外部拓展系统
      外部拓展其实是个相对来说很好玩的章节,可以真正开始用单片机写程序了,比较重要的是外部存储器拓展,81C55拓展,矩阵键盘,动态显示,DAC和ADC。0.IO接口电路概念与存 ... [详细]
  • 本文详细介绍了MySQL数据库的基础语法与核心操作,涵盖从基础概念到具体应用的多个方面。首先,文章从基础知识入手,逐步深入到创建和修改数据表的操作。接着,详细讲解了如何进行数据的插入、更新与删除。在查询部分,不仅介绍了DISTINCT和LIMIT的使用方法,还探讨了排序、过滤和通配符的应用。此外,文章还涵盖了计算字段以及多种函数的使用,包括文本处理、日期和时间处理及数值处理等。通过这些内容,读者可以全面掌握MySQL数据库的核心操作技巧。 ... [详细]
  • 本报告对2018年湘潭大学程序设计竞赛在牛客网上的时间数据进行了详细分析。通过统计参赛者在各个时间段的活跃情况,揭示了比赛期间的编程频率和时间分布特点。此外,报告还探讨了选手在准备过程中面临的挑战,如保持编程手感、学习逆向工程和PWN技术,以及熟悉Linux环境等。这些发现为未来的竞赛组织和培训提供了 valuable 的参考。 ... [详细]
  • 如何将Python与Excel高效结合:常用操作技巧解析
    本文深入探讨了如何将Python与Excel高效结合,涵盖了一系列实用的操作技巧。文章内容详尽,步骤清晰,注重细节处理,旨在帮助读者掌握Python与Excel之间的无缝对接方法,提升数据处理效率。 ... [详细]
  • 您的数据库配置是否安全?DBSAT工具助您一臂之力!
    本文探讨了Oracle提供的免费工具DBSAT,该工具能够有效协助用户检测和优化数据库配置的安全性。通过全面的分析和报告,DBSAT帮助用户识别潜在的安全漏洞,并提供针对性的改进建议,确保数据库系统的稳定性和安全性。 ... [详细]
  • 如何将TS文件转换为M3U8直播流:HLS与M3U8格式详解
    在视频传输领域,MP4虽然常见,但在直播场景中直接使用MP4格式存在诸多问题。例如,MP4文件的头部信息(如ftyp、moov)较大,导致初始加载时间较长,影响用户体验。相比之下,HLS(HTTP Live Streaming)协议及其M3U8格式更具优势。HLS通过将视频切分成多个小片段,并生成一个M3U8播放列表文件,实现低延迟和高稳定性。本文详细介绍了如何将TS文件转换为M3U8直播流,包括技术原理和具体操作步骤,帮助读者更好地理解和应用这一技术。 ... [详细]
  • 提升视觉效果:Unity3D中的HDR与Bloom技术(高动态范围成像与光线散射)
    提升视觉效果:Unity3D中的HDR与Bloom技术(高动态范围成像与光线散射) ... [详细]
  • POJ 2482 星空中的星星:利用线段树与扫描线算法解决
    在《POJ 2482 星空中的星星》问题中,通过运用线段树和扫描线算法,可以高效地解决星星在窗口内的计数问题。该方法不仅能够快速处理大规模数据,还能确保时间复杂度的最优性,适用于各种复杂的星空模拟场景。 ... [详细]
  • Python内置模块详解:正则表达式re模块的应用与解析
    正则表达式是一种强大的文本处理工具,通过特定的字符序列来定义搜索模式。本文详细介绍了Python内置的`re`模块,探讨了其在字符串匹配、验证和提取中的应用。例如,可以通过正则表达式验证电子邮件地址、电话号码、QQ号、密码、URL和IP地址等。此外,文章还深入解析了`re`模块的各种函数和方法,提供了丰富的示例代码,帮助读者更好地理解和使用这一工具。 ... [详细]
  • 技术日志:使用 Ruby 爬虫抓取拉勾网职位数据并生成词云分析报告
    技术日志:使用 Ruby 爬虫抓取拉勾网职位数据并生成词云分析报告 ... [详细]
  • 本文详细介绍了在C#编程环境中绘制正方形图像的技术和实现方法,通过具体示例代码帮助读者理解和掌握相关技巧。内容涵盖从基础概念到实际应用的各个方面,适合初学者和有一定经验的开发者参考。希望对您的C#学习之旅有所帮助,并激发您进一步探索的兴趣。 ... [详细]
  • 在C#中开发MP3播放器时,我正在考虑如何高效存储元数据以便快速检索。选择合适的数据结构,如字典或数组,对于优化性能至关重要。字典能够提供快速的键值对查找,而数组则在连续存储和遍历方面表现优异。根据具体需求,合理选择数据结构将显著提升应用的响应速度和用户体验。 ... [详细]
author-avatar
elgin2010
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有