作者:来自 Elastic Dai Sugimori
了解稀疏向量嵌入,理解它们的作用/含义,以及如何使用它们实现语义搜索。
Elasticsearch 提供语义搜索功能,允许用户使用自然语言进行查询并检索相关信息。为此,目标文档和查询必须首先通过嵌入过程转换为向量表示,该过程由在 Elasticsearch 内部或外部运行的经过训练的机器学习 (ML) 模型处理。
由于选择好的机器学习模型对于大多数搜索用户来说并不容易,因此 Elastic 推出了一个名为 ELSER (Elastic Learned Sparse EncodeR) 的自制 ML 模型。它与 Elasticsearch 捆绑在一起,因此他们可以根据白金许可开箱即用(请参阅订阅页面)。它是一种广泛使用的实现语义搜索的模型。与许多其他生成 “密集向量” 的模型不同,ELSER 生成的是 “稀疏向量”,它们以不同的方式表示嵌入。
虽然稀疏向量模型在许多用例中都有效,但直到 Elasticsearch 和 Eland 8.16 版本,只有密集向量模型才能上传到 Elasticsearch。但是,从 8.17 版开始,你现在也可以使用 Eland 的 eland_import_hub_model CLI 上传稀疏向量模型。这意味着你可以使用 Hugging Face 中的模型(而不仅仅是 ELSER)生成稀疏向量嵌入。
在本文中,我想回顾一下稀疏向量与密集向量的比较,并介绍如何从外部上传它们以在 Elasticsearch 中使用。
什么是稀疏向量?
密集向量和稀疏向量有什么区别?让我们从密集向量开始,密集向量在当今的搜索中更常用。
密集向量 - dense vector
当文本嵌入为密集向量时,它看起来像这样:
[0.13586345314979553,-0.6291824579238892,0.32779985666275024,0.36690405011177063,...
]
密集向量的主要特征:
- 向量具有固定维度。
- 每个元素都是浮点数。
- 每个元素都代表一些特征,但它们的含义不易被人类解释。
- 大多数元素具有非零值。
如果输入文本的含义相似,ML 模型(尤其是基于 transformer 的模型)将产生几何相似的向量。相似度由一些不同的函数计算,例如余弦、l2_norm 等。
例如,如果我们嵌入单词 “cat” 和 “kitten”,它们的向量在向量空间中会彼此接近,因为它们具有相似的语义含义。相反,“car” 的向量会更远,因为它代表一个完全不同的概念。

