很多数据开发者使用bitmap技术对用户数据进行编码和压缩,然后利用bitmap的与/或/非的极速处理速度,实现类似用户画像标签的人群筛选、运营分析的7日活跃等分析。
本文给出了一个使用MaxCompute MapReduce开发一个对不同日期活跃用户ID进行bitmap编码和计算的样例。供感兴趣的用户进一步了解、分析,并应用在自己的场景下。


import com.aliyun.odps.OdpsException;
import com.aliyun.odps.data.Record;
import com.aliyun.odps.data.TableInfo;
import com.aliyun.odps.mapred.JobClient;
import com.aliyun.odps.mapred.MapperBase;
import com.aliyun.odps.mapred.ReducerBase;
import com.aliyun.odps.mapred.conf.JobConf;
import com.aliyun.odps.mapred.utils.InputUtils;
import com.aliyun.odps.mapred.utils.OutputUtils;
import com.aliyun.odps.mapred.utils.SchemaUtils;
import org.roaringbitmap.RoaringBitmap;
import org.roaringbitmap.buffer.ImmutableRoaringBitmap; import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.util.Base64;
import java.util.Iterator; public class bitmapDemo2
{ public static class BitMapper extends MapperBase { Record key;
Record value;
@Override
public void setup(TaskContext context) throws IOException {
key = context.createMapOutputKeyRecord();
value = context.createMapOutputValueRecord();
} @Override
public void map(long recordNum, Record record, TaskContext context)
throws IOException
{
RoaringBitmap mrb=new RoaringBitmap();
long AID=0;
{
{
{
{
AID=record.getBigint("id");
mrb.add((int) AID);
//获取key
key.set(new Object[] {record.getString("active_date")}); }
}
}
}
ByteBuffer outbb = ByteBuffer.allocate(mrb.serializedSizeInBytes());
mrb.serialize(new DataOutputStream(new OutputStream(){
ByteBuffer mBB;
OutputStream init(ByteBuffer mbb) {mBB=mbb; return this;}
public void close() {}
public void flush() {}
public void write(int b) {
mBB.put((byte) b);}
public void write(byte[] b) {mBB.put(b);}
public void write(byte[] b, int off, int l) {mBB.put(b,off,l);}
}.init(outbb)));
String serializedstring = Base64.getEncoder().encodeToString(outbb.array());
value.set(new Object[] {serializedstring});
context.write(key, value);
}
} public static class BitReducer extends ReducerBase {
private Record result = null; public void setup(TaskContext context) throws IOException {
result = context.createOutputRecord();
} public void reduce(Record key, Iterator<Record> values, TaskContext context) throws IOException {
long fcount = 0;
RoaringBitmap rbm=new RoaringBitmap();
while (values.hasNext())
{
Record val = values.next();
ByteBuffer newbb = ByteBuffer.wrap(Base64.getDecoder().decode((String)val.get(0)));
ImmutableRoaringBitmap irb = new ImmutableRoaringBitmap(newbb);
RoaringBitmap p= new RoaringBitmap(irb);
rbm.or(p);
}
ByteBuffer outbb = ByteBuffer.allocate(rbm.serializedSizeInBytes());
rbm.serialize(new DataOutputStream(new OutputStream(){
ByteBuffer mBB;
OutputStream init(ByteBuffer mbb) {mBB=mbb; return this;}
public void close() {}
public void flush() {}
public void write(int b) {
mBB.put((byte) b);}
public void write(byte[] b) {mBB.put(b);}
public void write(byte[] b, int off, int l) {mBB.put(b,off,l);}
}.init(outbb)));
String serializedstring = Base64.getEncoder().encodeToString(outbb.array());
result.set(0, key.get(0));
result.set(1, serializedstring);
context.write(result);
}
}
public static void main( String[] args ) throws OdpsException
{ System.out.println("begin.........");
JobConf job = new JobConf(); job.setMapperClass(BitMapper.class);
job.setReducerClass(BitReducer.class); job.setMapOutputKeySchema(SchemaUtils.fromString("active_date:string"));
job.setMapOutputValueSchema(SchemaUtils.fromString("id:string")); InputUtils.addTable(TableInfo.builder().tableName("bitmap_source").cols(new String[] {"id","active_date"}).build(), job);
// +------------+-------------+
// | id | active_date |
// +------------+-------------+
// | 1 | 20190729 |
// | 2 | 20190729 |
// | 3 | 20190730 |
// | 4 | 20190801 |
// | 5 | 20190801 |
// +------------+-------------+
OutputUtils.addTable(TableInfo.builder().tableName("bitmap_target").build(), job);
// +-------------+------------+
// | active_date | bit_map |
// +-------------+------------+
// 20190729,OjAAAAEAAAAAAAEAEAAAAAEAAgA=3D
// 20190730,OjAAAAEAAAAAAAAAEAAAAAMA
// 20190801,OjAAAAEAAAAAAAEAEAAAAAQABQA=3D JobClient.runJob(job);
}
}

对Java应用打包后,上传到MaxCompute项目中,即可在MaxCompute中调用该MR作业,对输入表的数据按日期作为key进行用户id的编码,同时按照相同日期对bitmap后的用户id取OR操作(根据需要可以取AND,例如存留场景),并将处理后的数据写入目标结构表当中供后续处理使用。

