草庐IT

零代码上线小布对话技能:技能平台的实践与思考

OPPO小布助手 2023-03-28 原文
前不久,OPPO旗下的人工智能助手“小布助手”月度活跃用户数突破一亿,成为国内首个月活用户数破亿的手机语音助手。

经过2年多的成长,小布助手在能力上实现大幅升级,也融入了我们身边便捷的服务功能。小布团队亦克服了诸多技术难点,为用户带来了更智能的服务。为此,小布团队撰写了一系列文章,详细介绍小布助手背后的技术支撑,本文是揭秘小布背后技术的第四篇,主要介绍技能平台的实践与思考。

第一篇: 对话系统简介与OPPO小布助手的工程实践

第二篇: 小布助手算法系统的探索、实践与思考

第三篇:对话交互:封闭域任务型与开放域闲聊算法技术

1. 平台化对话能力的目标与挑战

1.1 背景及平台化思考

小布助手做为新兴交互入口,是OPPO万物互融战略的关键节点,通过小布可以为用户提供丰富的技能体验、全面又贴心的对话能力。

同时,由于现有技能&对话多数形态固定、技术相对通用且以量盖面的特点。迫切需要降低对话技能算法研发的门槛,支撑内外部开发者大量建设对话技能。小布助手团队于19年底开始布局技能平台,过程中也积累部分对于平台化的思考。

平台化的优势是:降低研发成本、加速上线、提升稳定性、加速能力扩散、统一数据资产、集团资源高效利用。

平台化潜在的风险:

  • 对创新的遏制:使用平台能力的线性组合是技能的上限,会抑制创新
  • 强制收编&反人性:中台是对现有场景的抽象,当创新场景被孵化后,往往会强制收编研发了许久的创新,往往造成精英人才的流失
  • 过度设计:为了能够组合出各种通用业务,平台的设计非常容易过度设计,为了一个需求而增加大量交互逻辑,会成为后续发展的瓶颈
  • 丧失度对于用户心智的追求:平台的目标是能力的研发,但是与实际用户产品并不直接等价
因此,小布技能平台的构建思路是:

  1. 面向重复、通用、长尾技能&对话
  2. 推动对话架构隔离性、局部替代、可扩展性的演进,保证平台设计的精炼及对创新能力的支撑
  3. 保持长期业务及平台共存的形式,促进创新演进的同时也能够积累足够的通用化能力
中台不是万能的,它仅仅适用于在高确定性和通用性的场景。

1.2 目标及挑战

技能平台的定位:面向通用对话&技能,提供免代码、高效、低成本的技能及对话全流程研发能力,助力无处不在的小布助手技能生态建设。

  • 面向内部自研技能,提供标准化对话框架,构建技能创建、意图理解、模型训练、数据发布、效果评测、部署于一体的可视化免代码工具,提升技能开发全流程效率,降低技能接入成本。
  • 面向设备&渠道定制, 支持小布自建技能及软工、IOT、客服、游戏等技能的低成本创建维护;
  • 向外部开发者提供开放技能平台,丰富小布助手技能生态。

首先我们看一下完整的对话流程,如上图所述,共分为8个环节。

技能平台主要负责其中右边3、4、5、6 的4个环节,而其中如何做到有效的数据流转、低成本能力建设就是我们所需要解决的核心问题。当然,其中也面临着不少的挑战。

2. 平台算法实践经验

对话系统 (Dialog System) 是“让机器理解并处理人类对话的系统”,核心是模仿及抽象人与人之间沟通的方式,将对话抽象成具体的任务模块:TTS(倾听)、NLU(理解)、Policy(记忆、见人说人话)、Action(组织语言)。

为了保证对话系统主体链路的稳定性及灵活性,小布的整体思路是“轻中控,重模块化”。目前的算法工作主要围绕NLU、Policy两个模块展开,其中 Policy 目前主要以规则及产品策略为主,因此下面重点介绍语义理解部分的一些算法事件经验。

语义理解主要是将Query 映射到具体的动作空间,并且提取动作执行所能识别的标准值,具体算法建模为意图理解和槽位解析。

小布技能平台覆盖了分类、语义匹配、文本匹配等三类意图理解方式,以及若干槽位解析能力,下面将展开详解。

