在新能源汽车推荐目录查询中,哪些指标最重要?,新能源汽车指标是怎么查的

AI 驱动的搜索:4 众包相关性

本章涵盖

  • 利用用户的集体见解来提高搜索平台的相关性
  • 收集和处理用户行为信号
  • 利用反射智能创建自调整模型,例如信号增强、协作推荐和个性化以及机器学习排名
  • 构建端到端信号增强模型
  • 从基于内容的信号进行众包学习

在第一章中,我们介绍了用户意图的维度“内容理解”、“用户理解”和“领域理解”。为了创建一个最佳的人工智能搜索平台,我们需要能够结合这些上下文来了解用户的查询意图。但问题是我们如何得出这些理解?

可能存在许多不同的信息源,我们可以从中学习文档、数据库、内部知识图、用户行为、领域专家等等。一些组织拥有手动标记文档主题或类别的团队,有些组织甚至使用 Amazon Mechanical Turk 等工具外包这些任务,这使他们能够从世界各地的人们那里众包答案。为了识别网站上的恶意行为或错误,公司通常允许用户报告问题,甚至建议纠正。所有这些都是众包的例子——依靠许多人的输入来学习新信息。

当涉及到搜索相关性时,众包可以发挥至关重要的作用,但通常重要的是不要因不断向客户寻求帮助而惹恼他们。幸运的是,通常可以根据用户的行为隐式地向他们学习,而不必通过明确要求输入来打扰他们。例如,如果您试图找到针对给定搜索返回的最佳文档,为什么不检查日志以确定其他用户在响应同一查询时最常点击哪些文档呢?

4.1 使用用户信号

每当客户采取行动时 - 无论是发出查询、点击结果、购买产品还是对搜索结果采取某些行动 - 这都会提供该用户意图的信号。我们可以记录每个信号,然后对其进行处理,以便了解有关每个用户、用户组以及整个用户群的见解。本节向您介绍利用用户信号的力量,介绍我们将在整本书中使用的示例电子商务数据集,并引导您完成收集、存储和处理用户信号的机制。

4.1.1 信号与内容

在构建搜索引擎时,我们有两种高级类型的数据 - “内容”和“信号”。我们处理的大部分内容都是以文档的形式存在的。文档可以代表网页、产品列表、计算机文件、图像、事实或我们可能想要搜索的任何其他类型的信息。内容文档通常包含带有某种文本的字段,通过这些文本我们可以搜索和查找关系,以及表示与内容相关的其他属性(作者、大小、颜色、日期等)的附加字段。这些内容文档的定义特征是它们包含人们正在搜索的信息(希望也包含他们正在搜索的答案)。然而,除了传统的文件之外,许多其他类型的内容可以合并到搜索体验中。外部构建的知识图、实体列表(人、地点、事物)、客户或员工创建的评论、标签或添加到文档中的属性等都是内容形式。

另一方面,“信号”反映了用户如何与内容互动。当有人发出查询时,他们会收到一组包含内容的文档。也许他们点击结果,将其添加到购物车,为文档添加书签,或采取其他类似的操作。我们将这些交互称为信号,它们的定义特征是它们提供外部见解,可用于了解用户希望如何与内容交互。当然,这些信号也可以稍后与预先存在的内容一起添加到文档中,如果您正在构建一个允许搜索信号的应用程序,那么这些信号实际上会成为该应用程序的新内容。尽管在某些情况下,根据用例,信号也可以被视为内容,

对于我们在构建人工智能驱动的搜索时承担的许多重要任务,我们可以通过使用内容或信号得出类似的结果,但它们为我们提供了两种不同的相关性视角。在理想情况下,我们实际上可以引入这两种观点来构建更智能的系统,但了解每种方法的优点和缺点以了解如何最好地利用它们是有用的。

举个例子,如果我们试图找到“driver”这个词的同义词,我们可以在所有文本内容中查找经常出现在同一文档中的单词。在这种情况下,我们可以按优先顺序(按它们在文档中出现的百分比)查找单词,例如“出租车”(40%)、“汽车”(35%)、“高尔夫”(15%)、“俱乐部”( 12%)、“打印机”(3%)、“Linux”(3%)和“Windows”(1%)。同样,我们可以查看收集到的所有搜索过的用户的信号driver并汇总他们搜索的最常见的其他关键字,并按优先顺序找到类似的单词,例如“螺丝刀”(50%)、“打印机”(30%)、“windows”(25%)、“mac”(15%) )、“高尔夫”(2%)、“俱乐部”(2%)。从信号与内容得出的列表可能相似,也可能看起来非常不同。基于内容的方法告诉我们文档中最具代表性的含义,而基于信号的方法告诉我们用户正在寻找的最具代表性的含义。

由于我们的最终目标是向用户展示他们正在寻找的内容,因此在大多数情况下,我们倾向于支持信号衍生的含义而不是内容衍生的含义。但是,如果我们实际上没有映射到信号衍生含义的良好内容怎么办?我们是否使用内容衍生的含义,或者我们是否尝试根据信号数据建议其他相关搜索?如果我们没有足够的信号或者信号数据不是很干净怎么办?我们能否以某种方式使用内容派生数据来清理信号派生数据?

我们在推荐方面遇到了类似的问题:基于内容的推荐利用文档中的属性,但不理解用户,而基于信号的推荐不理解内容属性,并且对于没有足够交互的项目根本不起作用。基于内容的推荐可能会推荐对用户来说不重要的功能,而基于信号的推荐可能会产生自我强化的循环,人们只与推荐的项目进行交互,然后只有那些项目被推荐,因为它们是唯一与之相关的项目。用户进行了互动。