本文作者:圣远

原文链接

本文为云栖社区原创内容,未经允许不得转载。

在MaxCompute中利用bitmap进行数据处理的更多相关文章

  1. Android中利用C++处理Bitmap对象

    相信有些Android&图像算法开发者和我一样,遇到过这样的状况:要对Bitmap对象做一些密集计算(例如逐像素的滤波),但是在java层写循环代码来逐像素操作明显是不现实的,因为Java代码 ...

  2. 如何简单地利用Bitmap为中介储存图片到数据库中

        这是我的第一篇博文,请大家多多指教!     大概一个月之前,在跟朋友合作开发一个APP的过程中,我们发现到一个问题:图片的存储.因为数据库没有图片这种数据类型,当用户上传的图片需要存储的时候 ...

  3. C#中的bitmap类和图像像素值获取方法

    一.Bitmap类 Bitmap对象封装了GDI+中的一个位图,此位图由图形图像及其属性的像素数据组成.因此Bitmap是用于处理由像素数据定义的图像的对象.该类的主要方法和属性如下: 1. GetP ...

  4. Android下利用Bitmap切割图片

    在自己自定义的一个组件中由于需要用图片显示数字编号,而当前图片就只有一张,上面有0-9是个数字,于是不得不考虑将其中一个个的数字切割下来,需要显示什么数字,只需要组合一下就好了. 下面是程序的关键代码 ...

  5. Hadoop 中利用 mapreduce 读写 mysql 数据

    Hadoop 中利用 mapreduce 读写 mysql 数据   有时候我们在项目中会遇到输入结果集很大,但是输出结果很小,比如一些 pv.uv 数据,然后为了实时查询的需求,或者一些 OLAP ...

  6. [原创]MYSQL中利用外键实现级联删除和更新

    MySQL中利用外键实现级联删除.更新 MySQL支持外键的存储引擎只有InnoDB,在创建外键的时候,要求父表必须有对应的索引,子表在创建外键的时候也会自动创建对应的索引.在创建索引的时候,可以指定 ...

  7. [.net 面向对象程序设计进阶] (21) 反射(Reflection)(下)设计模式中利用反射解耦

    [.net 面向对象程序设计进阶] (21) 反射(Reflection)(下)设计模式中利用反射解耦 本节导读:上篇文章简单介绍了.NET面向对象中一个重要的技术反射的基本应用,它可以让我们动态的调 ...

  8. PHP中利用GD实现的柱状图

    PHP中利用GD实现的柱状图,自己写的一个画柱状图的类,上代码. <?php Class Chart{ private $image; // 定义图像 private $title; // 定义 ...

  9. springMVC中利用model在JSTL进行回填值

    1.ringMVC中利用model回填值 后台中,利用model返回值,如 model.addAttribute("MS_info" , MS_info); 前台回填值: text ...

随机推荐

  1. JS和JQuery概括

    1. BOM 1. location相关 1. location.href 2. location.href="http://www.sogo.com" 3. location.r ...

  2. Django项目: 4.用户登录登出功能

    用户登录登出功能 一.功能需求分析 1. 登录退出功能分析 流程图 功能 登录页面 登录功能 退出功能 二.登录页面 1. 接口设计 接口说明 类目 说明 请求方法 GET url定义 /user/l ...

  3. Apache ActiveMQ教程

    一.特性及优势 1.实现JMS1.1规范,支持J2EE1.4以上 2.可运行于任何jvm和大部分web容器(ActiveMQ works great in any JVM) 3.支持多种语言客户端(j ...

  4. Java基础知识(面试问题1)

    1.什么是 GC?为什么要有 GC?GC(Garbage Collection)是垃圾收集的意思,负责清除对象并释放内存.Java 提供的 GC 功能可以自动检测对象是否超过作用域从而达到自动回收内存 ...

  5. Windows API 25篇 TerminateProcess

    导语:结束一个进程的方法通常有:exit(), ExitProcess, TerminateProcess. 通常一个进程在正常情况下结束的话,系统会调用 ExitProcess函数结束进程,但有时候 ...

  6. Window API 第五篇 WTSEnumerateProcesses

    这个函数可用来枚举系统进程,先来看定义: BOOL WTSEnumerateProcesses( _In_  HANDLE            hServer, _In_  DWORD        ...

  7. leyou_06_Nginx的自启

    1.在linux系统的/etc/init.d/目录下创建nginx文件 vim /etc/init.d/nginx 添加以下内容 #!/bin/sh # # nginx - this script s ...

  8. leyou_02_nginx使用域名访问本地项目

    1.nginx的搭建依赖环境 1.1 准备jdk环境 当前最新版本下载地址:http://www.oracle.com/technetwork/java/javase/downloads/index. ...

  9. Java内功修炼系列一观察者模式

    观察者模式又称发布-订阅模式,就是观察者通过订阅被观察者,或关注被观察者,从而实时更新观察者的信息.比如我们玩微博的时候,如果关注了一些博主,那么当博主发动态时,在首页微博列表中就会自动更新这些博主发 ...

  10. PAT甲级——A1026 Table Tennis

    A table tennis club has N tables available to the public. The tables are numbered from 1 to N. For a ...