文本分类:通过文本分类的方式进行意图理解,能够在有限域内完成更精细化的意图理解。其准召的天花板较高,业内及小布技能平均准召在反复迭代优化后普遍能够做到90%以上。

意图理解的文本分类,其本质是一个N+1 分类的多分类任务。

N:指域内需要理解的用户意图,如音乐领域包含:点播歌手的歌曲、随机播放歌曲、查询信息、点播类型音乐等等。

1:是指的域外的other意图,所有非该领域意图的query 都需要分类模型能够拒绝,避免无论用户说什么问题都会一定分类到域内意图。

由于“other”意图近乎无穷,因此意图理解分类同时也是一个严重样本不均衡任务。

在意图分类任务中,尤其在泛娱乐等资源相关领域存在实体知识决定意图分类的例子,如:

  • 播放七里香 -> 歌曲
  • 播放无间道 -> 电影
  • 播放郭德纲 -> 相声
为了解决实体知识依赖问题。我们借鉴Embedding Concat的方式,构建了以Tiny model 为核心骨架的知识嵌入model。

在实际探索过程中会发现:

  1. tiny model (耗时< 15ms CPU) 的限制条件下,TextCNN、Lite Trans、SWEM 等model效果及稳定性明显高于Trans系列model
  2. 直接嵌入one-hot 效果会比Embedding 后更好。Concat 的通用性会优于Sum/Add (不强制要求空间相等,无信息损失)。

同时为了保证嵌入特征及文本分类的效果,进一步降低模型训练成本。

围绕数据对抗做了一系列的特征及数据增强:

  1. 通过自动构建包含过拟合片段的负样本,降低字词过拟合现象
  2. 对实体进行替换,避免对实体的过拟合。如:周杰伦 ->音乐
  3. 通过构建query 一致,嵌入不同的负样本,增加实体信息的有效性
  4. 通过构建实体及嵌入一致,但是上下文不同的负样本,提升模型对说法及上下文的拟合,避免过拟合嵌入信息

预训练模型蒸馏会很大程度上提升小模型的泛化能力。

但是在实际工作中发现,现有大规模预训练模型在实体相关性上存在偏差。尤其在泛娱乐相关领域对于资源实体无法很好的区分。

因此,现有做法是,通过大规模预训练语言模型进行离线数据挖掘及数据增强。通过数据蒸馏的方式引入大规模预训练语言模型的相关泛化能力。

分类的方式适用于语料充分、准召要求高的场景。但是分类算法需要掌握较多的算法及调优知识。

为了满足非算法人员无成本的研发语音相关技能,同时覆盖开发域、低数据量的部分意图理解场景,因此需要提供意图匹配相关算法能力。

业内语义匹配算法主要分为语义表征及交互匹配两种技术方案。

前者可以通过ANN等算法大量降低Query-Query 匹配的计算量及匹配次数,缺点是需要在query -> model -> embedding的过程中将不相似query 在embedding 层面进行区分,embedding learning 的难度较高。

后者则能同时捕捉交互信息,因此在准确性上会明显优于语义表征的方式,但是计算代价较高。因此往往配合方案为:语义表征(召回)+ 语义交互(精排)。

但是由于技能平台的特殊性:面向场景不定、领域数众多。无法针对每一个技能都单独训练一个交互匹配模型。因此技能平台在语义匹配方案主要以语义表征为主。

在语义表征领域,近年来以无监督预训练相关任务发展最为迅速。

在实际业务使用过程中,我们发现仅通过700w左右的数据预训练已经能达到80%左右的准召,也证实了无监督预训练任务的确能过为语义表征带来一定的收益。但是无监督预训练任务的天花板也较为明显。

上图分别列举了word2vec与PTM 两种方式的部分case 及优缺点。

为了进一步提升语义表征的效果,我们采用了metric learning 相关的做法对已有无监督模型进一步finetuning。两者叠加构建技能平台的语义表针算法能力。

常规语义匹配及分类虽然已经能够满足大部分应用场景,但是在新闻、客服等领域存在许多不含有上下文、或上下文与标准主体相差很大的匹配问题。因此,我们同样利用ES构建了基于文本主体的匹配算法。