理想情况下,我们希望创建一个平衡的系统,可以充分利用内容衍生智能和信号衍生智能的优势。虽然本章主要关注信号衍生的众包智能,但本书的主要目标是展示如何平衡和结合基于内容和基于信号的方法,以产生最佳的人工智能驱动的搜索体验。

4.1.2 设置我们的产品和信号数据集 (RetroTech)

在探索不同的用例时,我们在整本书中利用了各种数据集,但拥有一个一致的示例也很有价值,我们可以在不断进步的基础上进行构建。我们将在本节中设置该中心数据集,并将在接下来的许多章节中继续以它为基础。

网络搜索和电子商务是当今人工智能驱动的搜索最普遍认可的两个用例。我们认为,在两者中,电子商务为探索最广泛的人工智能驱动的搜索技术提供了最佳机会。电子商务示例也将更容易地映射到本书大部分读者所提供的现实世界用例。值得注意的是,本书中的大多数技术都适用于各种用例——网络搜索、企业搜索、站点搜索、桌面搜索、邮件搜索、电子发现、职位搜索、产品搜索、支持门户搜索——凡是你能想到的。何时使用任何给定技术的决定因素通常更多地与内容和信号的数量和种类相关,而不是与特定用例相关。

话虽如此,让我们介绍一下我们的示例用例和数据集:RetroTech!

RetroTech 用例

在本书的大部分内容中,我们将受益于拥有大量数据和用户交互的强大搜索用例。电子商务搜索为人工智能驱动的搜索技术的价值提供了最具体的用例之一,也是读者最容易理解的问题之一,因此我们创建了一个电子商务数据集来帮助我们探索这个领域:复古技术数据集。

由于销售最新、最好的电子、多媒体和科技产品的零售商之间竞争激烈,小型在线企业很难竞争。然而,一小部分新兴人群选择避开最新、最好的产品,而是退回到过去几十年熟悉的技术。RetroTech 公司的成立是为了满足这一独特消费者群体的需求,提供当今货架上很难找到的老式硬件、软件和多媒体产品。

让我们加载数据集,以便我们可以开始了解文档和用户信号之间的关系,以及众包智能如何提高我们的搜索相关性。

加载产品目录

RetroTech 网站有大约 50,000 种可供销售的产品,因此我们需要将这些产品加载到我们的搜索引擎中才能开始,以便我们可以搜索它们。如果您构建了人工智能驱动的搜索代码库来运行第 3 章的示例,那么您的搜索引擎已经启动并运行。如果您还没有这样做,可以在附录 A 中找到构建和运行本书所有示例的说明,您现在可以运行它来进行设置。

当你的搜索引擎启动并运行后,我们接下来要做的就是下载本书附带的 Retrotech 数据集。该数据集包括两个 CSV 文件,一个包含 Retrotech 的所有产品,另一个包含来自 Retrotech 用户的一年信号数据。清单 4.1显示了产品目录数据集的几行,以帮助您熟悉该格式。

清单 4.1。探索 RetroTech 产品目录

"upc","name","manufacturer","shortDescription","longDescription""096009010836","Fists of Bruce Lee - Dolby - DVD",\N,\N,\N"043396061965","The Professional - Widescreen Uncut - DVD",\N,\N,\N"085391862024","Pokemon the Movie: 2000 - DVD",\N,\N,\N"067003016025","Summerbreeze - CD","Nettwerk",\N,\N"731454813822","Back for the First Time  - CD","Def Jam South",\N,\N"024543008200","Big Momma's House - Widescreen - DVD",\N,\N,\N"031398751823","Kids - DVD",\N,\N,\N"037628413929","20 Grandes Exitos - CD","Sony Discos Inc.",\N,\N"060768972223","Power Of Trinity (Box) - CD","Sanctuary Records",\N,\N

您可以看到产品由 UPC(通用产品代码)编号标识,然后有名称、制造商以及简短描述(在搜索结果中用作预告)和详细描述(产品上使用的完整描述)详情页)。

由于我们的目标是搜索产品,因此下一步是将它们发送到搜索引擎进行索引。为了能够在我们的 RetroTech 产品目录上进行搜索,让我们运行清单 4.2中的文档索引代码,将产品文档发送到搜索引擎。

清单 4.2。发送产品文档到搜索引擎

#Create Products Collectionproducts_collection="products"create_collection(products_collection)#Modify Schema to make some fields explicitly searchable by keywordupsert_text_field(products_collection, "upc")upsert_text_field(products_collection, "name")upsert_text_field(products_collection, "longDescription")upsert_text_field(products_collection, "manufacturer")print("Loading Products...")csvFile = "../data/retrotech/products.csv"product_update_opts={"zkhost": "aips-zk", "collection": products_collection,"gen_uniq_key": "true", "commit_within": "5000"}csvDF = spark.read.format("com.databricks.spark.csv").option("header", "true").option("inferSchema", "true").load(csvFile)csvDF.write.format("solr").options(**product_update_opts).mode("overwrite").save()print("Products Schema: ")csvDF.printSchema()print("Status: Success")

结果:

Wiping 'products' collectionCreating 'products' collectionStatus: SuccessAdding 'upc' field to collectionStatus: SuccessAdding 'name' field to collectionStatus: SuccessAdding 'longDescription' field to collectionStatus: SuccessAdding 'manufacturer' field to collectionStatus: SuccessLoading Products...Products Schema:root |-- upc: long (nullable = true) |-- name: string (nullable = true) |-- manufacturer: string (nullable = true) |-- shortDescription: string (nullable = true) |-- longDescription: string (nullable = true)Status: Success

最后,为了验证文档现在是否已编入索引且可搜索,让我们运行一个示例关键字搜索。清单 4.3显示了搜索 的示例ipod,这是一个真正的经典设备!

