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

怎么用bitmap实现用户画像的标签圈人功能

本篇内容介绍了“怎么用bitmap实现用户画像的标签圈人功能”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带

本篇内容介绍了“怎么用bitmap实现用户画像的标签圈人功能”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

标签有哪些类型呢?

枚举类标签: 描述性别,地理位置。这类标签取值通常是可枚举出来的。
时间类标签: 描述业务触达和流失时间信息。 注: 时间类标签可存储成数值。
数值类标签: 比如账户金额,积分数量等。

所以本质上,标签只有两种: 离散枚举和连续数值。

有了标签后,如何在计算机中建模存储呢?

最简单最直观的方式就是设置大宽表,即每个标签一个字段。 通常一个小型的画像系统,有几百个标签足够。所以对于大部分场景宽表足够简单可依赖。

宽表一般存储在Hive中,出于性能考虑,会存储到Impala中。当数据量较大时,Impala也一般无法满足查询的性能需求。这是因为Impala没有索引,每次查询都是扫表。所以,为了能够利用索引提升性能,大宽表一般会从Impala转存到Elasticsearch中。

当一个用户Id附着成百上千个标签,按ES存储方式,会相当耗费存储资源,导入数据到ES也会成为性能瓶颈。 所以变通的方案是将所有的标签存储到ES的一个array字段中。但本质上,还是大宽表的方案。

大宽表的方案最大的问题: 新增标签时间成本太大,所以画像系统基本是T+1的实效性。 如果对响应时间没有苛刻的要求,基于Hadoop生态的ad hoc查询引擎构建宽表,比如Impala或presto是可以使用多张宽表来解决新曾标签T+0生效问题,毕竟大数据系统,存储资源还是很充足的。

可惜的是业务对系统的需求是: 更高,更快,更强,像体育运动一样。

我们用ES存储标签,查询速度快的原因是ES构建了倒排索引。我们构建标签时,标签数据的主体是用户ID, 而在ES的世界,站在倒排索引的角度,标签数据的主体是标签,这完全是两个对立面。

我们使用标签圈人,本质上是集合的交并补运算。  所以,我们可以干脆再往前迈一步: 直接构建标签-用户ID的映射关系,而非原始的用户ID-标签

这样,整个数据结构就变成类似如下的样式:

男: 张三,李四,王五...

由于一个标签可以圈定上亿的用户,如何存储这样的结构?  RoaringBitmap 。这样存储后,标签圈人就脱离了SQL和ES语法,还原到最本质的集合运算:A and B or (C and D)

使用标签-用户ID这种数据建模方式,有个很大的问题: 数值类标签的处理。比如用户积分。 通常有一种解决方法就是分段,然而这样做损失了数据精度。变得不灵活了。还有一种解决方法是为每个值建立一个bitmap。 这样做一则耗费空间,二则无法很好处理区间查询的问题。

使用标签-用户ID这种方式, bitmap存储数据关系是标签值等于XXX的用户ID, 提取核心点bitmap存储的是等于关系。 那么bitmap存储大于或者小于关系也是可以的。

对于数值型标签,我们重新定义存储关系: bitmap(2) 表示value值大于2的所有用户ID。 同理, bitmap(5) 表示value值大于5的所有用户ID。这样的话,计算value=(3,1000)之间的用户,使用bitmap(3) andNot bitmap(999)就可以了。很好地解决了区间查询的问题。 依然遗留了一个问题: 需要为每个值准备一个bitmap。

这个问题的解决思路很巧妙: 多个bitmap组合表示一个数值。例如200, 拆分成个位,十位,百位3个部分,每一部分用10个bitmap存储。这样就能够把bitmap的数量控制在有限的数量里面。比如对于int整型,最多需要100个bitmap。

优化是没有止尽的,我们还能走得更远。如果数值采用二进制表示,那么每一位只需要2个bitmap, 一个Int类型最多需要64个bitmap。 采用二进制,存储的规则可以如下设置:

bitmap(0)表示该位为0的用户ID集合。
bitmap(1)表示该位为0或1的用户ID集合。

由于对于二进制的某一位,取值只有0和1两种可能,所以对于二进制,每一位只需要bitmap(0), 所以最多需要32+1=33个bitmap存储。

综上, 我们解决bitmap数量的问题,也解决了区间查询的问题。但是多位二进制组合处理区间查询,又引出了新的问题: 多个bitmap如何组合表示一个区间?

我们把问题再简化一下,多个bitmap如何表示一个小于等于的区间。 比如i<7 如何用bitmap表示? 再回顾bitmap的存储规则:

bitmap(0)表示该位为0的用户ID集合。
bitmap(1)表示该位为0或1的用户ID集合。

我们按从右到左的顺序给bitmap位取名字,下标从1开始。 例如01,有两位,分别是b2,b1。

这样的话: i<7 = i<0111, 用bitmap表示就是b4。 再举几个例子:

i<5 = i < 0101, 用bitmap表示就是 (b4 and b2) or (b4 and b3)

为了理解这个过程,我自己画了如下的横向树形图:

      1
   1
      0
0
      1
   0  
      0

来观察这个规律,最后实现的代码如下:

import lombok.Data;
import org.roaringbitmap.RoaringBitmap;

import java.util.*;

public class RangeBitmapDemo2 {

    @Data
    private static class QueryCond{

        private List base = new ArrayList<>();

