Generator-Evaluator重排模型在淘宝流式场景的实践

news2024/12/28 20:38:09

cab9ceb5e8516249c66a1f43a31d28dc.gif

除了相关性,复杂信息流推荐场景还需要兼顾多样的业务需求,包括打散(多样性),流量调控,多展示形态/多路供给融合等。传统推荐系统采用pipeline的形式,分步处理上述需求,缺少统筹优化,这些模块之间常出现矛盾与覆盖,限制场景推荐效果。我们提出全新的基于Generator-Evaluator(GE)架构的重排模型,它不仅能够突破传统相关性贪心排序的范式,以序列整体效果为目标生成序列,还能突破pipeline的推荐范式,在一个模型中有机融合复杂业务规则,给出end2end联合最优解。我们在淘宝信息流场景验证了提案的有效性,并全量上线。

2130b95971947983b93413de408329ee.png

引言


  信息流场景面临的复杂挑战



复杂信息流可能包含不同类型、展示样式丰富的供给:文字、图片、视频、货架等,需要用一个统一的模型给不同类型的内容做排序。我们将业务需求总结为四大类:流量控制、多样性、组间排序以及定坑插入。纷繁复杂的业务需求可以拆解为这四个问题或者他们的组合。传统推荐系统往往需要构建pipeline,分步应对上述挑战。pipeline缺少统筹优化,时常会出现需求逻辑冲突与相互覆盖,无法获得联合最优解。

重排模型在淘宝不断发展,经历了3版迭代:V1版基于context特征增强的DNN-based判别式模型(贪心排序)[1]、V2版基于seq2seq结构的pointer-network生成式模型(贪心排序)[2]、V3版基于generator+evaluator架构的模型(生成式模型+判别式模型有机融合,考虑序列整体最优,非贪心排序)。这3版重排模型在淘宝不同的业务场景均拿到了明显的业务效果。今天我们聚焦于信息流场景,介绍如何利用V3版重排模型,突破pipeline的推荐范式,将四大类业务需求融入模型,给出end2end联合最优解。在淘宝信息流场景上,新模型实现了相关性与业务指标双增长,最终全量上线。

  GE架构介绍

V3版模型由generator+evaluator两部分组成,在强化学习中generator也可以称为actor(agent),evaluator也可以称为simulator。在我们的实现中,generator是基于pointer network的seq2seq生成式模型,它负责基于一个输入序,端到端地输出一个新的重排序。

9f868f7deefd866a9cb2eccb3208abb1.png

EG架构的重排模型相比于监督学习的重排模型的一个优势是,generator不需要使用监督学习的方式训练,人为指定一个“最优序”作为label供模型学习,generator不需要学习生成我们人为给定的排序结果,因为人为给定的结果肯定是次优的。如果有一个evaluator模型能够近乎模拟线上用户的真实反馈,那么generator通过强化学习的方式,对着这个evaluator模型给出的反馈去训练是更合理的,不断尝试最大化获得的reward。如果数据中有一些非贪心排序范式的排序结果能够获得更好的线上指标,generator也会趋向生成这种模式的排序结果,从而突破贪心排序的范式,生成一些创造性的排序。



因此generator模型是通过探索/采样的方式,在训练初期,先尝试生成一些(不一定那么好的)序列,然后假设evaluator能够评估序列好坏,它能够给出用户对各种序列的反馈的估计,因此这个evaluator的打分就相当于对generator生成出的序列的reward。如果reward是正的,generator就调大生成这个序列的联合概率,相反,如果收到的reward是负的,generator就降低生成这个序列的联合概率。generator的训练目标是要使自己产生的序列能够最大化获得的evaluator给出的reward,所以是一个面向reward最终效果优化而不是面向模仿监督信号的模型,相当于一个强化学习框架。我们的generator就相当于agent,evaluator相当于真实环境的模拟器,generator通过不断探索试错,(基于模型参数)自主尝试各种action,并基于收到的reward不断调整自己的行为(调整模型参数),期望能够最大化获得evaluator反馈的reward。所以一开始generator可能都是生成一些随机的序列,随着训练的进行,generator会逐渐懂得生成一些能够最大化reward的序列,如果这个来自evaluator的reward与线上用户的真实反馈是相对保持一致的,那reward变大也就意味着线上效果会获得提升。

