作者:JOSH DEVINS
在这篇文章中,我们将介绍多语言向量搜索。 我们将使用 Microsoft E5 多语言嵌入模型,该模型在零样本和多语言设置中具有最先进的性能。 我们将介绍多语言嵌入的一般工作原理,以及如何在 Elasticsearch 中使用 E5。更多关于多语言的搜索,请阅读 "Elasticsearch:多语言语义搜索"
近年来,向量搜索席卷了搜索和信息检索领域。 它能够将查询的语义与文档相匹配,合并文本的上下文和含义,并为用户提供前所未有的自然语言查询能力。 向量搜索是促进大型语言模型 (LLM) 的重要上下文来源,并且它在生成式 AI 时代赋予越来越多的现代搜索体验。
为什么要使用多语言嵌入?
当研究人员第一次开始使用和训练向量搜索的嵌入模型时,他们使用了他们能找到的最广泛可用的数据集。 然而,这些数据集往往都是英语。 查询是英文的,维基百科索引的文章也是英文的,很快非英语世界就注意到了。 针对德语、法语、中文、日语等语言的特定语言的语言模型慢慢开始出现。 然而,这些模型只能在该语言中运行。 借助嵌入的强大功能,我们还能够使用单个模型来训练将多种语言嵌入到同一 "嵌入空间" 中的模型。 你可以将嵌入空间视为与语言无关的、句子(查询或段落)所表示的概念的数学表示(密集向量),其中嵌入空间中彼此接近的嵌入具有相似的语义含义。
既然我们可以将文本、图像和音频嵌入到一个嵌入空间中,为什么不将多种语言嵌入到同一个嵌入空间中呢? 这就是多语言嵌入模型背后的想法。 通过对齐的训练数据集(包含不同语言的相似句子的数据集),可以使模型学习的不是语言之间的单词翻译,而是每个句子背后的关系和含义,而与语言无关。 这是一个真正的跨语言模型,能够处理其所训练的任何语言的文本对。 现在让我们看看如何使用这些对齐的多语言模型。
让我们考虑几个例子
在本练习中,当英语和德语的句子具有相同的基本含义时,我们会将它们映射到嵌入空间的同一部分。 假设我有以下句子,我想对其进行索引和搜索。 对于非德语人士,我们提供了德语句子的直接英语翻译。 😉
ini
1. id=doc1, language=en, passage="I sat on the bank of the river today."
2. id=doc2, language=de, passage="Ich bin heute zum Flussufer gegangen." (English: "I walked to the riverside today.")
3. id=doc3, language=en, passage="I walked to the bank today to deposit money."
4. id=doc4, language=de, passage="Ich saß heute bei der Bank und wartete auf mein Geld." (English: "I sat at the bank today waiting for my money.")
在下面的示例查询中,我们展示了多语言嵌入如何克服传统词汇检索在多语言搜索中面临的一些挑战。 通常我们谈论向量搜索克服了词法搜索的语义不匹配和词汇不匹配的限制。 语义不匹配是指我们在查询中使用的标记(单词)与索引文档中的形式相同,但含义不同的情况。 例如,河流里的 "bank (岸 )" 与存放金钱的 "bank" 的含义不同。 由于词汇不匹配,我们面临着标记不同,但潜在的概念或含义与文档中表示的含义相似。 我们可能会搜索 "ATM",它没有出现在任何文档中,但与 "bank that holds money (持有货币的银行)" 密切相关。 除了词法搜索的这两项改进之外,多语言(跨语言)嵌入还增加了语言独立性,允许查询和段落使用不同的语言。 要更深入地了解向量搜索的工作原理以及它如何与传统词汇搜索相结合,请观看此网络研讨会:向量数据库如何支持人工智能搜索。
现在让我们尝试一些搜索示例,看看它是如何工作的。
例子 1
查询:"riverside"(德语:"Flussufer")
结果:
ini
1. id=doc1, language=en, passage="I sat on the bank of the river today."
2. id=doc2, language=de, passage="Ich bin heute zum Flussufer gegangen." (English: "I walked to the riverside today.")
在此示例中,"riverside" 在德语中的翻译为 "Flussufer"。 然而,语义含义与英语短语 "bank of the River" 以及德语关键字 "Flussufer" 匹配,因此我们对两个文档进行匹配。
例子2
查询:"Geldautomat"(英语:"ATM")
结果:
ini
1. id=doc4, language=de, passage="Ich saß heute bei der Bank und wartete auf mein Geld." (English: "I sat at the bank today waiting for my money.")
2. id=doc3, language=en, passage="I walked to the bank today to deposit money."
在此示例中,"Geldautomat" 的英文翻译为 "ATM"。 "Geldautomat" 和 "ATM" 都没有作为关键字出现在任何文档中,但语义含义接近英语短语 "bank ... Money" 和德语短语 "Bank ... Geld"。 在这种情况下,上下文很重要,查询指的是持有货币的银行,而不是河岸,因此我们仅匹配引用此类 "bank" 的文档,但我们这样做跨语言基于语义而不是关键字。
例子 3a
查询:"movement"
结果:
ini
1. id=doc3, language=en, passage="I walked to the bank today to deposit money."
2. id=doc2, language=de, passage="Ich bin heute zum Flussufer gegangen." (English: "I walked to the riverside today.")
在此示例中,我们正在搜索文本中表示的运动类型。 我们对运动或行走感兴趣,而不是坐在一处或一动不动。 因此,最接近的文档由德语单词 "gegangen"(英语:"have gone to")和英语单词 "walked" 表示。
例子 3b
查询:"stillness"
结果:
ini
1. id=doc4, language=de, passage="Ich saß heute bei der Bank und wartete auf mein Geld." (English: "I sat at the bank today waiting for my money.")
2. id=doc1, language=en, passage="I sat on the bank of the river today."
如果我们反转示例 3a 中的查询并查找 "stillness" 或缺乏运动,我们会得到"相反"的结果。
多语言E5嵌入模型
2022 年 12 月,微软发布了一种新的通用嵌入模型,称为 E5,或来自 bidirE ctional E ncoder rE presentations 的 E mbEddings。 (我知道,命名事物很困难。)该模型是在一个名为 CCPairs 的特殊的纯英文数据集上进行训练的,并在训练过程中引入了一些新方法。 该模型很快就在众多基准测试中名列前茅,在该模型成功后,他们将目光投向了非英语领域。 除了嵌入英语模型之外,微软后来还使用各种多语言数据集在多语言文本上训练了 E5 模型的变体,但总体过程与英语模型相同。 这表明他们的训练过程在很大程度上帮助产生了如此好的英语嵌入,并且这种成功也转移到了多语言嵌入。 在一些纯英语基准测试中,多语言嵌入甚至比仅在英语数据集上训练的其他嵌入更好! 对于那些感兴趣的人,请查看 MTEB 检索基准以了解更多详细信息。
正如嵌入模型的常见做法,E5 系列提供三种尺寸,允许用户针对其特定用例和预算在有效性和效率之间做出权衡决策。
- 嵌入的有效性是指它们在某项任务上的表现如何,根据特定数据集进行衡量。 对于语义搜索,这是一项检索任务,并使用 nDCG@10 或 MRR@10 等搜索相关性指标来衡量。
- 嵌入和嵌入模型的效率受以下因素影响:
- 模型生成的向量有多少维,这会影响存储需求(磁盘上和内存中)以及它们的搜索速度。
- 嵌入模型有多大(参数数量),这会影响推理延迟或在摄取和搜索时创建嵌入所需的时间。
下面我们可以看到三个多语言 E5 模型及其特征,以及在 Mr. TyDi(看,命名很难)的多语言基准测试上测量的有效性。 作为基线和比较,我们纳入了 Mr. TyDi的 BM25(词汇搜索)有效性分数,如 E5 作者报告的那样。
Effectiveness: Avg. MRR@10 | Efficiency: dimensions | Efficiency: parameters | |
---|---|---|---|
BM25 | 33.3 | n/a | n/a |
multilingual-e5-small | 64.4 | 384 | 118M |
multilingual-e5-base | 65.9 | 768 | 278M |
multilingual-e5-large | 70.5 | 1024 | 560M |
Elasticsearch 使用 E5 进行多语言向量搜索
Elasticsearch 使你能够生成、存储和搜索向量嵌入。 我们已经大致了解了多语言嵌入的介绍,并且对 E5 有了一些了解。 让我们看一下如何将所有这些实际连接到 Elasticsearch 的搜索体验中。 该博客有一个随附的 notebook,其中详细显示了上面示例中使用 Elasticsearch 端到端的所有代码。
以下是所需内容的快速概述:
- 使用一个大小为 8GB 或更大的 ML 节点创建 Elastic Cloud 部署(或使用任何具有 ML 节点的 Elasticsearch 集群)
- 在 Elasticsearch 中设置 multilingual-e5-base 的嵌入模型,以通过推理处理器在摄取时嵌入文本
- 创建索引并将文档提取到 ANN 索引中以进行近似 kNN 搜索
- 使用 query_vector_builder查询 ANN 索引
现在让我们看一下 notebook 中每个步骤的一些代码片段。
设置
创建 Elastic Cloud 集群或准备另一个 Elasticsearch 集群后,我们可以使用 eland 库上传嵌入模型。
lua
1. MODEL_ID = "multilingual-e5-base"
3. !eland_import_hub_model \
4. --cloud-id $CLOUD_ID \
5. --es-username elastic \
6. --es-password $ELASTIC_PASSWORD \
7. --hub-model-id intfloat/$MODEL_ID \
8. --es-model-id $MODEL_ID \
9. --task-type text_embedding \
10. --start
现在模型已上传到集群并准备好进行推理,我们可以创建包含 inference pipeline 的 ingest pipeline 来执行我们选择的文本字段的嵌入。 使用网络爬虫等企业搜索功能时,你还可以通过 Kibana UI 管理摄取管道。
ini
1. client.ingest.put_pipeline(id="pipeline", processors=[{
2. "inference": {
3. "model_id": MODEL_ID,
4. "field_map": {
5. "passage": "text_field" # field to embed: passage
6. },
7. "target_field": "passage_embedding" # embedded field: passage_embedding
8. }
9. }])
索引数据
对于上面的简单示例,我们仅使用一个非常简单的索引映射,但希望它也能让你了解你的映射可能是什么样子。
json
1. mapping = {
2. "properties": {
3. "id": { "type": "keyword" },
4. "language": { "type": "keyword" },
5. "passage": { "type": "text" },
6. "passage_embedding.predicted_value": {
7. "type": "dense_vector",
8. "dims": 768,
9. "index": "true",
10. "similarity": "cosine"
11. }
12. },
13. "_source": {
14. "excludes": [
15. "passage_embedding.predicted_value"
16. ]
17. }
18. }
使用根据上述映射创建的索引,我们就可以提取文档了。 你可以使用任何你想要的摄取方法,只要引用我们在开始时创建的摄取管道(或设置为索引的默认值)即可。 请注意,与其他嵌入模型一样,E5 确实有 token 限制(512 个令牌或约 400 个单词),因此较长的文本需要在被摄取之前分块为单独的段落(例如使用 LangChain 或其他工具)。 这是我们的示例文档的样子。
ini
1. passages = [
2. {
3. "id": "doc1",
4. "language": "en",
5. "passage": """I sat on the bank of the river today."""
6. },
7. {
8. "id": "doc2",
9. "language": "de",
10. "passage": """Ich bin heute zum Flussufer gegangen."""
11. },
12. {
13. "id": "doc3",
14. "language": "en",
15. "passage": """I walked to the bank today to deposit money."""
16. },
17. {
18. "id": "doc4",
19. "language": "de",
20. "passage": """Ich saß heute bei der Bank und wartete auf mein Geld."""
21. }
22. ]
搜索
文档已被索引并创建了嵌入,因此我们准备好搜索!
perl
1. client.search(index="passages", knn={
2. "field": "passage_embedding.predicted_value",
3. "query_vector_builder": {
4. "text_embedding": {
5. "model_id": MODEL_ID,
6. "model_text": f"query: {q}",
7. }
8. },
9. "k": 2, # for the demo, we're always just searching for pairs of passages
10. "num_candidates": 5
11. })
就是这样! 通过上述步骤以及 notebook 中的完整代码,你可以完全在 Elasticsearch 中构建自己的多语言语义搜索体验。
注意:E5 模型在嵌入之前使用文本前缀的指令进行训练。 这意味着当你想要嵌入文本进行语义搜索时,必须在查询前加上 "query:" 前缀,并在索引段落前加上 "passage:"。 有关更多详细信息和需要不同前缀的其他用例,请参阅 multilingual-e5-base 模型卡中的常见问题解答。
结论
在本博客和随附的 notebook 中,我们展示了多语言向量搜索的工作原理,以及如何将 Elasticsearch 与 E5 嵌入模型结合使用。 我们通过展示跨语言的多语言搜索示例来推动这一点,但实际上相同的 E5 嵌入模型也可以在单一语言中使用。 例如,如果你只有一个德语文本语料库,你可以自由地使用相同的模型和相同的方法来仅使用德语查询来搜索该语料库。 它们都是相同的模型,并且最终的嵌入空间相同!
试用 notebook,并确保启动你自己的云集群,以尝试使用 E5 对你选择的语言和数据集进行多语言语义搜索。 如果你有任何疑问或想要讨论多语言语义搜索,请加入我们和整个 Elastic 社区的讨论论坛。