很多数据开发者使用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. 深入浅出 Java Concurrency (27): 并发容器 part 12 线程安全的List/Set[转]

    本小节是<并发容器>的最后一部分,这一个小节描述的是针对List/Set接口的一个线程版本. 在<并发队列与Queue简介>中介绍了并发容器的一个概括,主要描述的是Queue的 ...

  2. 杂项-公司:Google

    ylbtech-杂项-公司:Google 谷歌公司(Google Inc.)成立于1998年9月4日,由拉里·佩奇和谢尔盖·布林共同创建,被公认为全球最大的搜索引擎公司.谷歌是一家位于美国的跨国科技企 ...

  3. 【solr】Solr与JDK对应版本关系,Tomcat与JDK

    Solr与JDK对应版本关系,Tomcat与JDK版本对应关系 最新在部署solrCloud集群,由于自己机器上用的JDK都是JDK1.7的,然后我就从网上下载了最新下载了最先的solr6.6.0和最 ...

  4. vue-cli 本地环境 API 代理设置和解决跨域

    前言 我们在使用 vue-cli 启动项目的时候npm run dev便可以启动我们的项目了,通常我们的请求地址是以 localhost: 来请求接口数据的,localhost 是没有办法设置 coo ...

  5. C#绘制渐变背景

    //绘制渐变色背景 Graphics g = e.Graphics; LinearGradientBrush linearGradientBrush = new LinearGradientBrush ...

  6. commons-httpclient和org.apache.httpcomponents的区别

    <dependency> <groupId>commons-httpclient</groupId> <artifactId>commons-httpc ...

  7. html的常用标签详解1

    1.<!DOCTYPE html> 文档声明,不算是标签,但是它可是不能少.这玩意是干什么用的呢? 它是向浏览器自报家门的,即告诉浏览器的解析器应该以什么样的文档类型定义(DTD)来解析它 ...

  8. main函数执行前后还会发生什么

    问题分析 首先main()函数只不过是提供了一个函数入口,在main()函数中的显示代码执行之前,会由编译器生成_main函数,其中会进行所有全局对象的构造以及初始化工作.简单来说对静态变量.全局变量 ...

  9. 微信小程序上传图片(附后端代码)

    几乎每个程序都需要用到图片. 在小程序中我们可以通过image组件显示图片. 当然小程序也是可以上传图片的,微信小程序文档也写的很清楚. 上传图片 首先选择图片 通过wx.chooseImage(OB ...

  10. Trie性能分析之敏感词过滤golang

    package util import ( "strings" ) type Node struct { //rune表示一个utf8字符 char rune Data inter ...