EG架构的重排模型,还有一个优势是能够方便地实现店铺打散、曝光宽度、曝光占比控制等业务目标,因为常用的贪心排序范式的模型,模型在打分的过程是不知道最终曝光的序列是怎样的,因此没办法端到端控制商家连续重复、某些类型曝光占比不足等问题,只能在按照模型分排序后做后处理。而EG架构这种生成式重排,generator模型在打分的过程中是直接生成最终排序的,因此在生成的过程中能够感知到生成的序列中商家是否重复、某些类型的曝光占比是否不足等问题。

f173af241cb42ddfb474f9204bc657c5.png

问题设定与符号定义

在全文中,一些表述比如:“商品/item”都可以理解为一个意思,表示推荐的一个独立载体;“序列/列表/排列”表示推荐系统中一页返回的多个商品构成的有序的推荐结果。

给定一个包含M个候选商品的集合31a35021f592fdfee680aa4bd990e424.png,一个用户090dc3d7b22b5d87f597af974ecf9f3d.png,还有一个商品序列奖励函数a6b9094480b77ec63a272b4526551e7e.png,由偏好权重w加权求和而得,重排的目标是要找到最优的序列aeb3fe26f02fff97f559a44393b2cb60.png,使得生成的序列能够最大化获得的reward:

26bc262e639a77a07656aa89ff263c52.png

其中生成的每个序列长度为N,并且6d584d48e24bfc2bb5a1cc1201eb1e74.png。在本文中,我们假设奖励函数f941bef43c33982fba3fcbd43be6ca35.png为线性:

22cc15e1e7d543c69ca07ac85ca43335.png

其中U表示效用函数,4cfc89f3b174ee51045d7631ffb1db96.png是我们关心的效用函数个数。因为w表示每个效用函数的相对重要性,它也被称为偏好权重。81df703cc78b481ebd9e6733a97def05.png通过一套人为设定的w计算而得,然后重排模型用参数表示,经过训练得到近似的指定w下的e87d6a671616d784ec7112650ae3dac3.pngedbe84006de35def98b532fae3000ee3.png的映射。

我们表示每个用户u为一个embedding向量902bccd9faf4152e6406905c9c895b2c.png,同样地,一个候选商品被表示为一个特征向量c0e1b708949fc05addc5524f672c6843.png。一个候选集合被表示为M个embedding的集合c230346b1266e90d32bdde664dc0eb14.png,重排模型选出的长度为N的商品序列可以被表示为一个矩阵9d72c839a0f6e6045e8b81ca8d5d5c57.png,也就是N个商品embedding的堆叠7bab75928a76bb012b2f7ec23178e623.png

用户-商品的交互行为可以用向量f3c9f0db0166b1f8b848d7f547bde3a5.png表示,其中交互行为向量e87b6321f160b1ef0d19c8f1a5358518.png中的每一个元素可以是:曝光、点击、购买、视频观看时长等等,取决于特定的应用场景。而用户-商品序列的交互行为可以被表示为矩阵71f4c5f563320c6dd8e19301b38e1b78.png。注意,我们没有所有M个候选商品的交互行为,因为只有其中的N个候选商品会在最终的推荐列表中,其余的商品用户不会看到。

每个用户-商品序列的交互行为会被记录成一条离线日志样本,一条样本也就是一个元组4aac583aa7e7c3e5ed284a5e3659782e.png。日志数据集f893e722ba92e99be3ca6fc7559b03d2.png4bb125b4cb876656af32a64307e95279.png,其中e15e8f1c86c5158f7872b96a74068467.png是记录下来的用户-商品序列的交互行为的数目。