对query 、template都分别进行分词、筛词、滤词。保留文本主体后在进行文本pattern层面的匹配。同语义表征匹配一同解决意图匹配的问题。

在槽位解析方面,技能平台共研发了标准时间解析、地点、人名等数十种通用槽位解析能力。

以及基于DAG+DP、AC双数组匹配等多种的词典匹配算法能力。

同时为了解决部分任意槽位的抽取,基于bilstm+CRF 构建了一整套模板数据生成、特征增强的算法解决方案。

通过上述解析器、模型、词典等槽位解析共同构建了整套算法槽位解析能力。同时为了针对多槽位、歧义槽位等问题,构建了槽位消解、槽位映射以及上图所示的语义槽功能。

技能平台通过抽象现有语义理解及槽位解析能力,提供了一整套的技能研发算法解决方案,使得非算法人员也能够通过有限的培训后,自主的完成技能的创建、迭代及上线。

以上就是技能平台在语义理解相关领域的算法简介。

3.平台算法及工程能力实践与经验

3.1 工程能力实践

3.1.1 平台整体架构

整体采用分层架构设计,整体架构具有可伸缩性,支持通用化能力的任意组合满足多种业务需求。

基础数据层
将数据管理进行抽象,保证语音助手内部数据统一性和稳定性。基础数据接入流程标准化,通过文件分发系统支持任意接入系统可以获取到需要的业务配置数据。打通多套业务环境,数据上线流程标准化,实现数据发布平台可视化流转。

基础组件层
平台经过一段时间的发展,将通用能力进行抽象,形成一批具有原子化能力的组件。基础组件和业务无关,专注于单一逻辑功能的实现。采用服务化+sdk两种实现方案,给业务编排服务提供多种选择。

现有已经支持的组件包括:

  • 检索引擎:支持高维向量检索,利用通用语言模型将标准query和用户query转化为句向量。使用hnsw算法进行向量的存储和检索。支持用户只进行少量语料的配置,亦可以达到意图召回的效果,简化了语义理解的使用成本。
  • 规则引擎:通过解析正则表达式实现对语料的召回,支持多种正则写法,提供高准确度的语义召回能力。
  • 通用提槽:将时间,人名,地名,金钱,电话等使用频率较高或者槽位解析方式比较特殊能力进行统一抽象固化为通用组件能力对外赋能。外部使用方可以选择一种或者多种提槽方式。
  • 协议映射:技能平台对接外部三方的情况较多,每一个三方数据协议各不相同。每一个新的三方接口的引入将会带来一定的研发成本。这里将协议解析的部分进行了抽象,实现协议解析配置化。只需要进行少量的映射配置就可以实现外部协议到内部协议的转换。
  • 技能回复:不同技能给用户的回复方式多种多样,这里将整个技能回复进行了流程和协议标准化。用户只需要在平台配置相应的回复数据,就可以端侧实现目标效果。
业务编排层和业务层
业务编排层根据业务层想要实现的效果进行整体业务的分解,形成一个一个独立的业务单元,每一个业务单元实现一个独立的业务逻辑。例如:cds实现云端技能平台的意图理解。每一个业务单元都是进行一定编排方式将组件层中一个或者多个组件组合起来。目前主要落地了两类业务单元——通用NLU和通用DM。

开放平台NLU

并行流水线设计,支持业务水平扩展。充分利用底层组件,结合实际业务需求进行业务逻辑编排。每一条业务流水线代表一个业务单元。实现平台通用语义理解可配置化接入。新业务逻辑快速接入。

具体收益:代码复用率达到70%,新业务接入提效超过100%(原来需要二周左右开发,现在3-4天可以完成)。性能从平响20ms提升到不到10ms,整体性能提升100%。

通用DM

业务单元模块化设计,将原子化组件能力加上业务逻辑组合为一个个业务单元,经过统一的编排层实现通用的dm能力。支持多重条件判断,支持多种格式的协议转换。用户可以配置化实现多种回复类型,可以通过简单的配置实现多轮对话流。

具体收益:多种dm通用能力沉淀为组件,代码服用率提高40%,实现dm能力可配置化实现。简化协议解析流程,通过简单的公式配置就可以实现协议转化,节约90%的协议转化逻辑。整体稳定性提升,半年内故障数为0。

