赞
踩
上一篇文章介绍了阿里开源高性能搜索引擎 Havenask - Ha3 本文重点解析2018年这个AI.OS版本的创新点
看到这张图可能会有点懵,熟悉和使用过搜索推荐服务的同学可能都知道在线技术组件如DII、RTP、HA3、BE、IGraph,它们在不同场景发挥各自擅长的作用。那么AI.OS(Artificial Intelligence Online Serving) 是个啥概念?
乍一看,是将搜索、推荐、广告、深度学习、信息流所应用到的技术组件融合成了一个体系,形成一个基础的引擎平台。仔细一琢磨,这么做是想干啥呢?带着这个问题一步一步往下看
在这个组件的最下层是资源的管理,叫 Hippo,是一个非常高效的资源管理系统。最上层业务,包括淘内业务,云上业务和广告业务,都是近几年陆陆续续拓展起来,一起逐步迁移到 AI·OS 这个功能体系上的。阿里的很多技术、业务是一个自底向上的模式,我们有非常强的创新意识。我们自底向上把搜索推荐平台化建设到百分之七八十,再组织推动到战略高度,加速之后形成了全覆盖的格局。
右侧是系统里的中间件,是更为基础的组件,跟实际的业务功能都直接相关。包括服务的定位——运行数万台机器的系统,内部要想服务定位需要有一个自己的机制。服务监控达到秒级的,这种秒级的服务监控和内部应用的 metrics 对分布式系统的 debug 是非常关键的。索引分发是解决引擎数据更新链路的重要基础组件。我们的消息队列是一个利用机器碎片资源搭建的高性能消息组件,只有非常小的 CPU 消耗和网络的通量,基本上是一个免费的组件,成本上比较有优势。二层调度和弹性扩缩,在应对大促时,是在内部做搜索、推荐、广告之间分钟级资源调配的重要手段。
左侧的算法平台、离线平台、训练平台、计算平台,是我们在深度学习时代新的开拓。从样本和特征的处理链路来说,有我们的算法平台——星云体系,在这个过程当中,有训练引擎的对接——XDL。计算平台,是支撑算法样本和训练的基础,也是阿里集团内部强大的技术支点,是和搜索一起成长起来的,相互促进相互支撑。
中间,是这几年最重要的积累,和业务密切相关。端上智能,我们在端上不仅仅做简单的推荐改变和结果混排的变化,而是真正在端上做模型的训练,深度模型的预测,在这方面,手淘信息流是全世界规模最大的深度学习、训练和预测的应用场景,
这是我们比较有特色的探索。
HA3 搜索引擎的服务是我们最经典的具有全文本检索能力的引擎。商业化引擎,是与 HA3 相对应的,支持广告业务、关键词匹配带广告,或者支持定向场景投放的召回引擎。iGraph 图引擎,是具备在线图计算和图检索能力,在业界规模较大的图检索引擎,它里面具备的用户个性化关系、知识图谱的在线推导能力都是很大规模的。这些引擎都是支持数据实时更新的,这个能力的来源就是 AI·OS Framework,支持对数据的管理,对更新的管理,是对右侧整套技术的依赖,也有延伸出来的深度学习的能力。
链式服务框架,天然支持意图解析服务QP
支持表:Dii支持的所有表类型KV,KKV,Trie,aitheta向量引擎index表(倒排索引表)有限支持
推荐服务平台,加载各种深度学习模型,机器学习模型,供RankService调用
针对推荐,更灵活的召回功能。同时作为向量引擎,更简洁。支撑业务如拍立淘
支持表:Dii支持的所有表类型KV,KKV,Trie,aitheta向量引擎index表(倒排索引表)有限支持
特点:
定位:简单召回,灵活,多种索引的查询,过滤,算分,排序,聚合等,适用推荐场景
图引擎
支持表:倒排,kv,kkv 表
定位:面向低门槛入门用户,低 rt,快速入门,面向索引和表的场景下优于 tair知识图谱推理场景
搜索引擎,淘宝搜索、天猫搜索、搜酷等都使用Ha3引擎。
支持表:index表,支持多列索引和复合索引新的图化HA3扩展了多表支持,同时也支持向量引擎.
定位:因其搜索功能特性强大,面向搜索场景
总的来说,底层索引实现,都会依赖标准的indexlib,各个引擎,根据业务需要,基于indexlib构建自己特有的召回能力
为了实现自定义OP的开发,你可能需要如下的4个步骤,其中1和2是必选项,3和4是可选项,大家可以根据实际情况进行设计与开发:
代码:
#include <iostream> #include "thirdparty/tensorflow/include/tensorflow/core/framework/op.h" #include "thirdparty/tensorflow/include/tensorflow/core/lib/core/status.h" #include "thirdparty/tensorflow/include/tensorflow/core/framework/op_kernel.h" #include "thirdparty/tensorflow/include/tensorflow/core/framework/register_types.h" #include "thirdparty/tensorflow/include/tensorflow/core/framework/shape_inference.h" using namespace tensorflow; //命名空间 REGISTER_OP("CustomOp") // 注册算子 .Input("input: float") .Output("output: float") .SetShapeFn([](shape_inference::InferenceContext* c) { c->set_output(0, c->input(0)); return Status::OK(); }); class CustomOp : public OpKernel { // 继承OpKernel类 public: explicit CustomOp(OpKernelConstruction* context) : OpKernel(context) {} // 禁止隐式转换 void Compute(OpKernelContext* context) override { const Tensor& input = context->input(0); Tensor* output = nullptr; Status s = context->allocate_output(0, input.shape(), &output); if (s != Status::OK()) { return; } auto input_data = input.flat<float>(); auto output_data = output->template flat<float>(); const int N = input.NumElements(); for (int i = 0; i < N; ++i) { output_data(i) = input_data(i) * 2; // Element-wise multiplication } std::cout << "CustomOp done.\n"; } }; REGISTER_KERNEL_BUILDER(Name("CustomOp").Device(DEVICE_CPU), CustomOp);
编译算子:
g++ -o “custom_op.cc.o” -c “custom_op.cc” -std=gnu++17 -msse4.2 -faligned-new -Wno-invalid-offsetof -Werror=conversion-null -Werror=reorder -Werror=non-virtual-dtor -Werror=overloaded-virtual -fPIC -m64 -mcx16 -pipe -g -DNDEBUG -D_FILE_OFFSET_BITS=64 -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -g -Wall -Wextra -Wno-unused-but-set-variable -Wno-unused-parameter -Wno-unused-local-typedefs -Wno-missing-field-initializers -Wno-unused-function -Wendif-labels -Wformat=2 -Wframe-larger-than=69632 -Wmissing-include-dirs -Wpointer-arith -Wwrite-strings -Werror=char-subscripts -Werror=comments -Werror=empty-body -Werror=endif-labels -Werror=format -Werror=missing-include-dirs -Werror=overflow -Werror=parentheses -Werror=return-type -Werror=sequence-point -Werror=sign-compare -Werror=switch -Werror=type-limits -Werror=uninitialized -Werror=unused-label -Werror=unused-result -Werror=unused-value -Werror=unused-variable -Werror=write-strings -Werror=vla -O3 -fno-omit-frame-pointer -Ithirdparty/tensorflow/include -ftree-vectorize -Wcpp -DEIGEN_USE_THREADS -pipe -fopenmp -fPIC -Wno-error=overloaded-virtual -Wno-error=sign-compare -Wno-error=maybe-uninitialized -Wno-error=unused-variable -Wno-error=reorder
ar rcs “libtf_ops.a” “custom_op.cc.o” //将.o文件制作成静态库文件libtf_ops.a
g++ -o “libmy_ops_cpu.so” -m64 -Wl,–whole-archive “libtf_ops.a” -Wl,–no-whole-archive -shared “libtensorflow_framework.so.2” “_pywrap_tensorflow_internal.so”
import tensorflow as tf
ops_cpu_module = tf.load_op_library('./libmy_ops_cpu.so')
sess = tf.Session()
result = ops_cpu_module.custom_op([[1.0, 2.0], [3.0, 4.0]])
print("****************")
print(sess.run(result))
QP 服务部署在一个叫做 DII 的算法在线服务平台上。DII 平台,可以支持 KV 表、index 表索引的构建和查询,其整体是一个链式服务框架,需要把复杂的业务逻辑拆分成相对独立和内聚的业务模块。比如,阿里内外的搜索 QP 服务,就拆分成分词、纠错、查询扩展、term weight、意图识别等多个功能模块。链式框架的好处是方便多人协作开发,每个人负责各自模块的开发,只要约定好上下游接口就可以,并且不同的 QP 服务可以复用同一个模块,减少重复代码。此外,在底层的算法服务上面包了一层,对外提供 TPP 接口。TPP 是阿里内部的一个成熟的算法推荐平台,可以很方便地做 AB 实验和弹性扩容,日志打点和监控报警的机制也非常成熟。
DII中对传统的链式处理框架进行了部分功能增强,主要包括:
ODPS上产出的数据都是行列式的表格结构,在线使用时为了提升查询效率自然要建立一个合理的索引结构,因此DII提供了丰富的本地索引结构,也称为表。目前支持的表类型包括:
kv表。可以指定ODPS表的某一个字段作为key,其它的多个字段作为value fields。
index表。可以对若干需要进行倒排查询的字段按照某种分词方式建立索引。
与ODPS表对应,DII中表的记录也是分字段带类型的,可以直接按字段的方式使用。DII使用的是isearch5的索引实现indexlib,因此也天然具备了indexlib强大的检索功能和优秀的性能。在召回之上,DII还提供了过滤和排序机制,包括内置的过滤和排序规则以及用户自定义插件接口。此外,DII还封装了几种常用的组合查询方式,包括迭代、join、merge,使用起来更加便利。DII的索引机制是可扩展的,可以根据用户需求新增索引类型,例如目前正在开发的Trie树索引结构,用来满足一些使用前缀查询的业务场景。
"小而美”是DII服务的一个共同特点,也是DII设计的初衷,所以免不了会访问一些外部服务。在搜索内部,最集中的体现就是访问iGraph–一个在线图存储和查询服务。DII集成了iGraph访问的功能,并且在易用性和性能两方面都进行了重点考量。首先,通过让用户模块在prepare阶段声明访问请求,框架收集后统一并发访问,可以大大降低整个服务的延迟。其次,通过让用户以配置的方式声明访问请求,可以提升开发和发布效率
数据更新包括两方面,一是ODPS表到DII表的全量更新,二是表数据的实时更新。DII在这两块都提供了完善的支持。用户只需要在自助接入的web上建立好ODPS表到DII表的映射关系,之后系统就会在ODPS表有新的分区产出时自动构建索引,触发线上DII表的全量更新,用户不需要参与。实时更新则有两种方式,一种是通过DII提供的工具来执行,另一种是调用API直接更新。前一种比较适合运营或算法同学手工干预,第二种适合由外部的实时更新系统持续调用。
阿里巴巴内部一个通用的在线预测平台,提供基本的模型推断(inference)能力,对排序打分有深度的优化。
从2016年开始,RTP平台开始逐渐支持一些简单的深度模型场景例如wdl、dnn等,但是有限的模型种类不仅限制了算法同学的发挥,在从系统维护优化角度来说,也是逐个击破的策略,总体业务支撑的效率偏低。
对于一个算法工程师而言,开发一个新的算法,或者上线一些新的feature需要做的工作
原始数据准备
一般而言数据源头都有对应的负责团队或者负责人负责数据的质量和使用方式的,大部分工作是数据准备,数据清洗等工作,odps/blink在这部分工作中起着巨大的作用,很多团队都沉淀了自己的一套流程,全量、批量数据、实时数据的产出都依托于odps及blink的能力,最终以表的形式推送到RTP系统。
feature生成
feature一般可以用通用的feature生成规则(一般就是原始值、id特征、各种交叉特征等规则),rtp从最初的版本开始就提供对应的feature生成规则,保证用户训练生成feature的逻辑与在线inference中产生的feature一致。
模型设计、训练
模型方面应该将自由度交给算法同学,让他们能自由设计;训练平台方面,集团内也已经有较为成熟的训练平台,常用的例如Pai、Porsche,或者基于PS等自己开发的算法,亦或者Caffe等开源平台训练。
模型、数据、feature生成规则部署到在线
这一步是比较复杂的,也是RTP系统希望能解决的。以往的做法有点类似算法同学作为PM的角色来上线整个模型,思考如何将模型推到在线的各种系统上去。具体需要考虑的部分包括原始数据、模型数据、模型inference具体逻辑。
虽然大部分都已经有自动流程,但是完全新增的模型,整体上线的时间也会很长,更重要的是,从模型与数据的整体设计产出,到真正可服务的链路过长,导致整体的认知成本极高,依赖算法同学来串联整体系统最终完成模型服务的模式是非常低效而又容易出现问题的。
整体模型的样本特征等的管理平台我们把它叫做AOP平台,AOP平台会负责整个模型及样本的所有元信息的管理及在离线的一致性。下图中可以看到AOP的运作方式,AOP主要管理着整体的元信息,并负责协调样本和日志数据的一致性,离线数据库表与在线字段数据的一致性、离线与在线的特征处理方式的一致性、离线模型的训练、验证及自动发布到RTP系统。
RTP平台主要的运行效率取决于对应特征及模型的计算过程,整个RTP设计优化的思路也围绕这几点而来。
在很长时间以来,在线服务的体系里都将业务的离线处理逻辑和在线计算逻辑分离开,用户需要协调离线数据处理过程和在线计算逻辑,为了完成对在线逻辑的一些性能优化,往往需要离线数据做一定的预处理或者索引构建等过程,而后才能让在线的服务使用。
环视其他有在线服务特性的系统,对于搜索引擎而言,类似“组合索引”、“过滤转倒排”等优化方式,包括正常的倒排索引,都是“因为可以加速在线检索过程”而生成的;对于数据库而言,类似“物化视图”的思路,也是因为可以加速在线的查询过程而在离线提前计算好;对于分析引擎而言也是一样的,为了能快速拿到统计数据,在索引构建的同时就会将统计结果预先计算好。这些方案的核心思路都是数据的构建是为了在线计算。
RTP系统是基于suez平台实现的,在RTP之前,suez平台并没有为数据的构建是为了在线计算建立一套行之有效的优化通路,先变更离线数据的计算方式,然后在线才开启这个优化/功能,这实际上和数据的构建是为了在线计算的思路是矛盾的。现有的一些优化方案中都需要多处配置,先配置好离线,等离线生效了才能配置在线,造成了很多优化功能实际上难以大范围的用起来,这也反向的制约了我们做联动优化的意愿。
这一现象在RTP的场景中更为明显,RTP的一个设计原则在于让迭代变得更简单,因此在RTP中,我们大大的削减了用户所需要关心的优化选项和配置,极尽可能的减少用户所需要关心的“工程优化”的问题,这就迫使我们必须体系化的解决优化的问题。
因此在过去的一年中,我们重构我们上线流程中涉及的大部分系统,将“用户应该做的优化”沉淀成一系列的optimize pass,从在线计算逻辑中推导出我们应该做的优化,并自动的生效的系统中。一些典型的应用,类似自动的离线predict、数据的format等都可以自动根据具体在线的运行逻辑而自动生成,大大降低了整体系统的优化的人力成本。
特征的计算在整个RTP的系统中是非常重要的一环,无论是传统的LR、GBDT模型还是深度学习模型,都离不开基本的特征运算。对于特征运算而言,不仅需要考虑特征的表达能力和运算速度,还需要考虑扩展能力、组合能力等。
特征计算的过程实际上是一个非常结构化的数据的计算,在这一方向上,很长一段时间依赖RTP的特征计算都是解释执行的,而特征计算本身是较为固化的,解释执行在泛用性上是可以满足需求,但是性能上是不够优的,在过去的一年我们尝试了codegen技术,并取得了相当不错的结果,这部分细节我们在另一篇文章中已经总结了,具体可以看:
大规模深度学习预测场景下 codegen 的思考与应用
对于深度学习场景而言,异构计算是其中非常关键的一环,目前RTP平台不仅支持GPU,也大量使用FPGA来加速预测过程。
GPU在重计算的场景下有着巨大的优势,特别是一些CNN模型的场景下,GPU整体的吞吐和latency都明显优于FPGA,同时有良好的生态,整个机器学习领域甚至并行计算领域中,GPU的案例非常之多,前人都留下了无数的工作成果可以很方便的应用起来,例如量化、甚至于排序等都有现成可用的方案。
FPGA而言,对于非图像视频类场景而言,模型的计算复杂度不是特别高,很难发挥GPU完全的能力,从我们实践下来的结果看,FPGA非常适用于中小复杂度的计算,一方面是从成本角度看,FPGA相对于GPU而言是便宜得多的,另一方面FPGA对硬件的定制化能力更强,可以精细化调度和控制计算单元,使得整体硬件的能力能更加充分的被发挥出来,在刚刚过去的双十一,RTP用到的异构计算资源中,FPGA的数量已经超过GPU的数量,成为整个机器学习异构计算中相当重要的一员。
在我们看来,FPGA和GPU各有所长,对平台而言,这两种异构计算实际上是互补的,一个考虑泛用性,一个考虑成本;一个考虑高密度计算,一个考虑中小密度计算。这两种异构计算给了平台业务更多的选择和手段,同时给用户提供高灵活性和低成本。
TensorFlow在2017年提供了Tensorflow Serving,可以将训练好的模型直接上线并提供服务,RTP也支持将TensorFlow的模型上线并提供服务。那么,问题来了,既然已有TensorFlow Serving,为什么还要用RTP?相比TensorFlow Serving,RTP有如下3方面特点和优势。
对于大规模打分场景而言,大部分的数据从请求中带入是不合适的,而RTP系统本地有数据存储的能力,而且是基于Suez框架的表存储,有高效的压缩读取机制,同时还能完全支持实时链路。
RTP系统额外增加的feature产生、数据读取、插件等机制,使其能够做到灵活支撑业务逻辑。
RTP系统是基于Suez框架开发的,因此能继承其管控系统、分布式行列服务等能力,这使得我们的系统拥有了数据分片、模型分片的能力,从而在大规模模型或者数据应用场景中,发挥巨大优势。
Suez在线服务框架是搜索事业部自研的大数据在线服务的通用抽象(要求具备秒级数据更新的最终一致性)。Suez框架统一了以下3个维度的工作。
索引存储(全文检索、图检索、深度学习模型)
索引管理(全量、增量及实时更新)
服务管理(最终一致性、切流降级扩缩容等)
下面用一张图来描述RTP与Suez框架的关系。、图中Tf_search是RTP的内核,基于Indexlib和Suez Worker承载对外提供端口服务。Suez Worker的部署由Suez admin完成和管理,而Suez worker和Suez admin的机器资源(如CPU、内存等)都是通过一个叫作Hippo的资源调度框架来管理的。
RTP和TensorFlow Serving一样,基本的功能就是将模型进行加载并提供端口对外服务。下面,首先从阿里巴巴网站的搜索和推荐业务来阐述RTP在其中的位置;然后,介绍RTP的模型和数据更新机制;
接着,从RTP提供对外服务接口开始,一步步深挖RTP是如何借鉴TensorFlow的图化思想来实现既支持TensorFlow的原生深度模型,又支持LR模型、GBDT等传统模型的;最后,介绍在面对海量的数据和模型时,RTP在工作效率、稳定性及性能方面具备的独特优势。
Rank Service和RTP内部其实是基于同一份二进制文件拉起的服务,都可以认为是宽泛意义上的RTP。两者的差异在于加载的模型不同,因而作用不同。
TPP是将上述在线服务编排、处理、整合的一个平台
原生的TensorFlow模型(如saved model)是不区分模型和数据的,只有模型的概念。这里的模型实际包含了两类信息:一类是图的结构,一类是参数的权重数据。在一个目录下存了多个文件,共同存储上述两类信息。RTP也支持saved model格式,不过这并不是RTP在生产环境的主流使用方式。
在生产环境的主流使用方式中,RTP出于对性能和数据容量的考虑,会将TensorFlow的原生模型按RTP的格式要求进行转换,分成两部分:一部分是抽取和转成网络结构,可以认为是模型的元数据,采用GRAPH.def的文件存放和使用;
另一部分是参数和对应的权重信息,采用KV表的形式进行分发和使用。RTP借助Suez框架将上述两部分信息进行分发并加载到内存中。上述网络结构的更新是非实时的,可以做到小时级别的更新,而参数和对应的权重支持实时更新,已应用在2019年的天猫“双11”大促中。
另外,RTP还有一部分信息可以做到实时更新,这就是内容表(item table)。在主流的应用场景中,内容表是一个超级大表,也是一个KV表,Key是商品ID,Value是商品维度的原始特征。
这么做是为了减小从请求串中传递的参数大小。大部分商品维度的特征可以从服务器本地的KV表中读取,而不是从请求串中解析。试想一下,如果数千个商品维度的特征都从请求串中传递,这个请求串会非常大,仅解析请求串、反序列化对象就会消耗不少时间。
RTP支持基于HTTP和ARPC两种协议的请求方式。其中,基于HTTP协议的请求方式与其他平台差别不大,整体过程就是在HTTP客户端将所有的输入拼装成JSON对象,按POST协议进行请求;
然后在RTP服务端将JSON对象解析为tensor input张量输入和tensor fetch张量读片以及其他的相关信息,调用TensorFlow Graph的执行器运行模型,得到fetch读片的具体内容;最后用同样的方式封装成JSON对象并返回给客户端。
对于基于ARPC协议的请求方式,其支持两种请求对象:一种是PBRequest,也就是JSON对象封装成了PB对象,其优点是对于单个请求附带了大量的商品id集合的场景,有比较大的性能提升;
一种是GraphRequest,这种请求是通过RTP客户端的SDK封装好tensor的input、fetch以及其他信息,存储到GraphRequest对象中,通过ARPC调用RTP,在RTP协议转换层将这些tensor信息传递给Tensor-Flow图执行器运行模型,得到输出的fetch的tensor。
基于HTTP协议的请求格式主要用于开发过程中的调试,在生产环境中会使用基于ARPC协议的请求格式。
前面讲到,RTP将模型拆分成两部分:一部分是纯粹的图结构,一部分是参数和权重数据。RTP会对图进行转化,将Training Graph训练图转成Inference Graph推理图,并对某些节点进行替换改写,使之能够读取本地数据KV表。图8所示是对训练出来的模型图进行添加和裁剪的过程。
添加一些节点,如Placeholder,用于外部请求数据的输入;也会添加一些Feature Generator特征生成器相关的节点,用于对请求串中输入的数据进行特征生成。
这些特征生成节点如果涉及商品维度的特征生成,往往会和本地的内容表关联,在节点执行时,会检索本地内容表,获取商品维度的数据,然后进行特征生成。另外,会对某些节点(如Loss节点)进行删除,因为前向预测时,这些节点是用不上的。
RTP在阿里巴巴集团的搜索和推荐体系中占据了非常重要的位置,工程实现的管控系统对训练和上线流程的封装让整个过程非常顺畅,让算法工程师能专注于模型的优化,从而大大提高算法的生产效率。
RTP基于图化的内核设计思想,支持将各种原生的算法模型都转成图化模型的形式,具备极强的通用性,这也是RTP在集团内部如此受欢迎的原因之一。同时,RTP结合Suez框架提供的本地数据存储和查询机定制开发了一些图化操作算子,提升了模型预测的计算性能。
RTP服务端具备分布式存储数据和分片部署的能力,让数以亿计的商品维度的数据不再通过网络传输,减少了网络传输,极大提升了模型执行的性能。RTP依托Suez框架实现了模型和数据的实时更新能力,让模型能快速捕捉当前的变化,提升准确性。# 7 BE
BE(Basic Engine) 是基于suez构建的,在suez框架服务的基础上,BE实现了与推荐业务相关的各种功能组件,如向量召回技术、多表join召回,自定义插件形式提供排序和算分插件接口。
BE(Basic Engine)是基于阿里巴巴集团另一个更底层的框架服务Suez构建的。在Suez框架服务的基础上,BE实现了与推荐业务相关的各种功能组件,如向量召回技术、多表join召回,以及以自定义插件形式提供的排序和算分插件接口。
典型的proxy+searcher的架构,其中3个proxy完全对等,互相备份。searcher集群有2行4列,这表示索引数据被分成4份分别放到4列机器上,2行之间完全对等,互相备份。
各种I2I/S2I/B2I的召回(search)、合并(union)、关联(join)、过滤(filter)和排序(sorter)均在searcher本地完成,最后经过proxy的合并排序(merge sorter)返回,如下图所示
图2中的I2I、S2I、C2I都是BE支持的召回功能,BE底层是基于阿里巴巴搜索事业部研发的通用索引和检索模块indexlib实现的,这里主要用到了indexlib的KV和KKV检索的功能。
顾名思义,KV检索是输入一个或者多个K,返回一个或者多个V。KKV检索是输入pkey和skey,返回单个值;如果只输入pkey,不输入skey,则返回的是值序列。在实际的推荐业务中,主要就是用这两种检索召回机制。
合并功能(union):指的是对多张表的检索结果进行合并,取并集,并记录召回的来源表的信息和是否被两张表同时召回的信息。这些召回过程中记录下来的信息可以用在算分阶段,比如不同的来源表权重不同,则最终得分不同;以及如果是两张表同时召回的,说明被召回的元素命中多种召回策略,则两张来源表的权重相加作为最终权重用于算分,得分就更高了。
关联功能(join):由于左表所存储的信息有限,从左表召回元素集合之后,还有一些信息存在右表,通过join功能可以获取右表的信息,让记录的字段更丰富。该功能用于算分阶段和返回给调用方。
排序功能(sorter):按某个字段或者表达式进行排序,支持用自定义插件实现。
最后,对不同的列(partition)的结果进行合并,然后返回给调用方,这是一个完整的BE召回过程。
通过将元素进行向量化来构建便于高效检索的索引。检索端采用同样的方式对检索元素进行向量化,利用检索技术得到相似度接近的集合,并根据相似度进行排序。比如拍立淘,搜索一个鞋子,会检索出跟鞋子相似的所有商品。
iGraph是搜索事业部工程团队打造的实时在线图存储与查询的系统,提供大规模图数据的存储、查询、更新和计算服务,目前承载了集团多个部门5000+表的数据。iGraph架构经历了3次大的演进,分别是
iGraph是一个功能强大的在线图存储和计算服务,被广泛的用到集团的各推荐业务以及主搜个性化等场景,它提供了kv表和kkv表等数据模型,用户一般将图计算中涉及到的“点”用kv模型存储,“边”用kkv模型存储。
DII是一个支持灵活定制的链式处理的在线计算引擎,在搜索业务的qp、suggest以及推荐场景的猜你喜欢等有深度的应用,它提供了kv模型,并使用了indexlib提供的普通表模型。
下图描述了iGraph和DII原有的架构。
此架构中有如下特点:
iGraph和DII都有全量索引和实时索引过程。全量索引由build job产生,实时索引由在线的服务节点产生。
实时索引的性能有逐渐恶化的现象,这时要依赖于在线compaction,但是这会引擎在线节点的I/O和CPU争用,造成查询抖动。
节点迁移的时间很长。需要迁移时,需要分发全量索引,并以全量时间点为基础拉取实时数据,如果很久没有build全量索引,那么这个拉取实时数据build实时索引的时间会非常长。
统一在线数据存储和管理框架
这个框架不是为iGraph和DII专用的,它对于面向最终一致性的在线数据存储和计算服务来说都是适用的
参考链接:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。