最简单的个性化形式,同时也是最有效的形式之一,是:如果购物者之前购买过某个产品,当他们搜索相关内容时,就提升该产品的排名。一个经常购买特定品牌巧克力曲奇的购物者,当他们搜索“曲奇”时,应该看到这些曲奇排名更高。这并非因为模型预测了偏好,而是因为有直接的行为证据。
当搜索请求包含用户标识符时(例如用户拥有开放会话的情况),控制平面会使用线程池并行运行两个 Elasticsearch 查询:
user_purchases 索引的购买历史查询,通过 term(user_id) 过滤到特定用户,然后将当前搜索字符串与该用户的产品标题进行匹配。这两个查询是并发运行的(互不等待),因此个性化查找不会给治理管道增加任何明显的延迟。
购买历史查询在将当前搜索字符串与存储的产品标题进行匹配时,会使用 Elasticsearch 的文本分析(词干提取、分词)。这意味着,搜索“cookies”将通过标准文本分析匹配到之前购买的“brownie cookies”,而无需精确的字符串匹配。
并非所有过去的购买都值得相同的提升权重。权重会考虑两个直观的因素:购物者购买该产品的频率,以及购买的最近程度。上周购买了 15 次的产品,比六个月前购买一次的产品,其信号要强得多。权重计算对频率使用对数缩放(以避免单个购买量大的商品压倒其他所有商品),对最近程度使用指数衰减(使旧的购买自然地随着时间推移而减弱)。
关于提升公式的数学细节,请参阅《无需 ML 后处理即可在 Elasticsearch 中实现搜索个性化》。
购买历史提升被组合到查询中,作为最外层的评分层,它包裹了第 3 和第 4 部分中的治理策略过滤器和提升,以及任何商业信号提升,例如利润和受欢迎度(我们将在第 7 部分中探讨)。这意味着,被治理策略移除的产品不会因为购买历史提升而重新出现。治理控制结果集;个性化调整结果集内的排序。没有购买历史的产品不会受到惩罚。它们的受治理排名得以保留,尽管在其他条件相同的情况下,具有相关购买历史的产品将排在它们之上。
购买历史是在每次搜索时从 Elasticsearch 查询的,而不是缓存在应用层。这是一个经过深思熟虑的设计选择。由于查询使用 Elasticsearch 的文本分析管道将当前搜索字符串与产品标题进行匹配,因此系统可以受益于与产品搜索本身相同的词干提取、分词和语言处理功能。如果采用缓存的内存查找,则需要重新实现该分析功能,或接受更粗略的匹配。
为了理解这种排序的重要性,考虑一个之前购买过橙汁,现在搜索“oranges”的购物者。购买历史查询通过文本分析将“orange juice”与搜索词“oranges”进行匹配,并计算该产品的提升。但治理层已经将“oranges”限制在农产品类别,完全排除了橙汁。橙汁的购买历史提升虽然存在于查询中,但它没有作用,因为在受治理的结果集中没有匹配的文档可以对其进行操作。购物者看到的是新鲜橙子,按相关性和个性化进行排名。治理的防护栏依然有效。
性能成本极小:购买历史索引很小(用户的购买历史通常是几十到几百个文档,而不是数百万),并且查询与 percolator 查找并行运行,因此它不会延长关键路径。
如果非登录用户或从未购买过“spring water”的用户进行搜索,他们可能会看到类似以下的结果:

另一方面,一位名叫 Carol 的用户拥有以下购物历史:

如果 Carol 搜索“spring water”,她将看到反映其过去购买行为的个性化结果。查看上面的购买历史,她购买了“Carbonated Spring Water”(绿色瓶装)约 40 次,最近一次购买是两天前。如果她搜索“spring water”,那么该产品就会被提升,因为我们知道她喜欢它。请注意,在非个性化结果中,Rubicon spring water 曾是首位结果。