清单 4.3。在产品目录上运行搜索

query = "ipod"collection = "products"request = {    "query": query,    "fields": <"upc", "name", "manufacturer", "score">,    "limit": 5,    "params": {      "qf": "name manufacturer longDescription",      "defType": "edismax",      "sort": "score desc, upc asc"    }}search_results = requests.post(solr_url + collection + "/select",json=request).json()<"response"><"docs">display(HTML(render_search_results(query, search_results)))

ipod清单 4.3的搜索结果如图 4.1 所示,表明我们的产品现已编入索引并可搜索。然而不幸的是,结果的相关性相当差。


图 4.1。产品搜索结果。我们可以看到产品目录已被索引,并且现在的查询ipod返回搜索结果

虽然搜索结果排名的质量不是很好,但我们至少现在拥有一个开箱即用的“关键字匹配”搜索引擎,我们可以开始改进。我们将以此为基础,并在本书的其余部分开始引入更多智能的人工智能搜索功能。我们的下一步将是介绍我们的信号数据。

加载信号数据

由于 RetroTech 在您的计算机上运行,​因此您不会有真正的用户访问、运行搜索、点击和购买以及以其他方式生成信号。因此,我们生成了一个数据集供您使用,该数据集近似于您在类似的现实数据集中所期望的信号活动类型。

为简单起见,我们将信号存储在搜索引擎中,以便能够在实时搜索场景和外部处理中利用它们。运行清单 4.4将模拟并索引一些示例信号,我们可以在本章的其余部分中利用这些信号。

清单 4.4。为用户信号数据集建立索引

#Create Signals Collectionsignals_collection="signals"create_collection(signals_collection)print("Loading Signals...")csvFile = "../data/retrotech/signals.csv"signals_update_opts={"zkhost": "aips-zk", "collection": signals_collection,"gen_uniq_key": "true", "commit_within": "5000"}csvDF = spark.read.format("com.databricks.spark.csv").option("header", "true").option("inferSchema", "true").load(csvFile)csvDF.write.format("solr").options(**signals_update_opts).mode("overwrite").save()print("Signals Schema: ")csvDF.printSchema()print("Status: Success")

结果:

Wiping 'signals' collectionCreating 'signals' collectionStatus: SuccessLoading Signals...Signals Schema:root |-- query_id: string (nullable = true) |-- user: string (nullable = true) |-- type: string (nullable = true) |-- target: string (nullable = true) |-- signal_time: timestamp (nullable = true)Status: Success

随着我们的 Retrotech 产品和信号数据全部加载,我们很快将开始探索使用信号数据来增强搜索相关性的方法。不过,在深入研究这些众包相关技术之前,让我们首先稍微探索一下信号数据,以便了解信号在现实系统中是如何构建、使用和收集的。

4.1.3 探索信号数据

不同类型的信号具有不同的属性,需要记录。例如,对于“查询”信号,我们要记录用户的关键字。对于“点击”信号,我们想要记录点击了哪个文档,以及哪个查询导致了点击。为了以后的分析,我们还想记录哪些文档在查询后被返回并可能被用户查看。

为了使事情更具可扩展性并避免为每种新信号类型编写自定义代码,我们在本书中采用了通用格式来表示信号。这可能与您记录信号的方式不同,但只要您随后可以将信号映射为这种格式,那么本书中的所有代码都应该可以工作,而不需要特定于用例的修改。

我们在本书中使用的信号格式如下:

  • query_id:发起此信号的查询信号的唯一 ID。
  • user:代表搜索引擎特定用户的标识符
  • type:什么样的信号(查询、点击、购买等)
  • target:此处信号适用的内容signal_time。
  • signal_time:信号发生的日期和时间

例如,假设用户执行了以下一系列操作:

  1. 发出查询ipad并返回三个文档(doc1、doc2和doc3)。
  2. 点击doc1。
  3. 返回并点击doc3。
  4. 添加doc3到购物车。
  5. 回去查找,ipad cover返回了两份文件(doc4,doc5)。
  6. 点击doc4。
  7. 添加doc4到购物车。
  8. doc3购买了购物车 ( , )中的商品doc4。

这些相互作用将产生以下信号:

表 4.1。信号格式示例

query_id

user

type

target

signal_time

1

u123

query

ipad

2020-05-01-09:00:00

1

u123

results

doc1,doc2,doc3

2020-05-01-09:00:00

1

u123

click

doc1

2020-05-01-09:00:10

1

u123

click

doc3

2020-05-01-09:00:29

1

u123

add-to-cart

doc1

2020-05-01-09:03:40

2

u123

query

ipad cover

2020-05-01-09:04:00

2

u123

results

doc4,doc5

2020-05-01-09:04:00

2

u123

click

doc4

2020-05-01-09:04:40

2

u123

add-to-cart

doc4

2020-05-01-09:05:50

1

u123

purchase

doc3

2020-05-01-09:07:15

2

u123

purchase

doc4

2020-05-01-09:07:15

关于信号格式需要注意的一些事项:

  1. 类型query和results类型信号被分解为单独的信号。这是不必要的,因为它们同时发生,但这使我们能够保持表结构一致,而不必添加results仅适用于query信号的额外列。此外,如果用户点击“下一页”链接或向下滚动页面并看到其他结果,此结构将允许我们在新时间为返回的结果附加新信号,而无需返回并修改原始结果信号。
  2. 每个信号都与启动一系列内容交互的query_id原始信号相关联。query这不仅仅是对用户输入的关键字的引用,而是对标识用户查询的时间戳实例的query_id特定信号的引用。query由于相同查询关键字的结果可能会随着时间的推移而变化,这使我们能够对用户对查询所显示的特定结果集的反应进行更复杂的处理。
  3. 大多数信号类型都包含 中的一项target,但该results类型包含文档的有序列表。原因是保持搜索结果的准确顺序很重要,因此在这种情况下“目标”实际上是文档的有序列表,而不是独立的文档。结果的顺序对于我们在本书后面介绍的一些衡量相关性的算法很重要。
  4. 结账时,purchase每件商品都会有一个单独的信号,而不是只有一个checkout信号。这是因为我们需要跟踪购买的两个商品是否源自不同的查询。当然,checkout如果您想跟踪交易,您也可以添加信号类型,并可能将两次购买列为target,但这对于我们在本书中的需求来说是多余的,因此我们将避免这种增加的复杂性。