一个效用函数是f6ab698e68457ad186c4c7001c75356f.png到一个实数的映射,即:979efcc4270859ca9c5458816c93b4f8.png。其中实数1b6b5a612094e04126bfe0265f3a7531.png分别表示对应的embedding维度。

c79b051aad011d773c1c746dee10a3bb.png

Generator

generator是一个encoder-decoder结构的模型,它的主要作用是从M个候选item中生成出长度为N的序列,其框架图如下所示。encoder负责对输入序进行编码,得到每个商品编码后的embedding,以及输入序整体的embedding,decoder会将输入序整体的embedding作为初始state,使用rnn一步一步地生成出最终的排序结果。

d706f5915691dc5b23ce7aa2e9de238d.png

  Encoder

在把候选商品集合输入给encoder之前,首先需要进行特征增强和embedding lookup的操作。一个商品的增强特征来源于候选集合,比如商品的历史点击率在整个候选集合中的排名。这是一个非常有效且简单的方式,告诉模型每个商品与它所在的候选集合之间的关系。然后ID特征会被转成实值embedding以方便数值计算。



Encoder是DeepSet的结构,因为它对输入商品的顺序不敏感,其结构图如下所示。DeepSet对于复杂的应用场景可能是更合适的encoder结构,因为要想找到一个好的混合了文本、图片、视频的初始输入序列是不容易的,差的初始输入序可能会伤害重排模型的效果。使用DeepSet不需要指定一个初始输入序,因为869db2f74b10046aa69caa777816333f.png已经包含了重排模型为了生成一个好的序列需要知道的所有信息。DeepSet定理描述了序不敏感函数,推导出了深度模型中排列不变性的充要条件,其模型结构入下图所示:

614d16bac0e5ed831b8fa759814ce121.png

  Decoder

Decoder是基于Pointer Network的结构,其结构图如下所示。它每次会从候选集合中选择一个商品,然后立即更新上下文信息,然后选择下一个商品。

b2839700c941b36ee092515d5d26e8ac.png

对计算出的attention概率分布会采用Masking机制,主要有两点原因。首先,一个在前序步骤中已经被选出的商品不应该再被选择了,所以已被选出的商品的attention值需要被mask成0。其次,业务规则可能会要求模型在结果列表中的一些特定位置放一些特定的商品。因为一个顾客可能是通过点击一个trigger商品来到当前推荐场景的,所以需要把trigger商品强制放在推荐列表的最前面,以便提供更多关于trigger商品的信息给用户。在这种情况下,除了trigger的所有商品的attention值应该被mask成0。



同时,generator使用一个采样机制选择商品是至关重要的,因为这会让generator在相似的state尝试不同的action,最终能够帮助generator找到更优的序列生成策略。最简单的选择是Thompson Sampling,会依据每个商品mask后的attention值成比例地选择商品。一个更好的选择可能是Random Network Distillation,倾向于选择一个在之前相似的state下很少被选择的商品。

0d75e9408c580ee86bfc6b6d5deb122d.jpeg

Evaluator

  模型介绍

evaluator包含了一系列的效用函数,一个效用函数U是从一个商品序列41e77cd7f59add2e9f3c8c0d618d1240.png到一个实数的映射,即09e4687f0ce9e394531085f89462ecc0.png,表示在某种视角下这个序列的质量分数,在相关工作中这通常被描述为一个任务。

一些效用函数通常来自于业务规则以及好的排序结果应该满足的先验知识,比如商品多样性,这些效用函数有解析公式,能够被直接计算出来。其他的一些效用函数,比如用户对序列的交互概率,则不得不需要使用模型预测,模型会通过离线数据训练出来。模型一旦训练好后,会被用作为预先定义好的效用函数。



fa12ceb1daeda0deed26dfbcd7a3dec9.png

evaluator的模型结构如上图所示。在经过与generator一样的特征处理后,会被5个聚焦于商品序列不同方面的模型channel处理,5个channel的输出结果会被concat起来,然后通过一个MLP转变成最终的预测分。

  业务规则与模型的融合