个人购买历史对于有既定行为的回头客非常有效。但许多购物者是新用户、匿名用户,或者正在浏览其常规模式之外的内容。对于这些购物者,群组会员资格提供了一种不同类型的个性化,它基于购物者的身份,而非其过往行为。
一个素食购物者搜索“巧克力”时,应该看到素食巧克力排名更高。一个遵循清真饮食的购物者搜索“零食”时,应该看到清真认证选项突出显示。一个注重健康的购物者搜索“酸奶”时,应该看到益生菌选项得到提升。
产品本身已经带有其常规属性,包括 dietary_restrictions: ["vegan"] 或 dietary_restrictions: ["halal"] 等字段。问题在于,连接购物者群组与这些产品属性的逻辑应该存放在哪里。
天真的方法是,在应用层或搜索模板中硬编码这种映射:如果用户是素食者,就对 dietary_restrictions: "vegan" 添加提升。但这与第 1 部分中描述的应用层“意大利面条式代码”问题相同,并会产生相同的操作摩擦:添加新的群组或更改群组含义需要更改代码。
受治理的控制平面将群组逻辑保留在策略引擎中。群组策略连接两件事:购物者的群组会员资格(例如,“vegan”)和产品属性(例如,dietary_restrictions: “vegan”)。策略定义了这种连接:当属于素食群组的购物者搜索时,提升 dietary_restrictions 包含“vegan”的产品。
由于群组逻辑存在于策略引擎而非应用程序代码中,这意味着:
商家创建了一个具有以下特征的群组策略:
["vegan"]。操作: 对 dietary_restrictions: "vegan" 进行软提升,提升权重为 2。

每个策略文档都有一个 cohorts 字段。适用于所有购物者(无论群组如何)的通用策略可以留空此字段,控制平面将在内部为其分配 "_all" 值。特定群组的策略存储其目标群组名称,例如 ["vegan", "kosher", “sweet_tooth”]。
当搜索请求包含用户个人资料时,控制平面会为 percolator 查询构建一个简单的 terms 过滤器:
{
"terms": {
"cohorts": [
"_all",
"vegan",
"health_conscious"
]
}
}这个单一过滤器包含了所有通用策略以及用户的特定群组策略。_all 哨兵使其成为一个清晰的包含过滤器:无需 must_not 或 exists 查询来处理策略没有群组限制的情况。
percolator 随后像往常一样评估策略匹配。唯一的区别在于,候选策略集已经缩小到与该购物者群组相关的策略。所有下游操作(级联转换、字段级冲突解决、已消费短语跟踪)都与第 3 和第 4 部分中描述的非个性化流程相同。
当非素食用户搜索巧克力时,其结果不会应用素食群组提升。他们通常会在顶部结果中看到非素食巧克力,如下所示:

当属于素食群组的购物者搜索“chocolate”时,此策略会包含在 percolator 候选集中。它会匹配,并且控制平面会对素食认证巧克力应用软提升。这种提升是乘法性的:素食巧克力的排名会更高,但非素食巧克力不会被完全排除,因为上述过滤器被定义为软提升,我们已在本系列的第 3 部分详细描述了这一点。

然而,如果购物者明确搜索“Hershey milk chocolate”,素食提升仍然适用,但可能会被 Hershey milk chocolate 产品的更强文本相关性所超越。

不在素食群组的购物者搜索相同的查询时,永远不会看到“素食群组”策略;它不在他们的候选集中。治理层是相同的;只有活跃策略集不同。
一个拥有丰富购买历史的素食购物者,将同时获得素食群组特定策略激活和购买历史提升。对于新用户或匿名购物者,仅凭隐含的群组会员资格就能提供有意义的个性化,而无需任何行为数据(例如,匿名用户可能只搜索过素食产品,因此我们将其归类为素食群组的成员)。在创建账户时自我识别为遵循清真饮食的购物者,在首次搜索时就能立即收到针对清真定制的结果。

function_score 层的嵌套顺序至关重要。从最内层到最外层:
fulltext_match、title_phrase_match)的关键词或语义匹配。bool.filter 子句的硬过滤器,作为 function_score 函数的软提升(第 3 和第 4 部分)。function_score 层。这种排序确保了治理控制结果集(显示什么),商业信号调整该集合内的排名(从零售商角度看什么优先显示),而购买历史则根据个人行为进一步调整排名(从购物者角度看什么优先显示)。每一层都以乘法方式包裹前一层,因此效果是叠加而非冲突的。
通过受治理的控制平面实现的个性化,保留了第 1 和第 2 部分中描述的每个操作属性:
下一篇文章将探讨受治理控制平面的另一个维度:如何通过策略针对每个查询调整利润和受欢迎度提升,将经济优化转变为治理决策而非静态配置。
请参阅第 7 部分:查询治理的经济优化:按查询调整利润和受欢迎度提升。
本文中描述的个性化模式(个人购买历史提升和群组感知策略激活)由 Elastic Services Engineering 设计和构建,作为我们可重复的电子商务搜索加速器的一部分。这两种机制都与本系列中描述的受治理控制平面架构集成。请联系 Elastic Professional Services。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。