3.1.2 模型流转

算法模型作为语义理解核心组成部分,其生命周期的管理在技能平台完成自动化流转。模型的生命周期分为几个部分 数据准备——模型训练——模型测试——模型上线——模型下线。

在技能平台完成数据准备,触发机器学习平台部署的训练脚本完成模型训练,生成算法模型。通过发布系统将模型推送到在线模型serving服务,加载最新模型,对外提供分类服务。

3.1.3 数据发布

技能平台将小布助手的全部基础数据进行统一管理,隔离数据源操作,保证数据的安全性。隔离离线数据和在线数据,用户在平台管理端产生离线数据,通过发布流程将数据发布到在线环境,影响在线服务。数据隔离保证在线数据的稳定性,所有在线服务加载的基础数据都是经过验证的快照数据。同时发布系统通过文件发布打通了线上线下各个环境,保证数据上线过程经过各个环境进行了严格的验证。

数据在技能平台具有一个完整的生命周期,每一个阶段都分别对应一个环境。

  • 新建:用户在平台经过增删改产生的数据都属于这个阶段,这些数据可以进入对话测试环境进行基本的功能验证。
  • 评测:在经过简单的基础功能验证之后,可以将数据流转到评测状态,数据将会被发布到评测环境进行评测。用户可以根据产生的评测报告,对召回语料进行一定的调整,直到语义部分达到评测要求。
  • 测试:在评测指标达标后,可以将数据发布到测试环境,进行完整的功能验证。
  • 预发:在功能测试通过后,可以进行数据的预发布,在预发环境进行简单的用例抽检。
  • 灰度:通过预发验证后,数据可以发布到灰度环境,经历一段时间真实流量的验证,在此期间也可以进行一定的对比测试验证上线功能的效果。
  • 生产:灰度流量验证通过后,数据就会部署到生产环境正式成为小布助手的新功能和用户见面。

4.技能平台使用简介

4.1 整体流程

接下来将会以云端技能平台为例简述平台的使用方式

技能上线流程如下:

技能平台为技能上线提供了一套标准流程,完整流程中的各个节点都可以根据实现需要进行一定的调整。

技能上线主要分为三个步骤:

1. 领域管理  

用户通过平台管理端创建语义理解相关数据,包括但不限于领域,意图,语料,槽位,词典等。语义理解相关数据创建完成后进行模型训练和模型测试。

2. 技能管理  

技能管理主要创建对话所需要的数据,包括但不限于技能,订阅意图,条件判断,技能回复等。对话和语义相关数据创建完成后就可以进行对话测试,进行相关数据的调试。

3. 数据发布

用户在平台管理端创建的全部数据都属于离线数据,这些数据的变化不会影响在线服务。数据上线需要通过发布流程进行,用户可以将数据发到各个验证环境进行测试验证,并且在预发和灰度环境进行真实流量充分验证后即可将数据部署到生产环境。所有环境数据的推送都可以通过平台进行可视化操作,用户可以实时跟进数据的发布状态,并且根据验证的结果决定是否继续进行发布流程。

4.2 示例介绍

接下来以简单的实例带入平台的使用。

1. 在平台创建需要的领域,选择具体的召回方案

召回方案分类两类:

文本分类:需要训练算法模型,适合语料较多,高精准召回场景

文本匹配:采用通用语言模型进行句向量转换,利用检索方案进行召回。适合少语料,召回要求不高的场景

2. 在领域下创建意图

默认的other意图做拒绝使用,其他意图可以手动任意添加,每一个意图即表示一个召回节点。

3. 在意图下创建槽位

槽位提取主要支持两种方式

自建词典:用户可以在词典管理界面新增和上传自建词典

通用提槽:平台提供通用的槽位提取能力

设置为纯实体的槽位,具有纯实体召回能力

4. 新增语料

平台支持三种召回语料

规则:用户可以输入正则表达式,平台的规则引擎将会加载这些规则语料实现召回。规则适用于确定场景的召回,编写正则表达式的时候需要注意对范围的限制防止对其他意图的误召回。