我们将现实业务中纷繁复杂的任务总结为四大类,包括:定坑插入、流量控制、多样性、分组排序,然后我们基于generator-evaluator框架的重排模型能够无缝地融合这些目标。

  • 流量控制



流量控制确保来自特定群组的内容能够得到更多的曝光机会。可以从多个角度理解。比如:从公平性的角度,这些内容是受保护的少数内容;从平台生态视角来看,新创作的内容会被优先分发;从一个业务场景的功能定位的角度来看,推广上新内容的业务场景可能会更加强调新的内容而不是旧的内容。流量控制可以通过调整占比以及曝光位置两个因素实现:

5cec1f456f2ef31d16c8adbc243b4d62.png



其中上标f表示流量控制,p表示一页的结果,b表示训练的一个batch,3d4c4677c61e4a66ff0f84f549651eb0.png表示曝光占比的阈值。我们复用一些符号,i既表示位于位置i的商品,又表示一个商品在结果列表中的位置下标。71ecca747277fe50d77b006f72e741e5.png是包含所有属于分组g的商品的集合,49e128e51717c436b8607fb80b30d42e.png表示一页的大小,也就是一页的坑位数,131d84680c23d9ff4bd7e3d975be0872.png是指示函数,7ab113627484760ab6c714944b483893.png表示第i个商品的曝光位置,029cb6f9ce3bd5144d27afec3570dea6.png表示曝光位置的阈值。

简单来说,这个算法是一个“抓大放小”的思想,如果整体没问题,没必要纠正其中个例的问题,如果整体有问题,那就需要对其中每一个不满足要求的个例都进行纠正与惩罚,才能逐渐达到整体满足要求的目的。

  • 多样性



多样性意味着推荐结果列表中应该包含不同群组的商品。群组的概念可能包括:商家、类目、货源、商品展示类型(比如文本、图像、视频)。一个电子商务系统通常会考虑多个群组的多样性。多样性的reward可以写成:

a5adf3a6f171ed8caef1d44675072ea2.png

其中上标d表示多样性,g_i表示位于位置i的商品所属的群组。a6cc93b6b137ba205517cc5c40c0ff6e.png是在商品i前的一个滑动窗口中的多个商品所属的群组的集合,即:

3e01bde253d210880b0cd2e4ec208dcd.png

其中2695bd4cc5a566c89d87204016ce6e6e.png是多样性的滑动窗口的长度。如果令cf46cab712d919bced26fe110f4ea1f8.png则表示提升整个列表(而不仅是一个滑动窗口内)的多样性。

  • 组间排序



组间排序意味着属于特定群组的商品应该以一个很大的概率被排在属于其他群组的商品的前面。在一个推广上新的场景,可能会倾向于优先展示3天内发布的新商品,然后才是展示发布超过3天的商品,以致于能够确保用户总能看到最新发布的内容。在另一些场景,被用户关注的商家的商品通常来说应该被排在用户未关注商家的商品的前面。组间排序能通过添加检查商品对的群组优先级的reward函数来实现。

cf4e1960ca4994744d01d61006184fd5.png

其中上标o表示组间排序,priority表示预定义好的群组的优先级函数。

  • 定坑插入



定坑插入是一个非常严格的任务,意味着一个给定的商品必须被放在结果列表中的某个特定位置。比如用户可能会通过点击一个trigger商品来到一个推荐场景,需要强制把那个trigger商品放在推荐列表中非常靠前的位置,为了提供给用户更多关于trigger商品的信息。乍一看似乎很简单,因为我们总是可以在推荐结果列表生成以后再把trigger商品放在列表的顶部。然而,我们认为如果重排模型想要做好类似多样性和流量控制的任务,那让重排模型感知到trigger商品是很重要的。比如,在最后单独将trigger商品放在一个已经生成好的推荐结果列表的前面可能会导致头两个商品的商家重复,这会打破多样性的要求。对这种任务添加一个reward函数不会很有效,因为仅靠一个reward函数不能提供一个强保证。取而代之,正如在上文generator中介绍的,我们采用masking机制来实现定坑插入逻辑。

