我们如何学会预测用户的请求并加快搜索结果的负荷

搜索提示(sjest)不仅是一项用户服务,还是一种非常强大的语言模型,可以存储数十亿个搜索查询,支持模糊搜索,个性化等等。 我们了解了如何在查询“查找”按钮之前使用最有趣的方法来预测用户的最终查询并加载搜索结果。


这项技术的引入-预渲染器-在移动开发,搜索运行时,日志和指标的开发中需要许多有趣的解决方案。 而且,当然,我们需要一个很酷的分类器来确定是否提前加载搜索查询:该分类器必须在下载加速,额外流量和搜索负载之间取得平衡。 今天,我将谈论我们如何设法创建这样的分类器。




1.这个想法行得通吗?


在研究任务中,事先很少有一个好的解决方案。 在我们的案例中,我们最初也不知道要建立足够好的分类器需要什么数据。 在这种情况下,从几个非常简单的模型入手非常有用,这将使您能够评估开发的潜在收益。


最简单的想法如下:我们将在搜索建议的第一个提示处加载搜索结果; 当提示更改时,我们将放弃先前的下载,然后开始下载新的候选者。 事实证明,这种算法效果很好,几乎所有请求都可以预加载,但是搜索后端的负载相应增加,用户流量也相应增加。 显然,这种解决方案无法实现。


以下想法也非常简单:并非在所有情况下都必须加载可能的搜索提示,而只有在我们有足够的信心确实需要它们时才加载。 最简单的解决方案是分类器,该分类器将根据sajest已拥有的数据在运行时直接运行。


第一个分类器仅使用十个因素构建。 这些因素取决于提示集上的概率分布(想法:第一个提示的“权重”越大,输入的可能性就越大)和输入的长度(想法:用户必须输入的字母越少,预加载就越安全)。 该分类器的优点还在于,为了构建它,没有必要发布任何东西。 可以通过在最简单的守护程序中发出一个http请求来收集候选者的必要因素,并且目标基于最简单的日志:如果用户的总请求完全匹配该候选者,则该候选者被视为“良好”。 可以在短短几个小时内组装一个这样的库,训练几个逻辑回归并构建散点图。


预渲染器的度量没有像通常的二进制分类中那样完整地排列。 只有两个参数很重要,但这不是准确性或完整性。


-请求总数, p-所有装扮者的总数, ep-成功渲染的总数,即 最终匹配用户输入的内容。 然后计算出两个有趣的特征,如下所示:


= fracp+repr1


= fracepr


例如,如果每个请求仅发出一个预渲染,并且成功完成了一半的预渲染,则该预渲染的效率将为50%,这意味着可以加快一半请求的加载速度。 同时,对于那些成功执行了请求的请求,不会创建额外的流量; 对于那些预提交失败的请求,必须设置另一个请求; 因此请求的总数是原始请求的一倍半,“额外”请求是原始请求数的50%,因此 =0.5


在这些坐标中,我绘制了第一个散点图。 他看起来像这样:



这些值包含相当多的假设,但至少已经很清楚,一个好的分类器很有可能会起作用:将数十%的请求的加载速度加快,将数十%的负载增加,这是一个有趣的变化。


观察分类器如何工作很有趣。 实际上,事实证明,请求的长度是一个非常重要的因素:如果用户几乎已经输入了第一个提示,并且很有可能同时输入,则可以进行预取。 因此,分类器的预测在查询结束时会急剧增加。


margin prefix candidate -180.424   -96.096    -67.425    -198.641    -138.851    -123.803    -109.841    -96.805    -146.568     -135.725     -125.448     -58.615      31.414     -66.754      1.716         

即使在输入请求的最后一个字母时发生预渲染,它也将很有用。 事实是,用户在输入请求后仍需要花费一些时间单击“查找”按钮。 此时间也可以保存。


2.第一次实施


一段时间后,有可能组装出一个完整的设计方案:该应用程序将搜索提示输入到最老的恶魔中。 除其他事项外,他发送了有关是否预加载第一个线索的信息。 接收到适当标志的应用程序下载了结果,如果用户输入最终与候选者一致,则呈现结果。