训练语料:用户可以新增或者导入需要召回的语料。如果训练方案选择的是文本分类,这里的语料将会用于模型训练,适用语料较多的场景。如果训练方案选择的是文本匹配,这里的语料将会用于建立向量空间,后续召回通过检索的方式实现,该方式适用于语料较少的场景。用户可以根据实际情况按需选择。

关键词增强:增加召回能力,通过关键词的添加可以增加召回的准确度

在完成召回语料的创建后,用户可以上传测试语料,用于对语义部分的测试使用。

5. 进行召回模型训练

在完成各种语料的创建之后,就可以进入到模型训练阶段。

这一阶段根据训练方案的不同将会产生不同的行为:

文本分类:触发部署在机器学习平台的训练脚本进行模型训练,训练完成后上传模型文件到指定目录,推送数据到对话测试环境,通知对话测试环境的在线模型服务更新模型。

文本匹配:推送数据到对话测试环境,通知该环境的检索服务进行向量空间的构建。

模型训练完成后,用户就可以通过批量测试验证语义理解部分,测试完成后将会生成测试报告用户下载报告进行查看。根据测试报告可以持续对语义部分进行调校。

6. 创建技能,订阅意图

在完成语义部分后就可以进入对话部分,首先创建新的技能。然后进入技能选择该技能需要订阅的意图。

7. 设置回复

这一步用户可以根据自己的实际需求进行回复配置,每一条回复都可以增加各类限制条件,只有当全部限制条件都满足的情况下才会出对应的回复。目前平台主要之处文字卡片和payload两种回复形式,后续平台还会支持更多的回复形式,敬请期待。

8. 数据发布

在完成了语义和对话数据的创建和测试后,就可以进入到发布阶段。首先进行发布单的创建,当前发布可以通过三种维度进行。

打包发布:以技能为主,将关联的领域数据进行打包发布

领域发布:只发布领域相关数据,包括领域,意图,槽位,词典等。

对话发布:只发布技能相关数据,包括技能,回复,映射关系等。

发布流程需要按照标准流程在每一个环境进行验证工作,只有验证通过后才能进入到下一个阶段。

9. 数据回滚

如果在上线之后发现新上线的数据产生了问题可以进行回滚操作,将数据回滚到上一个稳定版本。

10. 数据下架

某个技能或者领域数据不再需要,或者需要紧急删除时可以进行下架操作。新建一个下架单,选择一个数据维度进行下架操作。

下架和回滚操作也属于部署操作的一部分,所以也需要遵循发布流程,在每一个环境进行验证验证后才能最终发布到线上。

5. 展望与未来

未来平台的发展方向依然是以能力输出为主,同时也会有一些不同的变化。主要体现在以下几个方面。

算法能力

  1. 持续探索预训练语言模型在泛化及通用智能上的应用。针对不同应用场景构建不同的预训练方案及模型
  2. 当前语义理解能力基本补全及完善,但是在对话策略、对话的灵活性、多样性上仍然有较多的工作需要去承接
  3. 构建更通用有效的语义表征算法能力,进一步提升语义表征空间的泛化能力。

工程能力

组件服务化,在平台发展过程中将部分通用化能力拆分为独立的服务沉淀为原子化能力,可以提供业务无关功能,达到组件最大化复用。

开放生态,对外依托开放平台吸引更多的开发者来丰富小布的技能生态。对内提供平台化解决方案,帮助业务提升技能开发效率。