376e56a359172a41151e62f2ff65d073.jpeg

模型训练方法

在generator训练之前,会首先使用纯正的监督学习方式充分训练evaluator。目前对于evaluator,我们使用经典的交叉熵损失函数训练得到一个分类模型:

576808b135a6cdd57f5c3031d0627ce4.png

其中177d4f4fdd04d2b60f2ada7cd185edd0.png是一个类别的one-hot label,4194c9692179c7dfb9c316472388edf5.png是对应类别的模型预测值。evaluator可能会预测生成的推荐结果列表是否会引导到某种特定的用户交互行为,比如点击以及各种交互的兴趣强度。

Evaluator-Generator架构中的generator,不会按照监督学习的方式,最大化某一个人为指定的输出序列的联合概率,而是像强化学习一样,generator通过一些带有随机性的探索机制,尝试让自己的生成结果能够最大化获得的reward。这个reward,既包含evaluator对生成序列点击率的模型预估分,又包含一些规则性的判断生成序列是否满足各项业务规则的评分,然后将这些分数通过加权求和的方式,融合到一个最终整体的reward上,这个reward是一个序列整体的reward,然后generator的训练目标就是不断最大化这个reward,手段是根据reward正负和大小调节生成具体序列的概率。



对于generator的训练,我们使用一个基于REINFORCE的方法。REINFORCE是一个经典的policy gradient算法。在强化学习中,policy是一个state到所有可能action的概率分布的一个映射,期望能够最大化total reward。简单来说,policy告诉我们在给定state下应该采取哪个action。在我们的模型中,公式(5)在policy中扮演了一个至关重要的角色,其中state就是6514b5db3be9ad14fffe0bb32d32e479.png,然后M个可选商品的概率分布就是881aa301318c05ab9e2ddb64dd5f1f46.png。假设对于一个用户u和一个候选商品集合cb24872ebb13cd3ab92c1d40c8649b5e.png,generator生成了一个结果列表d3c40f727b8991ba8f8ece2f445a1c37.png记为c24e3592d409e1db3aca7a8b640fe749.pngfef8d94db86dd536adb08321ffeaa01e.png是一个商品列表的指示器,比如c6b4954e0a63fc7ca0dc1dda45b4094b.png表示候选集合中的第m个商品被放在了输出列表中的第n个位置。这里我们假设在候选集中进行任意排序得到f3ce552a8d26e1e08cd3b9b776f126d6.png。generator的损失函数4090bc0eec81fe9628f09e3ae833644e.png为:

9090e531d8dee70dd5a95f7d46193fd8.png

其中b04f7b352f93c5e4b72000289d195b7f.png是generator生成的重排后的商品序列,8d6ba16521eefd745d57ce578aba6f47.png是线上日志记录下来的曝光序列,这两个序列的reward差值6c52bfa76a5618fe815178155fcfd244.png作为advantage函数。在这个loss中,我们假设每个动作对advantage值的贡献相等。

我们知道先进的训练方法比如PPO,尽管如此,基于REINFORCE的方法也表现得很好,所以我们把这个选项留待后续研究。我们观察到梯度裁剪对训练有很大好处。



总结一下这种强化学习训练方式的两个好处:

  1. 不需要显式地指定label,在我们重排的场景下,就是不需要显式地指定模型应该输出怎样的重排序。因为我们根本不知道最优的重排序是什么,或者是有可能存在较多种优秀的重排序,没法知道哪个更好。这种情况下,我们就不需要去让模型模仿监督信号,而是要直接面向reward也就是最终效果进行优化,只要是能够获得更高reward的行为,就是更好的行为,有可能找到比贪心排序更好的组合更优的排序结果。正所谓“不管黑猫白猫,抓到老鼠就是好猫”,只面向最终结果,只要结果是好,不强求一定要模仿怎样的行为。

  2. 由于这个reward R是环境给予的反馈,在我们的实践中就是evaluator给予的反馈,它跟generator的模型参数是没关系的,因此我们调整generator的模型参数,去最大化这个最终获得的总reward R,是不需要对reward R算gradient的。也就意味着,如果假设reward是一个函数产生的,就算产生reward的这个函数是不可导的也没关系,因为我们不需要对产生reward的这个函数进行求导,就算它是一个黑盒,我们不知道它的计算式子也没关系,只要我们拿到它最终的值就可以了。因此这个reward函数可以任意复杂,既可以是模型预估分,也可以是根据业务规则计算出来的分数,方便融入各种业务要求,因此非常适用于我们这个业务规则约束较多的场景。