Elastic 有许多关于向量搜索的有趣文章。如果你有兴趣了解更多信息,请参考它们:
- 向量搜索快速入门 - Elasticsearch Labs
- 探索 Elastic 向量数据库 - Elasticsearch Labs
- 向量相似度技术和评分 - Elasticsearch Labs
稀疏向量 - sparse vector
相比之下,稀疏向量具有不同的结构。它们不是为每个维度分配一个值,而是主要由零组成,只有少数非零值。稀疏向量表示如下所示:
{"f1":1.2,"f2":0.3,… }
稀疏向量的主要特征:
- 向量中的大多数值都是零。
- 它们通常存储为键值对,而不是固定长度的数组,其中只记录非零值。
- 具有零值的特征永远不会出现在稀疏向量表示中。
- 表示更具可解释性,因为每个键(特征)通常对应于一个有意义的术语或概念。
BM25 和稀疏向量表示
BM25 是一种著名的词汇搜索排名函数,它使用文本的稀疏向量表示,即术语向量。在此表示中,文档中的每个术语(称为标记或单词)都根据其在语料库(一组文档)中的频率和重要性分配权重。此方法通过将查询术语与文档术语匹配来实现高效检索。
更多阅读,请参阅 “Elasticsearch:分布式计分 - TF-IDF”。
词汇搜索 vs. 语义搜索
BM25 是词汇搜索的一个示例,其中匹配基于在文档中找到的精确术语。它依赖于从语料库的词汇中派生的稀疏向量表示。
另一方面,语义搜索超越了精确术语匹配。它使用向量嵌入来捕获单词和短语的含义,即使它们不包含精确的查询术语,也可以检索相关文档。
此外,Elasticsearch 可以做更多。你可以将这两个搜索合并为一个查询作为混合搜索。请参阅以下链接以了解更多信息。
- 当混合搜索真正大放异彩时 - Elasticsearch Labs
- 具有多个嵌入的混合搜索:有趣且毛茸茸的猫咪搜索! - Elasticsearch Labs
- 混合搜索:结合全文和 kNN 结果 - Elasticsearch Labs
- 混合搜索:结合全文和 ELSER 结果 - Elasticsearch Labs
- 教程:使用 semantic_text 进行混合搜索 | Elasticsearch 指南 | Elastic
语义搜索中的密集和稀疏向量
语义搜索可以同时利用密集和稀疏向量:
- 密集向量模型(例如基于 BERT 的模型)将语义含义编码为固定长度的向量,从而实现基于向量距离的相似性搜索。
- 稀疏向量模型(例如 ELSER)在保留可解释性的同时捕获语义含义,通常利用基于术语的权重。
借助 Elasticsearch 8.17,你现在可以上传和使用密集和稀疏向量模型,从而让你能够更灵活地实施满足你需求的语义搜索。
为什么是稀疏向量?
稀疏向量在 Elasticsearch 中具有多种优势,在某些情况下,它们可以成为密集向量的有力替代品。例如,密集向量 (knn) 搜索要求使用用户正在使用的领域的良好/足够的语料库来学习模型。但要拥有适合你用例的模型并不总是那么容易,而对大多数用户来说,微调模型甚至更难。在这种情况下,稀疏向量模型将为你提供帮助。让我们来了解一下原因。
适合零样本学习
稀疏向量,尤其是由 ELSER 等模型生成的稀疏向量,可以很好地推广到新领域,而无需进行大量微调。与通常需要特定领域训练的密集向量模型不同,稀疏向量依赖于基于术语的表示,这使得它们更适合零样本检索 - 模型可以处理尚未明确训练的查询。
资源效率
稀疏向量本质上比密集向量更节省资源。由于它们主要包含零,并且仅将非零值存储为键值对,因此它们需要较少的内存和存储空间。
Elasticsearch 中的稀疏向量
Elasticsearch 最初使用 rank_features 查询支持稀疏向量搜索。但是,随着最近的进步,稀疏向量搜索现在可以通过 sparse_vector 查询原生实现,从而更好地与 Elasticsearch 的机器学习模型集成。
与 ML 模型集成
sparse_vector 查询旨在与在 Elasticsearch ML 节点上运行的经过训练的模型无缝协作。这允许用户动态生成稀疏向量嵌入并使用高效的相似性搜索检索相关文档。
利用 Lucene 的倒排索引
Elasticsearch 中稀疏向量的主要优势之一是它们利用 Lucene 的倒排索引 - 这与 Elasticsearch 快速且可扩展的搜索所采用的核心技术相同。
- 资源效率:由于 Lucene 针对基于术语的索引进行了优化,因此稀疏向量可从高效的存储和检索中受益。
- 成熟度:Elasticsearch 拥有完善且高度优化的索引系统,因此稀疏向量搜索非常适合其架构。
通过利用 Lucene 的索引功能,Elasticsearch 可确保稀疏向量搜索保持快速、可扩展且资源高效,使其成为实际搜索应用程序的不二之选。
使用 Hugging Face 中的首选模型实现稀疏嵌入
从 Elasticsearch 8.17 开始,只要使用受支持的标记化(tokenization)方法,你就可以使用 Hugging Face 中的任何稀疏向量模型。这可以更灵活地使用根据你的特定需求量身定制的模型来实现语义搜索。
Elasticsearch 目前支持以下稀疏和密集向量嵌入的标记化方法:
- bert – 适用于 BERT 样式模型
- deberta_v2 – 适用于 DeBERTa v2 和 v3 样式模型
- mpnet – 适用于 MPNet 样式模型
- roberta – 适用于 RoBERTa 样式和 BART 样式模型
- xlm_roberta – 适用于 XLM-RoBERTa 样式模型
- bert_ja – 适用于专门针对日语训练的 BERT 样式模型
有关受支持的标记化方法的完整列表,请参阅官方文档:Elasticsearch 参考:PUT 训练模型
如果你的模型的标记化可用,即使它不适用于非英语语言,你也可以选择它!以下是 Hugging Face 上可用的一些稀疏模型示例:
- naver/splade-v3-distilbert
- hotchpotch/japanese-splade-v2
- aken12/splade-japanese-v3
使用 Hugging Face 稀疏向量模型的步骤
我们已经有一篇关于使用 ELSER 进行稀疏向量搜索的好文章。大部分步骤都相同,但如果你想使用 Hugging Face 的稀疏嵌入模型,则需要事先使用 Eland 将其上传到 Elasticsearch。
以下是在 Elasticsearch 上使用外部稀疏模型进行语义搜索的分步指南。
1. 找到一个稀疏向量模型
浏览 Hugging Face (huggingface.co) 以查找适合你用例的稀疏嵌入模型(sparse embedding model)。确保该模型使用上面列出的受支持的标记化方法之一。
让我们选择 “naver/splade-v3-distilbert” 模型作为稀疏嵌入模型的示例。
注意:Elastic 的 ELSER 模型深受 Naver 的 SPLADE 模型的启发。访问他们的网站以了解有关 SPLADE 的更多信息。
2. 将模型上传到 Elasticsearch
你需要安装 Eland,这是一个用于 Elasticsearch 中的 DataFrames 和机器学习的 Python 客户端和工具包。请注意,你需要 Eland 8.17.0 或更高版本才能上传稀疏向量模型。
python -m pip install eland
一旦在你的计算机上安装完毕,请使用 Eland 的 CLI 工具 (eland_import_hub_model) 将模型导入 Elasticsearch。
eland_import_hub_model \
--url "your.elasticsearch.host" \
--es-api-key "your_api_key" \
--hub-model-id naver/splade-v3-distilbert \
--task-type text_expansion \
--start
或者,如果你不想在本地安装 Eland,你可以对 Docker 执行相同的操作。
docker run -it --rm docker.elastic.co/eland/eland \
eland_import_hub_model \
--url "your.elasticsearch.host" \
--es-api-key "your_api_key" \
--hub-model-id naver/splade-v3-distilbert \
--task-type text_expansion \
--start
这里的关键点是,你需要将 text_expansion 设置为稀疏向量嵌入的任务类型,而不像将 text_embedding 设置为密集向量嵌入的任务类型。(仅供参考,有关于任务名称的讨论。)
3. 使用 sparse_vector 定义索引映射
创建一个具有 sparse_vector 字段的索引。
PUT sparse-test
{"mappings": {"properties": {"content_embedding": { "type": "sparse_vector" },"content": { "type": "text" }}}
}
需要注意的是,sparse_vector 字段类型以前称为 rank_features 字段类型。虽然它们之间没有功能差异,但为了清楚使用,你应该使用 sparse_vector 字段类型。
注意:Elastic 最近引入了一个 semantic_text 字段。它非常有用且易于实现的语义搜索。有关详细信息,请参阅本文。你可以将 semantic_text 字段用于相同目的,但为了专注于嵌入部分,我们现在使用 sparse_vector 字段。
4. 使用推理处理器创建摄取管道
文本信息需要先嵌入到稀疏向量中,然后再进行索引。这可以通过带有推理处理器的摄取管道来完成。
使用推理处理器创建摄取管道,该推理处理器引用你之前上传的模型。
PUT _ingest/pipeline/sparse-test-pipeline
{"processors": [{"inference": {"model_id": "naver__splade-v3-distilbert","input_output": [ {"input_field": "content","output_field": "content_embedding"}]}}]
}
5. 使用管道提取数据
使用我们创建的 “sparse-test-pipeline” 将文本数据提取到索引中,以便内容自动嵌入到稀疏向量表示中。
POST sparse-test/_doc/1?pipeline=sparse-test-pipeline
{"content": "Elasticsearch provides a semantic search feature that allows users to query in natural language and retrieve relevant information."
}
完成后,让我们检查一下它是如何被索引的。
GET sparse-test/_doc/1
它将像这样返回:
{"_index": "sparse-test","_id": "1","_source": {"content": "Elasticsearch provides a semantic search feature that allows users to query in natural language and retrieve relevant information.","content_embedding": {"software": 3.2601595,"web": 2.0722878,"browser": 1.8972412,"platform": 1.6211865,"java": 1.5984035,"sql": 1.5119768,"engine": 1.4900811,...},"model_id": "naver__splade-v3-distilbert"}
}
可以看到,输入文本 “Elasticsearch provides a semantic search feature that allows users to query in natural language and retrieve relevant information.” 嵌入为:
{"software": 3.2601595,"web": 2.0722878,"browser": 1.8972412,"platform": 1.6211865,"java": 1.5984035,"sql": 1.5119768,"engine": 1.4900811,...
}
如你所见,输入文本并未直接提及响应中列出的大多数单词,但它们在语义上看起来相关。这意味着,模型根据模型训练的语料库知道这些词的概念与输入文本相关。因此,这些稀疏嵌入的质量取决于你配置的 ML 模型。
使用语义查询进行搜索
现在,你可以使用 sparse_vector 查询对 “sparse-test” 索引执行语义搜索。我已将一些 Elastic 的博客内容导入到 sparse-test 索引中,让我们来测试一下。
GET sparse-test/_search
{"query":{"sparse_vector":{"field": "content_embedding","inference_id": "naver__splade-v3-distilbert","query": "How to implement semantic search?"}}
}
答复是:
{"hits": {"hits": [{"_index": "sparse-test","_id": "QYrHE5UB5umUPDxXt3YF","_score": 1.9065769,"_source": {"content": "In this article, we'll learn how to connect local models to the Elasticsearch inference model using Ollama and then ask your documents questions using Playground.","content_embedding": {"algorithms": 1.2229483,"modeling": 1.4566671,"inference": 1.4407207,"software": 1.3217216,"neural": 0.4337984,...},"model_id": "naver__splade-v3-distilbert"}},{"_index": "sparse-test","_id": "RorHE5UB5umUPDxXt3YF","_score": 1.4432585,"_source": {"content": "One of the main challenges that developers, SREs, and DevOps professionals face is the absence of an extensive tool that provides them with visibility to their application stack. Many of the APM solutions out on the market do provide methods to monitor applications that were built on languages and frameworks (i.e., .NET, Java, Python, etc.) but fall short when it comes to C++ applications.","content_embedding": {"code": 0.3599707,"software": 2.6935644,"developers": 0.4449697,"cad": 0.19158684,"##kit": 0.03371501,...},"model_id": "naver__splade-v3-distilbert"}},{"_index": "sparse-test","_id": "SorHE5UB5umUPDxXt3YF","_score": 1.2041138,"_source": {"content": "Elastic and Confluent are key technology partners and we're pleased to announce new investments in that partnership. Built by the original creators of Apache Kafka®, Confluent's data streaming platform is a key component of many Enterprise ingest architectures, and it ensures that customers can guarantee delivery of critical Observability and Security data into their Elasticsearch clusters. Together, we've been working on key improvements to how our products fit together. With Elastic Agent's new Kafka output and Confluent's newly improved Elasticsearch Sink Connectors it's never been easier to seamlessly collect data from the edge, stream it through Kafka, and into an Elasticsearch cluster.","content_embedding": {"server": 0.98200905,"software": 2.248463,"link": 0.37674126,"technology": 0.9098742,"networks": 0.8262937,...},"model_id": "naver__splade-v3-distilbert"}},...]}
}
如你所见,原始内容嵌入到稀疏向量表示中,因此你可以轻松理解模型如何确定这些文本的含义。第一个结果不包含查询文本中可以找到的大多数单词,但由于稀疏向量表示相似,因此相关性得分仍然很高。
为了获得更好的精度,你还可以尝试使用 RRF 进行混合搜索,以便你可以在一个查询中结合词汇和语义搜索。请参阅官方教程以了解更多信息。
结论
稀疏向量提供了一种强大而有效的方法来增强 Elasticsearch 中的搜索功能。与密集向量不同,稀疏向量具有关键优势,例如更好的零样本性能和资源效率。它们与 Elasticsearch 的机器学习功能无缝集成,并利用 Lucene 成熟且优化的倒排索引,使其成为许多应用程序的实用选择。
从 Elasticsearch 8.17 开始,用户现在可以根据自己的特定需求在密集和稀疏向量模型之间进行更灵活的选择。无论你是在寻找可解释的表示、可扩展的搜索性能还是高效的内存使用,稀疏向量都是现代搜索应用程序的一个引人注目的选择。
随着 Elasticsearch 的不断发展,稀疏向量搜索将在未来的信息检索中发挥越来越重要的作用。现在,你可以利用 ELSER 和其他 Hugging Face 模型来探索语义搜索的新可能性。
使用此自定进度的 Search AI 动手学习亲自尝试向量搜索。你现在可以开始免费的云试用或在本地机器上试用 Elastic。
原文:https://www.elastic.co/search-labs/blog/sparse-vector-embedding