有关零代码上线小布对话技能:技能平台的实践与思考的更多相关文章

  1. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  2. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  3. ruby-on-rails - Rails 源代码 : initialize hash in a weird way? - 2

    在rails源中:https://github.com/rails/rails/blob/master/activesupport/lib/active_support/lazy_load_hooks.rb可以看到以下内容@load_hooks=Hash.new{|h,k|h[k]=[]}在IRB中,它只是初始化一个空哈希。和做有什么区别@load_hooks=Hash.new 最佳答案 查看rubydocumentationforHashnew→new_hashclicktotogglesourcenew(obj)→new_has

  4. ruby-on-rails - 浏览 Ruby 源代码 - 2

    我的主要目标是能够完全理解我正在使用的库/gem。我尝试在Github上从头到尾阅读源代码,但这真的很难。我认为更有趣、更温和的踏脚石就是在使用时阅读每个库/gem方法的源代码。例如,我想知道RubyonRails中的redirect_to方法是如何工作的:如何查找redirect_to方法的源代码?我知道在pry中我可以执行类似show-methodmethod的操作,但我如何才能对Rails框架中的方法执行此操作?您对我如何更好地理解Gem及其API有什么建议吗?仅仅阅读源代码似乎真的很难,尤其是对于框架。谢谢! 最佳答案 Ru

  5. ruby - 模块嵌套代码风格偏好 - 2

    我的假设是moduleAmoduleBendend和moduleA::Bend是一样的。我能够从thisblog找到解决方案,thisSOthread和andthisSOthread.为什么以及什么时候应该更喜欢紧凑语法A::B而不是另一个,因为它显然有一个缺点?我有一种直觉,它可能与性能有关,因为在更多命名空间中查找常量需要更多计算。但是我无法通过对普通类进行基准测试来验证这一点。 最佳答案 这两种写作方法经常被混淆。首先要说的是,据我所知,没有可衡量的性能差异。(在下面的书面示例中不断查找)最明显的区别,可能也是最著名的,是你的

  6. ruby - 寻找通过阅读代码确定编程语言的ruby gem? - 2

    几个月前,我读了一篇关于ruby​​gem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题:

  7. ruby - Net::HTTP 获取源代码和状态 - 2

    我目前正在使用以下方法获取页面的源代码:Net::HTTP.get(URI.parse(page.url))我还想获取HTTP状态,而无需发出第二个请求。有没有办法用另一种方法做到这一点?我一直在查看文档,但似乎找不到我要找的东西。 最佳答案 在我看来,除非您需要一些真正的低级访问或控制,否则最好使用Ruby的内置Open::URI模块:require'open-uri'io=open('http://www.example.org/')#=>#body=io.read[0,50]#=>"["200","OK"]io.base_ur

  8. 程序员如何提高代码能力? - 2

    前言作为一名程序员,自己的本质工作就是做程序开发,那么程序开发的时候最直接的体现就是代码,检验一个程序员技术水平的一个核心环节就是开发时候的代码能力。众所周知,程序开发的水平提升是一个循序渐进的过程,每一位程序员都是从“菜鸟”变成“大神”的,所以程序员在程序开发过程中的代码能力也是根据平时开发中的业务实践来积累和提升的。提高代码能力核心要素程序员要想提高自身代码能力,尤其是新晋程序员的代码能力有很大的提升空间的时候,需要针对性的去提高自己的代码能力。提高代码能力其实有几个比较关键的点,只要把握住这些方面,就能很好的、快速的提高自己的一部分代码能力。1、多去阅读开源项目,如有机会可以亲自参与开源

  9. 叮咚买菜基于 Apache Doris 统一 OLAP 引擎的应用实践 - 2

    导读:随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时OLAP数据库,构建一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。经过调研选型,最终引入ApacheDoris作为最终的OLAP分析引擎,Doris作为核心的OLAP引擎支持复杂地分析操作、提供多维的数据视图,在叮咚买菜数十个业务场景中广泛应用。作者|叮咚买菜资深数据工程师韩青叮咚买菜创立于2017年5月,是一家专注美好食物的创业公司。叮咚买菜专注吃的事业,为满足更多人“想吃什么”而努力,通过美好食材的供应、美好滋味的开发以及美食品牌的孵

  10. 7个大一C语言必学的程序 / C语言经典代码大全 - 2

    嗨~大家好,这里是可莉!今天给大家带来的是7个C语言的经典基础代码~那一起往下看下去把【程序一】打印100到200之间的素数#includeintmain(){ inti; for(i=100;i 【程序二】输出乘法口诀表#includeintmain(){inti;for(i=1;i 【程序三】判断1000年---2000年之间的闰年#includeintmain(){intyear;for(year=1000;year 【程序四】给定两个整形变量的值,将两个值的内容进行交换。这里提供两种方法来进行交换,第一种为创建临时变量来进行交换,第二种是不创建临时变量而直接进行交换。1.创建临时变量来

随机推荐