有了这些原始信号作为我们的构建块,我们现在可以开始考虑如何将这些信号链接在一起,以开始了解我们的用户及其兴趣。在下一节中,我们将讨论在搜索平台中对用户、会话和请求进行建模的方法。

4.1.4 对用户、会话和请求建模

在上一节中,我们将用户信号的结构视为与原始查询相关的独立交互列表。我们假设“用户”具有唯一的 ID,但是如何识别和跟踪唯一的用户呢?此外,一旦您确定了如何跟踪唯一用户,将他们的交互分解为会话以了解他们的上下文何时可能发生变化的最佳方法是什么?

网络搜索中用户的概念可能非常灵活。如果您的搜索引擎有经过身份验证(登录)的用户,那么您已经拥有某种内部用户 ID 来跟踪他们。但是,如果您的搜索引擎支持未经身份验证的访问或者是公开可用的,那么您将有许多正在运行的搜索,而没有正式的用户 ID。然而,这并不意味着您无法追踪它们;它只是需要对“用户”的含义进行更流畅的解释。我们想要跟踪用户的原因是这样我们可以将不同的信号联系在一起以学习交互模式,并且如果没有一些表示同一用户发出多个请求的共享标识符,则将这些交互联系在一起并不容易。

如果我们将已知信息视为从用户的“最佳”表示到“最差”的层次结构,它将如下所示:

  • 用户 ID:跨设备持续存在的唯一用户 ID(经过身份验证)
  • 设备 ID:同一设备上跨会话持续存在的唯一 ID(例如设备 ID 或 IP 地址 + 设备指纹)
  • 浏览器 ID:仅在同一应用程序/浏览器中的会话之间持续存在的唯一 ID(持久 cookie ID)
  • 会话 ID:在单个会话中持续存在的唯一 ID(例如浏览器隐身模式下的 cookie)
  • 请求 ID:仅在单个请求中持续存在的唯一 ID(关闭 cookie 的浏览器)

在大多数现代搜索应用程序中,当然还有大多数电子商务应用程序中,我们通常必须处理所有这些问题。根据经验,您希望将用户与最持久的标识符联系起来 - 列表中尽可能靠前的标识符。请求 ID 和会话 ID 之间的链接,以及会话 ID 和浏览器 ID 之间的链接都是通过用户的 cookie,因此最终浏览器 ID(存储在 cookie 中的持久唯一 ID)是其中每一个的共同点。

具体来说,

  • 如果用户启用了持久cookie,则一个浏览器ID可以有多个会话ID,会话ID可以有多个请求ID。
  • 如果用户在每次会话后清除cookie(例如使用隐身模式),则每个浏览器ID只有一个会话ID,而会话ID可以有多个请求ID。
  • 如果用户关闭 cookie,则每个请求 ID 都会有一个新的会话 ID 和一个新的浏览器 ID。

在构建搜索平台时,大多数组织没有正确规划和设计其信号跟踪机制。由于无法将访问者的查询与​​特定的结果操作(查看结果的顺序、单击的结果以及与单击的项目的任何后续交互)关联起来,许多组织很难通过增强的分析来最大化其搜索平台的相关性并通过自动搜索相关性方法。在某些情况下,可以在事后导出丢失的信号跟踪信息(例如使用时间戳将信号建模到可能的会话中),但通常最好设计系统以更好地预先处理用户跟踪,以防止潜在的信息丢失。更丰富的信号将使您能够以最佳方式关联用户交互,从而为您的人工智能搜索工作增加最大价值。在 4.2 节中,我们将介绍如何通过称为“反射情报”的过程实际使用这些丰富的信号来提高相关性

4.2 反思智能简介

在上一节中,我们介绍了如何在用户与搜索引擎交互时捕获用户的信号。虽然信号本身有助于帮助我们了解搜索引擎的使用方式,但它们也可以作为构建模型的主要输入,这些模型可以不断地从用户交互中学习,并使您的搜索引擎能够自我调整其相关性模型。在本节中,我们将通过反射智能的概念介绍这些自调整模型如何工作。

4.2.1 什么是反映智力?

想象一下,您是一家五金店的员工,有人问您在哪里可以找到锤子,您告诉他们“第二过道”。几分钟后,您看到同一个人没有锤子从二号过道走到五号过道,然后拿着锤子走出五号过道。第二天,其他人要锤子,你也告诉他们“第二通道”,然后你观察到几乎相同的行为模式。如果您没有发现这种模式并调整您的建议以便为您的客户提供更好的体验,那么您将成为一名非常糟糕的员工。现在想象一下,如果您继续对每一位进门寻找锤子的新客户提供数百甚至数千次相同的、糟糕的答案。

不幸的是,这正是大多数搜索引擎的工作方式 - 它们为每个查询返回一组相当静态的文档,无论每个用户是谁或先前的用户对显示的文档列表有何反应。值得庆幸的是,我们可以通过将机器学习技术应用于从用户交互中收集的信号来大幅改进这一点。这使我们能够从用户的信号中了解他们的意图,然后将这些知识反映回来以改进未来的搜索结果。这个过程称为“反思智能”