那时,分类器获得了新的因素,该模型不再是逻辑回归,而是一个CatBoost 。 最初,我们为分类器推出了相当保守的阈值,但即使它们使我们能够立即加载几乎10%的搜索结果。 这是一次非常成功的发行,因为 我们设法显着地改变了SERP下载速度的次要分位数,用户注意到了这一点,并开始从统计学上显着返回搜索:搜索的显着加速影响了用户执行搜索会话的频率!


3.进一步的改进


尽管实施成功,但解决方案仍然非常不完善。 对操作日志的仔细研究表明存在一些问题。


  1. 分类器不稳定。 例如,可能会发现,通过Yandex前缀可以预测Yandex查询,通过Yandex前缀可以预测Yandex查询,而通过Yandex前缀可以预测Yandex查询。 然后,我们的第一个简单的实现提出了两个请求,尽管可以很好地处理一个请求。


  2. Prerender不知道如何处理口碑提示。 单击字词提示会导致请求中出现额外的空格。 例如,如果用户输入了Yandex,则他的第一个提示将是Yandex;否则,第一个提示将是Yandex。 但是如果用户使用逐字提示,则输入内容将已经是字符串“ Yandex”,而第一个提示将是“ Yandex cards”。 这将导致灾难性的后果:已经下载的Yandex请求将被丢弃,而是将加载Yandex卡请求。 之后,用户单击“查找”按钮,并且...将根据Yandex的请求等待发行的全部内容。


  3. 在某些情况下,候选人没有机会获得成功。 搜索不准确的重合会直接导致问题,例如,候选人只能包含用户输入的单词中的一个单词。 或用户可以输入错误,那么第一个提示将永远不会与其输入完全匹配。



当然,即使这样有用,也要留下一个不完美的瑕疵。 逐字提示的问题使我特别生气。 我一直认为在Yandex移动搜索中引入单词对单词技巧是我在公司工作期间一直以来最好的实现方式之一,但是在这里,演示者不知道如何与他们合作! 丢人,别无他法。


首先,我们解决了分类器不稳定的问题。 选择的解决方案非常简单:即使分类器返回了否定预测,我们也不会停止加载先前的候选者。 这有助于保存其他请求,因为当同一候选人下一次返回时,您无需再次下载相应的问题。 同时,由于候选人是在分类器首次为他工作时下载的,因此,您可以更快地加载结果。


然后是众所周知的线索。 临时服务器是无状态的守护程序,因此很难实现与处理同一用户的先前候选者相关的逻辑。 要同时搜索提示以查找用户请求和没有尾随空格的用户请求,实际上意味着将RPS加上最简单的守护程序加倍,因此这也不是一个好选择。 结果,我们做到了:客户端向候选参数传递了一个特殊参数,该文本现在正在加载; 如果此候选对象(最多空格)与用户输入相似,即使当前输入的候选对象已更改,我们也会将其放弃。


此版本发布后,终于可以使用逐字提示输入查询并享受预取! 有趣的是,在此发行版之前,只有那些完成了使用键盘输入请求的用户时才使用了预取功能。


最后,我们在ML的帮助下解决了第三个问题:关于提示来源的附加因素,与用户输入的重合; 此外,得益于首次发布,我们能够收集更多统计信息并从每月数据中学习。


4.结果如何


这些发行版中的每一个都使即时下载量增加了百分之十。 最好的部分是,我们能够将预渲染性能提高两倍以上,而实际上没有涉及机器学习的部分,而只是提高了过程的物理性。 这是一个重要的教训:分类器的质量通常不是产品的瓶颈,但改进是最有趣的任务,因此开发会因此而分心。


不幸的是,即时加载的 SERP并非完全成功。 仍然需要渲染已加载的输出,这不会立即发生。 因此,我们仍然必须努力将即时数据下载更好地转换为搜索结果的即时呈现。


幸运的是,已实现的实现已经使我们可以将预渲染器作为一个相当稳定的功能来讨论。 我们还测试了第2节中描述的实现:它们全部一起也导致了用户自己开始更频繁地进行搜索会话的事实。 这是另一个有用的教训:服务速度的显着提高可以从统计上显着影响其保留。


在下面的视频中,您可以看到预渲染器现在在我的手机上如何工作。


Source: https://habr.com/ru/post/zh-CN455427/


All Articles