更多技术交流、求职机会,欢迎关注字节跳动数据平台微信公众号,回复【1】进入官方交流群
 
由于流量红利逐渐消退,越来越多的广告企业和从业者开始探索精细化营销的新路径,取代以往的全流量、粗放式的广告轰炸。精细化营销意味着要在数以亿计的人群中优选出那些最具潜力的目标受众,这无疑对提供基础引擎支持的数据仓库能力,提出了极大的技术挑战。
 
本篇内容将聚焦字节跳动OLAP引擎技术和落地经验,从广告营销场景出发,上篇讲解利用ByteHouse 加速实时人群包分析查询的技术原理;下篇以字节跳动内部场景为例,具体拆解广告业务的实现逻辑和业务效果。(文本为下篇)
 

广告精准投放场景

广告投放过程一般包含数据收集->数据整合->人群圈选->广告投放->反馈分析等关键流程,人群圈选是广告精准投放的关键步骤,它帮助确定广告目标受众,辅助投放平台根据不同受众和广告目标优化投放策略,提升广告收益;

人群预估

  • 人群预估主要是根据一定的圈选条件,确认命中的用户数目。在广告精准投放过程中,广告主需要知道当前选定的人群组合中大概会有多少人,用于辅助判断投放情况进而确定投放预算,通常要求计算时间不能超过 5 秒。

广告投放

广告精准投放过程中遇到的问题与痛点:

  1. 数据预估:广告主需要对选定的人群组合进行预估,以便判断投放情况并确定投放预算。但人群包数据量多,基数大。平台的用户数上亿,仅抖音的 DAU 就几亿,抖音、头条对应的人群包在亿级别,早期的预估版本采用ElasticSearch,但由于数据过于庞大,只能采用1/10抽样存储,导致10%的误差,业务难以接受。
  2. 查询性能:广告主可以设定一个非常复杂的圈选条件,导致计算复杂(单次计算可能包含几百上千个人群包),Hive和ES等方案在处理大数据量时,查询速度会变得非常慢,如果需要查询某个广告主的所有用户,需要扫描整个用户库,而这个过程可能需要几分钟甚至几个小时,无法满足实时性要求。
  3. 存储空间大:Hive和ES等方案需要额外的索引结构,导致存储空间变大,从而增加了存储成本。例如,如果需要对用户属性进行索引,就需要额外的存储空间来存储索引数据。
  4. 不支持高并发:Hive和ES等方案在处理高并发请求时,容易出现性能问题,无法支持高效的广告投放。例如,如果同时有多个广告主需要查询用户信息,就可能会出现查询阻塞或响应延迟等问题。
  5. 数据查询效率:采用ClickHouse支持预估,但随着数据量的增长,ClickHouse在当前存储引擎的支持下也难以保证查询时间。这导致了数据查询效率的问题,影响了用户体验。

ByteHouse BitEngine方案

方案简介

新查询引擎

  • 针对广告人群预估业务开发的新查询引擎,基于ClickHouse提供的MergeTree Family系列引擎,添加了新的bitmap64类型和一系列的相关聚合函数。BitEngine提供的bitmap64类型适合存储和计算大量的用户ID之间的关系;在广告人群预估业务中,bitmap64类型用于存储人群包数据,然后将人群包之间的交并补计算转化为bitmap之间的交并补,从而达到远超普通查询的性能指标。

实现步骤

创建一个bitmap64类型,可以将用户ID直接存储在bitmap中,提供一系列交并补的聚合计算,并且还希望可以充分利用多核CPU的并行计算能力,由此我们设计了BitEngine。示例如下
CREATE TABLE cdp.tag_uids_map (
tags String,
uids BitMap64 BitEngineEncode
)ENGINE = HaMergeTree('/clickhouse/xxxx/{shard}', '{replica}')
ORDER BY tag

  

tag_uids_map存储格式如下
tag uids
A {10001,20001,30001,40001,50001,60001,70001,80001,90001}
B {10001,20001,20002,20003,20004,20005,20006,20007,20008}
要查询 A&B 的结果 SQL 为
SELECT bitmapCount('A&B') FROM tag_uids_map

BitEngine实现逻辑

核心思想

  1. 对数据做分区划分和编码,保证每个区间的数据之间不存在交集,然后使用roaring bitmap保存数据;
  2. 计算时每个分区的数据可以独立的做聚合计算,充分利用机器的并行能力,每个分区内部的聚合计算就是多个bitmap之间的交并补,利用roaring bitmap高效的交并补计算降低CPU和内存的使用;
  3. 通过字典将编码的结果反解回来,数据编码是为了让数据的分布尽可能稠密,roaring bitmap在存储和计算的时候就可以获得更好的性能。

业务应用