反射智能就是创建反馈循环,根据不断变化的用户交互不断学习和改进。图 4.2 展示了实施反射智能流程的高级概述。


图 4.2。反映情报过程。用户发出查询、查看结果并执行一组操作。然后处理这些动作(信号)以创建改进未来

让我们看一下图 4.2 所示的反射智能流程。名为 Alonzo 的用户运行搜索,ipad在搜索框中输入术语。记录查询信号,其中包含显示给 Alonzo 的所有搜索结果的列表。然后,阿朗佐会看到搜索结果列表,并采取一些操作。在图中,Alonzo 单击一个文档 ( doc22),然后购买该文档代表的产品,从而产生两个额外的相应信号。然后,Alonzo 的所有信号以及来自其他用户的信号都可以通过各种机器学习算法进行聚合和处理,以创建学习的相关性模型。

这些学习的相关性模型可以提升特定查询的最受欢迎的结果,为每个特定用户及其兴趣个性化结果,甚至了解正在搜索的文档的哪些一般属性往往最重要,并调整排名算法以考虑这些属性。这些模型还可以学习如何更好地解释用户查询,例如识别常见的拼写错误、短语、同义词或其他语言模式和特定领域的术语。

一旦生成了这些学习到的相关性模型,就可以将它们部署回生产搜索引擎中,并立即应用于增强未来查询的结果。然后,该过程再次开始,下一个用户运行搜索,查看(现在希望得到改进)搜索结果,并与这些结果进行交互。这个过程创建了一个自学习系统,该系统会随着每次额外的用户交互而改进,随着时间的推移变得越来越智能和更相关,并且还会随着用户兴趣和内容的发展而自动调整。

在接下来的部分中,我们将探讨几类反映智能模型,包括信号增强(大众化相关性)、协作过滤(个性化相关性)和学习排名(广义相关性)。我们将从最简单也是最有影响力的模型之一开始:信号增强模型。

4.2.2 通过信号提升普及相关性

从相关性的角度来看,发送到搜索引擎的最流行的查询往往也是最重要的优化查询。值得庆幸的是,由于更流行的查询会产生更多信号,这意味着它们通常更容易众包反映智能模型以提高相关性。

信号增强是反射智能最简单的形式之一,也是提高最流行、流量最高的查询相关性最有效的形式之一。

信号增强模型在最常见和最高量的查询上运行良好,使它们成为学习“流行相关性”模型的理想方式。

清单 4.5ipad演示了在我们的 RetroTech 搜索引擎中对查询的开箱即用的搜索。

清单 4.5。将查询的关键字搜索发送ipad到搜索引擎。

query = "ipad"collection = "products"request = {    "query": query,    "fields": <"upc", "name", "manufacturer", "score">,    "limit": 5,    "params": {      "qf": "name manufacturer longDescription",      "defType": "edismax"    }}search_results = requests.post(solr_url + collection + "/select",json=request).json()<"response"><"docs">display(HTML(render_search_results(query, search_results)))

正如预期的那样,此查询的结果将返回许多包含该关键字的文档ipad,并且根据我们在第 3 章中学到的有关如何利用 TF-IDF 和 BM25 排名算法对关键字相关性进行评分的知识,包含术语 the 的ipad文档大多数时候通常会排名最高。图 4.3 显示了清单 4.5中的查询结果。


图 4.3。查询的关键字搜索结果ipad


虽然这些结果在其内容中多次包含“ipad”一词,但大多数用户会对这些结果感到失望,因为它们是次要配件,而不是搜索重点的主要产品类型。正如您可能猜到的那样,仅从产品文档中的文本很难找出主要产品与次要配件。然而,对于非常流行的查询,许多客户可能会一遍又一遍地运行相同的查询,并在令人沮丧的搜索结果中奋力拼搏,最终找到他们正在寻找的真正产品。信号增强是一种利用流行查询中的聚合用户行为来自动学习并返回最佳产品的技术。

图 4.4 演示了信号增强如何作为连续反馈循环工作。


图 4.4。信号增强反馈环路。记录用户的搜索,并应用当前信号增强模型来返回增强结果


一旦您的产品被索引并且您开始收集用户查询和文档交互的信号,实现信号增强所需的唯一额外步骤就是聚合您的信号,然后将聚合信号添加为您的查询或文档交互的增强你的文件。清单 4.6演示了一个将信号聚合到 sidecar 集合中的简单模型。

边车系列

Sidecar 集合是与主集合一起位于搜索引擎中的附加集合,其中包含其他有用的数据以改进您的搜索应用程序。在我们的电子商务示例中,我们的主要集合是集合products,并且我们已经介绍了我们的signals集合,可以将其视为边车集合。在本节中,我们还将介绍一个signals_boostingsidecar 集合,我们将在查询时利用它来增强我们的查询。在整本书中,我们将介绍其他几个 sidecar 集合来存储自学习模型的输入和输出。

清单 4.6。通过聚合信号生成信号增强模型。

products_collection="products"signals_collection="signals"signals_boosting_collection="signals_boosting"create_collection(signals_boosting_collection)signals_opts={"zkhost": "aips-zk", "collection": signals_collection}signals_boosting_opts={"zkhost": "aips-zk", "collection":signals_boosting_collection, "gen_uniq_key": "true","commit_within": "5000"}df = spark.read.format("solr").options(**signals_opts).load()df.registerTempTable("signals")print("Aggregating Signals to Create Signals Boosts...")signals_aggregation_query = """select q.target as query, c.target as doc, count(c.target) as boost  from signals c left join signals q on c.query_id = q.query_id  where c.type = 'click' AND q.type = 'query'  group by query, doc  order by boost desc"""spark.sql(signals_aggregation_query).write.format("solr").options(**signals_boosting_opts).mode("overwrite").save()print("Signals Aggregation Completed!")