1b855270ff782c17c450d4a173bc2152.jpeg

实验结果

我们在淘宝信息流场景实践了EG架构的重排。generator模型的输入是混排后分数最高的20个候选item,这20个item中会包含不同类型的供给,它们会作为一个集合送进generator模型(也就是actor)打分,然后generator生成一个长度为10的重排后的序列。 训练结束后,我们只将训练好的序列生成器generator上线,evaluator不上线。



evaluator是判别式模型,给每个序列打一个分,希望用户反馈更多的序列的evaluator分数比用户反馈更少的序列的evaluator分数要高,因此evaluator离线评估看的是auc指标。在我们的实验中,evaluator的auc大概为0.75左右。

generator的离线评估指标是better percentage,含义是所有请求的样本中,generator生成的重排序获得的evaluator score,比线上真实曝光序的evaluator score更高的比例。在我们的实践中,generator的better percentage通常能达到70%+左右,也就是说如果evaluator的评判打分是靠谱的,那么大概有70%的请求,generator能够生成出比之前的线上曝光序更好的序列。



该重排模型成功上线并取得了显著的线上效果。

539c44278f052878d6826c7c2c3066c7.jpeg

参考文档

[1] MiDNN:Tao Zhuang, Wenwu Ou, and Zhirong Wang. Globally optimized mutual influence aware ranking in e-commerce search. In IJCAI, 2018.

[2] seq2slate: Irwan Bello, Sayali Kulkarni, Sagar Jain, et al. Seq2slate: Re-ranking and slate optimization with rnns, 2018

[3] PRM: Changhua Pei, Wenwu Ou, Dan Pei, Yi Zhang, Yongfeng Zhang, Fei Sun, Xiao Lin, Hanxiao Sun, Jian Wu, Peng Jiang, and Junfeng Ge. Personalized re-ranking for recommendation. In RecSys, 2019.

[4] DLCM: Qingyao Ai, Keping Bi, Jiafeng Guo, and W. Croft. Learning a deep listwise context model for ranking refinement. In SIGIR, 2018.

[5] GSF: Qingyao Ai, Xuanhui Wang, Sebastian Bruch, Nadav Golbandi, Michael Bendersky, and Marc Najork. Learning groupwise multivariate scoring func- tions using deep neural networks. In ICTIR, 2019

[6] MiRNN:Tao Zhuang, Wenwu Ou, and Zhirong Wang. Globally optimized mutual influence aware ranking in e-commerce search. In IJCAI, 2018.

[7] Exact-k: Gong, Yu, et al. "Exact-k recommendation via maximal clique optimization." Proceedings of the 25th ACM SIGKDD international conference on knowledge discovery & data mining. 2019.

[8] EGRerank: Guangda Huzhang, Zhenjia Pang, Yongqing Gao, et al. Aliexpress learning-to-rank: Maximizing online model performance without going online. TKDE, 2021

a1c643e8c6a38b5e6fe8af66fb8cc166.jpeg

团队介绍

我们是大淘宝技术-私域用户算法团队,负责淘宝商家私域产品(店铺、详情、关注)相关的算法,我们通过对海量数据的分析和学习,帮助亿万用户在商家私域高效地逛和买,辅助数千万商家运营客户。同时我们也是一支注重技术创新,乐于分享的团队,不少成果已经整理发表在了AAAI、SIGIR、WWW、KDD等国际顶会上。这里有海量的数据、充足的计算资源、丰富的应用场景等着你来挑战!想进一步了解我们,可以通过邮件tieyi.lq@taobao.com联系我们!