业务关键要素
  1. 人群包:广告主自定义规则计算出来的人群数据,标签是dmp团队根据市场需求定义的人群数据。
  2. 标签ID:每天定时根据产出规则更新一次,人群ID是自增的,每天根据广告主需求进行新建计算。
统一编码
  1. 为了对标签数据和人群数据的uid统一编码,编码服务先将标签数据中的uid和人群数据中的uid提取出来进行统一编码,将全量uid均匀hash到一万个桶中,桶编号为i[0<=i<=9999],uid在每个桶内由1开始顺序编码,每个桶的范围为i*2^40 - (i+1)*2^40。
  2. uid数据每天都在增加,因此需要支持增量编码, 编码服务每天会先获取增量uid,hash后顺序放置到每个桶中。
数据存储
  1. 完成编码后,会先把字典数据统一写入hive表中,便于字典的各种使用场景。
  2. 在数据经过分区和编码之后,ClickHouse可以以多种数据导入格式将数据以bitmap64类型存入磁盘。
数据计算
BitEngine如何充分利用计算机的并行能力完成每个分区多个bitmap之间的交并补计算?
存在问题:
假设存在四个bitmap,分别为a,b,c,d;则(a | c) & (b | d)不一定等于(a & b) | (c & d)。
人群包
  • 人群包A = [10001, 20001,30001,40001,50001],人群包B = [10001, 20001,20002,20003,20004]
期望结果
  • 通过BitEngine计算A&B = [10001, 20001]
设计方案
  • 人群包按照一定的规则划分为多个区间,任意两个区间之间的人群包没有交集
  • 一个计算线程只读取同一个区间的人群包进行计算,得到一个中间结果
  • 最终的中间结果只需要简单的进行bitmap or计算即可
对于这个设计,BitEngine需要保证数据的读取和计算是严格按照区间进行。BitEngine在数据读取时会为每一个文件构建一个读任务,由一个线程调度模块完成整个任务的调度和读取,这个线程调度模块的调度原则是:
  • 不同分区的文件不会交叉读取(ClickHouse的文件读取粒度小于文件粒度,会存在多个线程先后读一个文件的情况,一个分区也可能由多个文件组成),即一个线程只会读A_1,B_1,不会在这之间读取A_2或者B_2。
  • 一个分区读取完成后,可以立即触发聚合计算,执行bitmap之间的计算逻辑,获得中间结果。即A_1,B_1 读取完成后,可以立即计算A_1 & B_1。
  • 线程计算完中间结果后,可以继续读其他文件
BitEngine完成所有中间结果的计算后,会按照结果的输出要求做一次数据合并:
  • 如果需要计算的结果是bitmap的基数的时候,BitEngine直接将各个中间结果的基数相加
  • 如果计算结果需要的是bitmap,BitEngine直接将所有的bitmap合并起来,这里合并指的是bitmap or计算

业务效果

广告业务效果

  1. 数据存储空间缩小了 3 倍+
  2. 导入时间缩小了 3 倍+
  3. 查询 avg/pct99/max 都下降明显,pct99 从 5 s 降低到 2 s
  4. CPU 使用下降明显,PageCache 节省 100 G+
  5. 查询误差从10% 下降到 0%

BitEngine上线前后查询耗时监控

BitEngine上线后CPU负载对比

PageCache 使用情况(lower is better)

案例总结

BitEngine上线使用后,经过大量调优,在广告人群预估业务上取得了良好收益。未来,BitEngine将继续增强功能以支撑广告业务场景,包括:引擎集成数据编码,使编码对用户透明;提供细粒度的缓存以缓存部分重复表达式的计算结果;优化表达式解析等。
 

点击跳转云原生数据仓库ByteHouse 了解更多