结果:

Wiping 'signals_aggregation' collectionCreating 'signals_aggregation' collectionStatus: SuccessAggregating Signals to Create Signals Boosts...Signals Aggregation Completed!

清单 4.6中最重要的部分是signals_aggregation_query,我们实际上只是将其定义为 SQL 查询,以使示例更具可读性。对于每个查询,我们都会获取用户在该查询的搜索结果中单击的文档列表,以及该文档被单击的次数。通过按每个查询的点击次数对文档进行排序,我们现在有了一个用户倾向于为每个查询进行交互的文档的有序列表。

这里的直觉是,用户倾向于选择他们认为最相关的产品,因此,如果我们要增强这些文档,那么我们预计我们的热门搜索结果会变得更加相关。我们将在清单 4.7中通过使用这些聚合计数作为下一个查询的信号增强来测试这个理论。让我们回顾一下之前的 查询ipad。

清单 4.7。生成信号增强查询以提高热门查询和文档的搜索相关性排名。

query = "ipad"signals_boosts_query = {    "query": query,    "fields": <"doc", "boost">,    "limit": 10,    "params": {      "defType": "edismax",      "qf": "query",      "sort": "boost desc"    }}signals_boosts = requests.post(solr_url + signals_boosting_collection +"/select", json=signals_boosts_query).json()<"response"><"docs">print("Boost Documents: \n")print(signals_boosts)product_boosts = ""for entry in signals_boosts:    if len(product_boosts) > 0:  product_boosts += " "    product_boosts += '"' + entry<'doc'> + '"^' + str(entry<'boost'>)print("\nBoost Query: \n" + product_boosts)collection = "products"request = {    "query": query,    "fields": <"upc", "name", "manufacturer", "score">,    "limit": 5,    "params": {      "qf": "name manufacturer longDescription",      "defType": "edismax",      "indent": "true",      "sort": "score desc, upc asc",      "qf": "name manufacturer longDescription",      "boost": "sum(1,query({! df=upc v=$signals_boosting}))",      "signals_boosting": product_boosts    }}search_results = requests.post(solr_url + collection + "/select", json=request).json()<"response"><"docs">display(HTML(render_search_results(query, search_results)))

Boost Documents:

<{'doc': '885909457588', 'boost': 966}, {'doc': '885909457595','boost': 205}, {'doc': '885909471812', 'boost': 202},{'doc': '886111287055', 'boost': 109}, {'doc': '843404073153','boost': 73}, {'doc': '635753493559', 'boost': 62}, {'doc':'885909457601', 'boost': 62}, {'doc': '885909472376', 'boost': 61},{'doc': '610839379408', 'boost': 29}, {'doc': '884962753071','boost': 28}>

Boost Query:

"885909457588"^966 "885909457595"^205 "885909471812"^202 "886111287055"^109"843404073153"^73 "635753493559"^62 "885909457601"^62 "885909472376"^61"610839379408"^29 "884962753071"^28

清单 4.7中的查询做了两件值得注意的事情:

  1. 它查询signals_boostingsidecar 集合以查找接收到查询的最高信号增强的有序(按增强)文档列表,并将这些信号增强转换为对搜索引擎的查询
  2. 然后,它使用以下相关性增强参数将该增强查询传递给搜索引擎:
  3. "boost": "sum(1,query({! df=upc v=$signals_boosting}))"
  4. "signals_boosting": product_boosts其中是清单 4.7product_boosts生成的“Boost Query”输出。

执行查询后,我们可以查看它如何改进我们的搜索结果。如果您还记得图 4.3,我们最初的关键字搜索ipad返回的大部分是 iPad 配件,而不是实际的 iPad 设备。图 4.5 演示了基于在关键字查询之上应用信号增强的新结果。


图 4.5。启用信号增强的搜索结果。我们现在看到的是实际的 iPad

应用信号增强后的新结果明显优于仅关键字结果。我们现在看到了实际的 iPad,这是用户输入并且几乎肯定想要找到的产品。您可以期望从搜索引擎中的大多数其他流行查询中看到类似的良好结果,因为与它们交互的人越多,这种众包方法用于确定相关性的可靠性就越高。当然,当我们在热门产品列表中进一步向下移动时,信号增强带来的相关性改进将开始下降,并且在信号不足的情况下,我们甚至可能在许多情况下降低相关性。值得庆幸的是,我们将引入许多其他技术,可以在没有足够信号量的情况下更好地处理查询。

本节的目标是引导您完成实施端到端反射智能模型的初始具体示例。尽管结果不言自明,但本实施中使用的信号聚合非常简单。在实现信号增强模型时,需要考虑许多注意事项和细微差别 - 是在查询时还是在文档上增强,如何增加新信号相对于旧信号的权重,如何避免恶意用户尝试在搜索中增强特定产品通过生成虚假信号供系统解释、如何引入和混合来自不同来源的信号等来了解结果。我们将在第 8 章“信号增强模型”中详细介绍每个主题。

不过,现在让我们从信号增强继续讨论一些其他类型的反射智能模型。

4.2.3 通过协同过滤实现个性化相关性

在第 4.2.2 节中,我们介绍了信号增强,我们将其称为“流行相关性”,因为它确定了所有用户中常见查询的最流行答案。在本节中,我们将介绍一种称为协作过滤的反射智能方法,将其更好地描述为“个性化相关性”。大众相关性决定了哪些结果通常在许多用户中最受欢迎,而个性化相关性则侧重于确定哪些项目最有可能与特定用户相关。