        private List> lowerRange = new ArrayList();

        public void addBase(String val){
            this.base.add(val);
        }

        public void addLowerRange(String val){
            List list = new ArrayList();
            list.addAll(base);
            list.add(val);
            this.lowerRange.add(list);
        }
    }

    public static void query(int upper, int binaryLength){
        String val =String.format("%"+binaryLength+"s", Integer.toBinaryString(upper)).replaceAll(" ","0"); //这里可以补空格
        System.out.println("query: upper is "+val);

        QueryCond cond = new QueryCond();

        char cur = val.charAt(0);

        if(cur==&#39;0&#39;){
            cond.addBase("b"+binaryLength);
        }

        for(int i=1;i=0 && val.charAt(back)==&#39;1&#39;){
                    cond.addLowerRange("b"+(binaryLength-back));
                    back -=1;
                }
                cond.addBase("b"+(binaryLength-i));
            }
        }

        System.out.println("query cond: "+cond);

    }

    public static void main(String[] args) {

        for(int i=0;i<32;i++){
            query(i, 6);
        }
    }
}

打印的结果

query: upper is 000110
RangeBitmapDemo2.QueryCond(base=[b6, b5, b4, b1], lowerRange=[[b6, b5, b4, b2], [b6, b5, b4, b3]])

表示000110的组合关系为(b6 & b5 & b4 & b3 & b2 & b1)  or (b6 & b5 & b4 & b2) or (b6 & b5 & b4 & b3) 即整个结果由3个部分组合而成。

“怎么用bitmap实现用户画像的标签圈人功能”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程笔记网站,小编将为大家输出更多高质量的实用文章!


推荐阅读
  • 本文介绍了使用cacti监控mssql 2005运行资源情况的操作步骤,包括安装必要的工具和驱动,测试mssql的连接,配置监控脚本等。通过php连接mssql来获取SQL 2005性能计算器的值,实现对mssql的监控。详细的操作步骤和代码请参考附件。 ... [详细]
  • 合并列值-合并为一列问题需求:createtabletab(Aint,Bint,Cint)inserttabselect1,2,3unionallsel ... [详细]
  • 一、Hadoop来历Hadoop的思想来源于Google在做搜索引擎的时候出现一个很大的问题就是这么多网页我如何才能以最快的速度来搜索到,由于这个问题Google发明 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • HDFS2.x新特性
    一、集群间数据拷贝scp实现两个远程主机之间的文件复制scp-rhello.txtroothadoop103:useratguiguhello.txt推pushscp-rr ... [详细]
  • EzPP 0.2发布,新增YAML布局渲染功能
    EzPP发布了0.2.1版本,新增了YAML布局渲染功能,可以将YAML文件渲染为图片,并且可以复用YAML作为模版,通过传递不同参数生成不同的图片。这个功能可以用于绘制Logo、封面或其他图片,让用户不需要安装或卸载Photoshop。文章还提供了一个入门例子,介绍了使用ezpp的基本渲染方法,以及如何使用canvas、text类元素、自定义字体等。 ... [详细]
  • EPPlus绘制刻度线的方法及示例代码
    本文介绍了使用EPPlus绘制刻度线的方法,并提供了示例代码。通过ExcelPackage类和List对象,可以实现在Excel中绘制刻度线的功能。具体的方法和示例代码在文章中进行了详细的介绍和演示。 ... [详细]
  • 十大经典排序算法动图演示+Python实现
    本文介绍了十大经典排序算法的原理、演示和Python实现。排序算法分为内部排序和外部排序,常见的内部排序算法有插入排序、希尔排序、选择排序、冒泡排序、归并排序、快速排序、堆排序、基数排序等。文章还解释了时间复杂度和稳定性的概念,并提供了相关的名词解释。 ... [详细]
  • Python使用Pillow包生成验证码图片的方法
    本文介绍了使用Python中的Pillow包生成验证码图片的方法。通过随机生成数字和符号,并添加干扰象素,生成一幅验证码图片。需要配置好Python环境,并安装Pillow库。代码实现包括导入Pillow包和随机模块,定义随机生成字母、数字和字体颜色的函数。 ... [详细]
  • 超级简单加解密工具的方案和功能
    本文介绍了一个超级简单的加解密工具的方案和功能。该工具可以读取文件头,并根据特定长度进行加密,加密后将加密部分写入源文件。同时,该工具也支持解密操作。加密和解密过程是可逆的。本文还提到了一些相关的功能和使用方法,并给出了Python代码示例。 ... [详细]
  • 本文介绍了贝叶斯垃圾邮件分类的机器学习代码,代码来源于https://www.cnblogs.com/huangyc/p/10327209.html,并对代码进行了简介。朴素贝叶斯分类器训练函数包括求p(Ci)和基于词汇表的p(w|Ci)。 ... [详细]
  • 本文介绍了在sqoop1.4.*版本中,如何实现自定义分隔符的方法及步骤。通过修改sqoop生成的java文件,并重新编译,可以满足实际开发中对分隔符的需求。具体步骤包括修改java文件中的一行代码,重新编译所需的hadoop包等。详细步骤和编译方法在本文中都有详细说明。 ... [详细]
  • 11月26日,由中国计算机协会(CCF)主办,CCF大数据专家委员会协办,CSDN承办的Hadoop与大数据技术大会(Hadoop&BigDataTechnology ... [详细]
author-avatar
勇淑丁
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有