¤ 拓展阅读 ¤

3DXR技术 | 终端技术 | 音视频技术

服务端技术 | 技术质量 | 数据算法

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/630511.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【博客650】irate适用于绘制细粒度灵敏图,但警惕用于告警

irate适用于绘制细粒度灵敏图,但警惕用于告警 1、irate解析 作用: irate(v range-vector) 函数用于计算区间向量的增长率,但是其反应出的是瞬时增长率。 原理: irate 函数是通过区间向量中最后两个两本数据来计算区间向量的增长…

C++表达式模板教程:从原理到应用的全面解析

C表达式模板教程 1. C表达式模板的引入 (Introduction to C Expression Templates)1.1 表达式模板的定义和作用 (Definition and Role of Expression Templates)1.2 表达式模板的历史和发展 (History and Development of Expression Templates)1.3 表达式模板在现代C中的地位 (…

java springboot VUE 在线学习平台系统开发mysql数据库web结构java编程计算机网页源码maven项目前后端分离

一、源码特点 springboot VUE 在线学习平台系统是一套完善的完整信息管理类型系统 前后端分离,结合springboot框架和VUE完成本系统,对理解JSP java编程开发语言有帮助系统采用springboot框架 (MVC模式开发),系统具有…

005Mybatis返回值(ResultMap 一对多,多对多)

属性 id 应该总是指定一个或多个可以唯一标识结果的属性。 虽然,即使不指定这个属性,MyBatis 仍然可以工作,但是会产生严重的性能问题。 只需要指定可以唯一标识结果的最少属性。显然,你可以选择主键(复合主键也可以…

DevOps系列文章之 远程部署的一种方案

远程部署的一种方案 sshpass 一个简单、轻量级命令行工具,提供非交互式密码验证 原理 ssh 直接使用 TTY 访问,以确保密码是用户键盘输入的。 sshpass 在专门的 tty 中运行 ssh,以误导 ssh 相信它是从用户接收到的密码使用 sshpass 是不安…

深入理解HashMap源码

文章目录 HashMap简介源码分析关键参数获取数组下标put方法resize扩容过程jdk1.7的扩容实现jdk1.8的扩容实现 get()方法remove()方法 总结 关于HashMap,一直都是一个非常热门的话题,只要你出去面试,一定少不了它! 本文主要结合 JD…

English Learning - L3 作业打卡 Lesson5 Day35 2023.6.8 周四

English Learning - L3 作业打卡 Lesson5 Day35 2023.6.8 周四 引言🍉句1: Publishers know that some people are self-conscious about what they read on public transport and so they put out different versions of a cover.成分划分弱读连读爆破语调 &#x…

实现表白墙

我们已经学习了Http以及Servlet类的相关知识 今天我们来实操一下,实现一个简单的既有前端又有后端的网站–表白墙 之前在学习前端的时候已经写过了表白墙的前端代码,存在两个问题 1.页面重启,数据丢失 2.数据只是在本地的,别人看不见 那么这样的问题我们要咋样解决呢? 引入…

黑马Redis视频教程高级篇(二:多级缓存)

目录 一、什么是多级缓存? 二、JVM进程缓存 2.1、导入案例 2.2、初识Caffeine 2.3、实现JVM进程缓存 2.3.1、需求 2.3.2、实现 三、Lua语法入门 3.1、初识Lua 3.2、HelloWord 3.3、变量和循环 3.3.1、Lua的数据类型 3.3.2、声明变量 3.3.3、循环 3.4…

Hadoop | 好用的脚本分享

知识目录 一、写在前面✨二、一键安装HA🍭三、Hadoop一键启动🔥四、一键启动可视化工具🍭五、结语🔥 一、写在前面✨ 大家好!我是初心,希望我们一路走来能坚守初心! 🏠 个人主页&a…

2023版一线大厂Java面试八股文(最新版)1000+ 面试题附答案详解,最全面详细

Java 面试八股文有必要背吗? 我的回答是:很有必要。你可以讨厌这种模式,但你一定要去背,因为不背你就进不了大厂。现如今,Java 面试的本质就是八股文,把八股文面试题背好,面试才有可能表现好。…

Python爬虫之Scrapy框架系列(21)——重写媒体管道类实现保存图片名字自定义及多页爬取

目录: 重写框架自带媒体管道类部分方法实现保存图片名字的自定义:1.爬虫文件:2.items.py文件中设置特殊的字段名:3.settings.py文件中开启自建管道并设置文件存储路径:4.编写pipelines.py5.观察可发现完美实现&#xf…

JetBrains 激活方式的区别

文章目录 简介激活方式 简介 JetBrains 是一家全球知名的软件开发工具公司。 JetBrains 成立于 2000 年,总部位于捷克共和国的布拉格。该公司致力于为开发者提供高效、智能和创新的软件开发工具,以提升开发人员的生产力和开发体验。 JetBrains 的主要…

Redis的主从复制、哨兵机制、集群

一、主从复制 1、定义 主:master以写为主当master数据变化的时候从:slave以读为主自动将新的数据异步同步到其他slave数据库 2、作用 读写分离、容灾恢复、数据备份、水平扩容支撑高并发。 3、使用方式——配从不配主 权限配置:master如…

【图书推荐 | 13】后端系列

【赠书活动第十二期 】 图书推荐 本期书籍:后端系列 图书列表 本期图书列表: Spring Cloud 微服务快速上手项目驱动零起点学JavaNode.js 从基础到项目实战Diango Web 开发实例精解Flask Web 全栈开发实战精通Hadoopsmysql 数据库基础与实战应用Neo4j 图谱…

指针--用指针变量作函数参数的实例(按值调用与模拟按引用调用)、函数指针及其应用

一、用指针变量作函数参数的实例 思考题&#xff1a; 例题&#xff1a;从键盘输入某班学生某门课成绩&#xff08;每班人数最多不超过40人&#xff0c;具体人数由键盘输入&#xff09;&#xff0c;是分析下列程序是否能实现计算并输出最高分以及相应学号。 #include <stdi…

群晖 NAS 外网访问设置 - 腾讯 DNSPod

目录 ​编辑 一、使用DNSPod&#xff0c;实现DDNS&#xff08;动态域名&#xff09; 二、公共概念厘清 三、腾讯DNSPod上详细设置步骤 1. 打开DNSPod.cn网站并登录 2. 登录成功后&#xff0c;选择【我的域名】-> 【添加域名】 3. 添加群晖NAS需要二级域名&#xff08…

Visual Studio封装静态链接库至新静态库,供程序调用

熟悉Windows开发的人都肯定了解静态链接库和动态链接库。 最近遇到一个问题&#xff1a; A静态库是使用VS编译&#xff0c;因为C版本的问题&#xff0c;并不能直接在Qt中被调用&#xff0c;因为会报头文件某处错误。 因为A库很大&#xff0c;同时又不想修改太多A库源文件&#…

开源社章程(2023版)

第 1 条 开源社是由志愿贡献于开源事业的个人志愿者&#xff0c;依 “贡献、共识、共治” 原则所组成的开源社区。第 2 条 开源社的英文名称为“KAIYUANSHE”&#xff0c;官方网站地址为 https://kaiyuanshe.cn/第 3 条 开源社的愿景为&#xff1a;立足中国、贡献全球&#xff…

English Learning - L3 作业打卡 Lesson5 Day36 2023.6.9 周五

English Learning - L3 作业打卡 Lesson5 Day36 2023.6.9 周五 引言&#x1f349;句1: So next time you are on a train, look around and see what other people are reading, but dont jump to any conclusions.成分划分弱读连读爆破语调 &#x1f349;句2: You will probab…