协同过滤是使用对某些用户的偏好的观察来预测其他用户的偏好的过程。毫无疑问,您之前已经多次看到协同过滤的实际应用。它是推荐引擎使用的最流行的算法类型,也是许多网站上出现的常见“喜欢该项目的用户也喜欢这些项目”推荐列表的来源。图 4.6 展示了协同过滤如何遵循我们在信号增强模型中看到的相同的反射智能反馈循环。


图 4.6。针对用户到项目推荐的协作过滤


与信号增强一样,协同过滤是利用连续反馈循环构建的,其中收集信号,根据这些信号构建模型,然后使用这些模型生成相关匹配,然后将这些交互的结果再次记录为附加信号。正如其他反射智能模型一样,用户和项目之间的交互被记录为信号,如图 4.6 所示。协作过滤方法通常会生成一个用户-项目交互矩阵,将每个用户映射到每个项目(文档),每个用户和项目之间的关系强度基于积极交互的强度(点击、购买、评分等)在)。

如果交互矩阵足够填充,则可以通过直接查找与同一项目交互的其他用户,然后增强这些用户与之交互的其他项目(类似于信号增强),从中推断出对任何特定用户或项目的推荐。还互动了。然而,如果用户-项目交互矩阵过于稀疏,那么通常会应用矩阵分解方法。

矩阵分解是将用户-项目交互矩阵分解为两个矩阵的过程:一个将用户映射到潜在“因素”,另一个将这些潜在因素映射到项目。这类似于我们在第 3 章中提到的降维方法,在该方法中,我们将与食品相关的短语从精确关键字(包含倒排索引中每个单词的元素的向量)映射到更少的维度,描述食物并允许我们匹配含义,而不必映射到每个特定项目(关键字)。这种降维使得可以基于非常稀疏的数据得出用户对项目的偏好以及项目之间的相似性。

在协同过滤的矩阵分解的背景下,潜在因素代表我们文档的属性,这些属性被认为是用户之间共享兴趣的重要指标。通过根据这些因素匹配其他文档,我们使用众包来查找与相同共同兴趣相匹配的其他类似文档。

您可以通过其他方式生成推荐,我们将在本书后面探讨这些方式,例如通过基于内容的推荐。然而,协作过滤的独特之处在于,它可以了解用户对其他文档的偏好和品味,而无需了解有关文档内容的任何信息 - 所有决策完全是通过观察用户与内容的交互并确定内容的强度来做出的。基于这些观察的相似性。当我们在第 9 章讨论实现个性化搜索时,我们将更深入地探讨协作过滤,包括代码示例。

协同过滤可以完全基于众包相关性来学习用户兴趣和品味,但不幸的是,它存在一个被称为冷启动问题的重大缺陷。

冷启动问题描述了一种场景,其中返回结果取决于信号的存在,但从未生成信号的新文档不会显示。这造成了第 22 条军规的情况,即新内容不太可能向用户显示(生成信号的先决条件),因为它尚未生成任何信号(显示内容所需的信号)。在某种程度上,信号增强模型展示了类似的问题,已经流行的文档往往会获得更高的增强,从而导致它们获得更多的信号,而从未见过的文档则不会获得信号增强。这个过程会产生一个自我强化的循环,可能导致搜索结果缺乏多样性。

不仅仅具有取决于用户与特定项目的交互的流行相关性或个性化相关性,通常还需要利用可以应用于所有搜索和文档而不仅仅是最流行的搜索和文档的更通用的相关性模型。这对于解决冷启动问题大有帮助。在第 4.2.4 节中,我们探讨了如何通过称为学习排名的技术来推广众包相关性。

4.2.4 通过学习排序获得广义相关性

由于信号增强(大众化相关性,第 4.2.2 节)和协同过滤(个性化相关性,第 4.2.3 节)仅适用于已经具有信号的文档。这意味着大部分查询和文档在开始接收流量并生成信号之前不会从这些方法中受益。这就是学习排名作为一种广义相关性形式的价值所在。

学习排名,也称为机器学习排名,是构建和使用排名分类器的过程,该分类器可以对任何文档(甚至是以前从未见过的文档)与任意查询的匹配程度进行评分。您可以将排名分类器视为经过训练的相关性模型。学习排名过程无需手动调整搜索增强和其他参数,而是训练机器学习模型,该模型可以学习文档的重要特征,然后对搜索结果进行适当的评分。图 4.7 显示了推出学习排序的一般流程


图 4.7。学习排名(广义相关性)。排名分类器是根据用户对每个查询(训练集)的已知文档相关性的判断而构建


在学习排名系统中,应用了我们在信号增强和协同过滤中看到的相同的高级反射智能过程(参见图 4.2)。不同之处在于,学习排名可以使用相关性判断列表(查询到理想排名文档集的映射)来自动训练可普遍应用于所有查询的相关性模型。您将看到“构建排名分类器”步骤的输出是相关特征的模型(title_match_any_terms, is_known_caegory, popularity,content_age),并且该模型会定期部署到生产搜索引擎中以增强搜索结果。一个非常简单的机器学习排名模型中的特征可能像这样可读,但并不要求排名分类器实际上像这样可解释和可解释,而许多高级的、基于深度学习的排名分类器则不然。

此外,请注意图 4.7 中实时用户流程从搜索单词开始依次进行ipad到一组初始搜索结果,到运行已部署的学习对分类器进行排名,到返回一组重新排序的搜索结果的最终结果。这组最终结果根据排名分类器中学习到的排名函数重新排名。由于排名分类器通常比传统的关键词排名相关性模型更加智能并且利用更复杂的排名参数,因此使用排名分类器对搜索引擎中的所有匹配文档进行评分通常太慢。相反,学习排名通常仍会使用初始的、更快的排名函数(例如 BM25)来查找前 N 个文档(通常是数百或数千个文档),然后仅通过排名分类器运行该文档子集以获得顶部结果的更好的相关性排序。