火山引擎ByteHouse:一套方案,让OLAP引擎在精准投放场景更高效的更多相关文章

  1. 高性能、快响应!火山引擎 ByteHouse 物化视图功能及入门介绍

    更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 物化视图是指将视图的计算结果存储在数据库中的一种技术.当用户执行查询时,数据库会直接从已经预计算好的结果中获取数据 ...

  2. cocos2d-x 多分辨率适配详解(转载),以前北京团队设计的游戏,也是用这套方案

    http://blog.csdn.net/kyo7552/article/details/17163487 多种分辨率的适配一直都是一个蛋疼的问题,各家公司可能都有自己的一套方案.今天我为大家介绍的是 ...

  3. [转帖]OLAP引擎这么多,为什么苏宁选择用Druid?

    OLAP引擎这么多,为什么苏宁选择用Druid? 原创 51CTO 2018-12-21 11:24:12 [51CTO.com原创稿件]随着公司业务增长迅速,数据量越来越大,数据的种类也越来越丰富, ...

  4. OLAP了解与OLAP引擎——Mondrian入门

    一.  OLAP的基本概念 OLAP(On-Line Analysis Processing)在线分析处理是一种共享多维信息的快速分析技术:OLAP利用多维数据库技术使用户从不同角度观察数据:OLAP ...

  5. 分布式大数据多维数据分析(olap)引擎kylin[转]

    Apache Kylin是一个开源的分布式分析引擎,提供Hadoop之上的SQL查询接口及多维分析(OLAP)能力以支持超大规模数据,最初由eBay 开发并贡献至开源社区.它能在亚秒内查询巨大的Hiv ...

  6. OLAP引擎:基于Druid组件进行数据统计分析

    一.Druid概述 1.Druid简介 Druid是一款基于分布式架构的OLAP引擎,支持数据写入.低延时.高性能的数据分析,具有优秀的数据聚合能力与实时查询能力.在大数据分析.实时计算.监控等领域都 ...

  7. 从0开发3D引擎(八):准备“搭建引擎雏形”

    大家好,现在开始本系列的第三部分,按照以下几个步骤来搭建引擎雏形: 1.分析引擎的需求 2.实现最小的3D程序 3.从中提炼引擎原型 4.一步一步地对引擎进行改进,使其具备良好的架构 5.实现与架构相 ...

  8. JS引擎(2):Java平台上JavaScript引擎—Rhino/Nashorn概述

    可以后端开发的 javascript引擎有 Chrome V8 基于C++ java的Rhino引擎(JDK6被植入),Java8 被替换为Nashorn Rhino和Nashorn都是用Java实现 ...

  9. Fixflow引擎解析(一)(介绍) - Fixflow开源流程引擎介绍

    Fixflow引擎解析(四)(模型) - 通过EMF扩展BPMN2.0元素 Fixflow引擎解析(三)(模型) - 创建EMF模型来读写XML文件 Fixflow引擎解析(二)(模型) - BPMN ...

  10. mongodb底层存储和索引原理——本质是文档数据库,无表设计,同时wiredTiger存储引擎支持文档级别的锁,MMAPv1引擎基于mmap,二级索引(二级是文档的存储位置信息『文件id + 文件内offset 』)

    MongoDB是面向文档的数据库管理系统DBMS(显然mongodb不是oracle那样的RDBMS,而仅仅是DBMS). 想想一下MySQL中没有任何关系型数据库的表,而由JSON类型的对象组成数据 ...

随机推荐

  1. MySQL简易教程

    本文是参考廖雪峰老师的,但是网站广告有点多,我就在本地抄写一份,一方面是为了加强记忆巩固基础,另一方面也是就是为了第一方面.廖雪峰老师Mysql教程直达地址:https://www.liaoxuefe ...

  2. MacOS X终端里SSH会话管理

    http://codelife.me/blog/2012/09/01/ssh-session-profile-management-in-terminal-of-macos-x/ 本文介绍如何在终端里 ...

  3. 邮差之死--python源代码

    """sth imported""" import time import os '''2 flags''' flag = 0 tmp = ...

  4. RIPEMD加密技术

    摘要:RIPEMD(RACE Integrity Primitives Evaluation Message Digest)是一种密码散列函数,广泛应用于网络安全领域.本文首先介绍RIPEMD的起源和 ...

  5. MySQL的索引为什么使用B+树而不使用跳表?

    目录 MySQL的索引为什么使用B+树而不使用跳表? 1.B+树的结构 2.跳表的结构 3.B+树和跳表的区别 1.B+树新增数据会怎么样 跳表新增数据 4.Mysql的索引为什么使用B+树而不使用跳 ...

  6. 前端解析excel表格

    需求如下: 前端拿到表格中的数据,对数据做以下判断,并将拿到的数据转换成以下json格式,传给后端. 具体实现: 下载npm包:npm install xlsx --save 在vue文件中引入依赖: ...

  7. httpclients 和 okhttp 区别

    HttpClient使用介绍使用HttpClient发送请求主要分为以下几步骤: 创建 CloseableHttpClient对象或CloseableHttpAsyncClient对象,前者同步,后者 ...

  8. .NET8顶级调试lldb观察FOH堆字符串分配

    前言 好久没有动用LLDB了,这种未来的下一代高性能调试器应该是用在Linux内核系统的Arm64/Riscv64/X64系统指令集上的,LLDB Debug .NET有点杀鸡用牛刀.本篇通过它来看下 ...

  9. [gym104076][CCPC2022济南站L] Tree Distance

    You are given an unrooted weighted tree \(T\) with vertices \(1,2,-,n\). Please answer some queries. ...

  10. 87 GB 模型种子,GPT-4 缩小版,超越ChatGPT3.5,多平台在线体验

    瞬间爆火的Mixtral 8x7B 大家好,我是老章 最近风头最盛的大模型当属Mistral AI 发布的Mixtral 8x7B了,火爆程度压过Google的Gemini. 缘起是MistralAI ...