学习排名可以利用显式相关性判断(由专家手动创建)或隐式判断(源自用户信号),或两者的某种组合。我们将在第 10 章和第 11 章中深入探讨从显式和隐式判断列表中实施学习排序的示例。

在第 4.2.5 节中,我们讨论了一些有用的基于信号的反射智能模型的其他示例。

4.2.5 其他反映智能模型

除了深入研究信号增强(第 8 章)、协作过滤(第 9 章)和学习排序(第 10 章)之外,我们还在本书中探索了许多其他类型的反射智能。在第 6 章中,我们探索挖掘用户查询以自动学习特定领域的短语、常见拼写错误、同义词和相关术语,在第 11 章中,我们探索从用户的交互中学习相关性判断的自动化方法,以便我们可以自动生成训练数据有趣的机器学习方法。

一般来说,用户和某些内容之间的每次交互都会创建一个连接(图中的一条边),我们可以用它来理解新兴关系并获得更深入的见解。图 4.8 展示了我们可以通过探索这个交互图来了解的一些各种关系。


图 4.8。许多反思智能模型

图 4.8 显示了如何通过各种信号聚合和机器学习方法对相同的输入信号数据进行不同的处理,以学习用户和项目之间的相似性、学习基于特定属性的偏好、生成用户兴趣的概况、学习项目之间的相似性,并生成对项目推荐的查询。我们将在接下来的章节中继续探讨这些技术,但请记住,信号数据包含潜在见解的宝库,这些见解通常提供与从中导出交互的文档一样多的好处。反射智能是向用户学习并镜像所学内容的概念,因此它不仅仅局限于信号增强、协作过滤、以及我们描述的学习排名技术。在第 4.2.6 节中,我们甚至讨论了从内容而不是信号中获取反射智能的几种方法。

4.2.6 内容众包

虽然我们通常认为众包是要求人们提供输入,但到目前为止,我们在本章中已经看到,隐式反馈通常可以在许多用户信号中提供同样多甚至更多的价值。虽然本章完全专注于利用用户信号来进行众包,但也必须指出,通常可以使用内容本身来为人工智能驱动的搜索平台众包智能。

例如,如果您想了解文档的总体质量,您可以查看客户评论以获得产品评级或查看该产品是否被报告为滥用或垃圾邮件。如果客户留下了评论,您可以对文本运行情感分析算法,这是一种可以确定评论是正面、中立还是负面的算法。根据检测到的情绪,您可以相应地提高或惩罚源文档。

我们提到,在第 6 章中,我们将介绍如何挖掘用户信号以自动学习特定领域的术语(短语、拼写错误、同义词等)。正如我们可以通过用户查询和交互来学习这个术语一样,我们也应该意识到我们的文档本身通常是由人们编写的,因此术语之间非常相似的关系也反映在书面内容中。我们将在下一章进一步探讨这些基于内容的关系。

现有最著名的搜索算法之一是 Page Rank 算法,这一突破性算法使 Google 成为最相关的搜索引擎并保持多年。页面排名本质上超越了任何给定文档中的文本,并查看所有其他网页创建者的行为,以了解他们如何链接到自己文档中的其他文档。通过测量传入和传出链接,可以根据人们更有可能链接到更高质量、更权威的来源的假设来创建网站“质量”的衡量标准,并且这些更高质量的来源不太可能链接到较低质量的来源。这种超越单个文档中存在的内容并将其与外部内容相关的想法 - 无论是直接的用户交互(信号)、论坛上发布的评论和反馈、网站之间的链接,甚至只是术语的使用以不同的、微妙的方式跨越其他文档是非常强大的。利用有关内容和用户的所有可用信息的艺术和科学是构建高度相关的人工智能搜索引擎的关键。在第 5 章中,我们研究了知识图的概念,以及如何利用文档之间链接中嵌入的一些关系来自动从我们的内容中学习领域理解。或者甚至只是在其他文档中以不同的、细致入微的方式使用术语,都是非常强大的。利用有关内容和用户的所有可用信息的艺术和科学是构建高度相关的人工智能搜索引擎的关键。在第 5 章中,我们研究了知识图的概念,以及如何利用文档之间链接中嵌入的一些关系来自动从我们的内容中学习领域理解。或者甚至只是在其他文档中以不同的、细致入微的方式使用术语,都是非常强大的。利用有关内容和用户的所有可用信息的艺术和科学是构建高度相关的人工智能搜索引擎的关键。在第 5 章中,我们研究了知识图的概念,以及如何利用文档之间链接中嵌入的一些关系来自动从我们的内容中学习领域理解。

4.3 总结

  • 内容和信号是人工智能驱动的搜索引擎的两个“燃料”来源,其中信号是众包相关性的主要来源。
  • 反射智能是创建持续学习反馈循环的过程,该循环可以从每次用户交互中进行改进,并将学到的智能反映回来,以自动增加未来结果的相关性。
  • 信号增强是“流行”相关性的一种形式,通常对最大量、最流行的查询产生最大影响。
  • 协同过滤是“个性化”相关性的一种形式,它能够使用用户与项目交互的模式来了解用户的偏好或项目之间关系的强度,然后根据这些学习到的关系推荐相似的项目。
  • 学习排名是“广义”相关性的一种形式,是基于相关性判断列表(映射到正确排名的文档列表的查询)训练排名分类器的过程,可用于对所有文档进行排名并避免冷启动问题。
  • 存在其他类型的反射智能,包括一些利用内容(而不仅仅是信号)来实现众包相关性的技术。

2023-11-23

2023-11-23