赞
踩
作者:来自 Elastic Carlos Delgado, Mike Pellegrini
你是否想开始使用语义搜索来搜索数据,但专注于模型和结果而不是技术细节?我们引入了 semantic_text 字段类型,它将处理你所需的细节和基础架构。
语义搜索(semantic search)是一种复杂的技术,旨在通过利用机器学习模型来增强搜索结果的相关性。与传统的基于关键字的搜索不同,语义搜索专注于理解单词的含义及其使用的上下文。这是通过应用机器学习模型来实现的,这些模型可以提供对文本的更深入的语义理解。
这些模型生成向量嵌入(vector embeddings),它们是捕获文本含义的数字表示。这些嵌入与你的文档数据一起存储,从而启用考虑单词含义和上下文而不是纯词汇匹配的向量搜索技术。
要执行语义搜索,你需要执行以下步骤:
从头开始配置语义搜索可能很复杂。它需要设置映射、提取管道和针对你选择的推理模型量身定制的查询。每个步骤都提供了微调和优化的机会,但也需要仔细配置以确保所有组件无缝协作。
虽然这提供了很大程度的控制,但它使使用语义搜索成为一个详细而深思熟虑的过程,要求你配置彼此相关并与推理模型相关的单独部分。
semantic_text 通过专注于重要的事情来简化此过程:推理模型。一旦你选择了推理模型,semantic_text 将通过提供合理的默认值让你轻松开始使用语义搜索,这样你就可以专注于搜索,而不是如何索引、生成或查询嵌入。
让我们看一下每个步骤,以及 semantic_text 如何简化此设置。
推理模型将为你的文档和查询生成嵌入。不同的模型在以下方面有不同的权衡:
Elasticsearch 支持内部和外部推理服务:
选择推理模式后,为其创建推理端点。推理端点标识符将是你设置 semantic_text 所需的唯一配置详细信息。
PUT _inference/sparse_embedding/my-elser-endpoint
- {
- "service": "elser",
- "service_settings": {
- "num_allocations": 1,
- "num_threads": 1
- }
- }
Elasticsearch 需要对模型生成的嵌入进行索引,以便以后可以有效地查询它们。
在使用 semantic_text 之前,你需要了解用于存储嵌入信息的两个主要字段类型:
要使用的字段类型取决于你选择的模型。如果使用密集向量,你需要配置字段以包含维度计数、用于计算向量接近度的相似度函数以及存储自定义,例如量化或每个元素使用的特定数据类型。
现在,如果你使用 semantic_text,则只需为模型指定推理端点标识符即可定义 semantic_text 字段映射:
PUT test-index
- {
- "mappings": {
- "properties": {
- "infer_field": {
- "type": "semantic_text",
- "inference_id": "my-elser-endpoint"
- }
- }
- }
- }
就是这样。你无需定义其他映射选项,也无需了解需要使用哪种字段类型。
一旦你的索引准备好存储嵌入,就该生成它们了。
在 semantic_text 之前,要自动在文档摄取时生成嵌入,你需要设置摄取管道。
摄取管道用于在摄取到索引中时或在摄取过程中明确指定时自动丰富或转换文档。
你需要使用 inference processor 为你的字段生成嵌入。处理器需要使用以下内容进行配置:
使用 semantic_text,你只需将文档添加到索引中。semantic_text 字段将使用指定的推理端点自动计算嵌入。
这意味着无需创建推理管道来生成嵌入。使用批量、索引或更新 API 将自动为你执行此操作:
PUT test-index/_doc/doc1
- {
- "infer_field": "These are not the droids you're looking for. He's free to go around"
- }
semantic_text 字段中的推理请求也是批量处理的。如果你在 bulk API 请求中有 10 个文档,并且每个文档包含 2 个 semantic_text 字段,那么该请求将一次性向你的推理服务执行包含 20 个文本的单个推理请求,而不是每次发出 10 个包含 2 个文本的单独推理请求。
选择模型的挑战之一是模型可以生成嵌入的标记数量。模型可以处理的标记数量有限。这被称为模型的上下文窗口。
如果你需要处理的文本比模型的上下文窗口长,你可以截断文本并仅使用其中的一部分来生成嵌入。这并不理想,因为你会丢失信息;生成的嵌入将无法捕获输入文本的完整上下文。
即使你有一个长的上下文窗口,长文本也意味着大量内容将被缩减为单个嵌入,从而使其成为不准确的表示。
此外,返回长文本会让用户难以理解,因为他们必须扫描文本以检查它是否是他们要查找的内容。最好使用较小的片段。
另一种选择是使用分块将长文本分成较小的片段。这些较小的块被添加到每个文档中,以更好地表示完整的文本。然后,你可以使用嵌套查询搜索所有单个片段并检索包含得分最高的块的文档。
在 semantic_text 之前,分块不是开箱即用的 - 推理处理器不支持分块。如果你需要使用分块,则需要在提取文档之前进行分块,或者使用脚本处理器在 Elasticsearch 中执行分块。
使用 semantic_text 意味着在索引时将为你完成分块。长文档将被拆分为 250 个单词的部分,其中有 100 个单词重叠,因此每个部分与前一个部分共享 100 个单词。这种重叠可确保连续性,并防止输入文本中的重要上下文信息因硬中断而丢失。
如果模型和推理服务支持批处理,则分块输入会自动批处理为尽可能少的请求,每个请求的大小都适合推理服务。生成的块将存储在嵌套对象结构中,以便你可以检查每个块中包含的文本。
现在文档及其嵌入已在 Elasticsearch 中编入索引,是时候进行一些查询了!
在使用 semantic_text 之前,你需要根据模型生成的嵌入类型(密集或稀疏)使用不同的查询。查询 sparse_vector 字段类型需要 sparse vector query,而搜索 density_vector 字段类型则可以使用 knn search 或 knn query。
查询过程可以进一步定制,以提高性能和相关性。例如,稀疏向量查询可以定义标记修剪(token pruning),以避免考虑不相关的标记。Knn 查询可以指定要考虑的候选数以及要从每个分片返回的前 k 个结果。
使用 semantic_text 时,你无需处理这些细节。你可以使用 single query type 来搜索文档:
GET test-index/_search
- {
- "query": {
- "semantic": {
- "field": "inference_field",
- "query": "robots you're searching for"
- }
- }
- }
只需包含字段和查询文本。无需在稀疏向量和 knn 查询之间做出选择,语义文本会为你完成此操作。
将其与使用具有所有配置参数的特定 knn 搜索进行比较:
- {
- "knn": {
- "field": "inference-field",
- "k": 10,
- "num_candidates": 100,
- "query_vector_builder": {
- "text_embedding": {
- "model_id": "my-dense-vector-embedding-model",
- "model_text": "robots you're searching for"
- }
- }
- }
- }
要了解 semantic_text 的工作原理,你可以创建一个 semantic_text 索引并检查摄取文档时会发生什么。摄取第一个文档时,推理端点会计算嵌入。索引后,你会注意到索引映射中的变化:
GET test-index
- {
- "test-index": {
- "mappings": {
- "properties": {
- "infer_field": {
- "type": "semantic_text",
- "inference_id": "my-elser-endpoint",
- "model_settings": {
- "task_type": "sparse_embedding"
- }
- }
- }
- }
- }
- }
现在有关于模型设置的附加信息。文本嵌入模型还将包括模型的维度数或相似度函数等信息。
你可以检查文档是否已包含嵌入结果:
GET test-index/_doc/doc1
- {
- "_index": "test-sparse",
- "_id": "doc1",
- "_source": {
- "infer_field": {
- "text": "these are not the droids you're looking for. He's free to go around",
- "inference": {
- "inference_id": "my-elser-endpoint",
- "model_settings": {
- "task_type": "sparse_embedding"
- },
- "chunks": [
- {
- "text": "these are not the droids you're looking for. He's free to go around",
- "embeddings": {
- "##oid": 1.9103845,
- "##oids": 1.768872,
- "free": 1.693662,
- "dr": 1.6103356,
- "around": 1.4376559,
- "these": 1.1396849
-
- …
- }
- }
- ]
- }
- }
- }
- }
该字段不仅包含输入文本,还包含一个结构,用于存储原始文本、模型设置以及输入文本被划分成的每个块的信息。
此结构由一个具有两个元素的对象组成:
semantic_text 通过对数据进行索引和查询做出默认决策来简化语义搜索:
这些都是合理的默认值,可让你快速轻松地开始使用语义搜索。随着时间的推移,你可能希望自定义查询和数据类型以优化搜索相关性、索引和查询性能以及索引存储。
目前还没有针对语义查询的自定义选项。如果你想针对 semantic_text 字段自定义查询,可以使用显式 knn 和稀疏向量查询执行高级 semantic_text 搜索。
我们计划添加对 semantic_text 的 retrievers 支持,并向 semantic_text 字段添加配置选项,以便在查询时不需要它们。敬请期待!
如果你需要对数据索引进行更深入的自定义,则可以使用 sparse_vector 或 density_vector 字段类型。这些字段类型让你可以完全控制嵌入的生成、索引和查询方式。
你需要创建一个带有推理处理器的摄取管道来生成嵌入。本教程将引导你完成整个过程。
我们刚刚开始使用 semantic_text!我们将继续致力于许多增强功能,包括:
使用此笔记本[准备好后添加链接]探索语义文本,快速了解语义文本的工作原理。
如果你已经拥有 Elasticsearch 集群,则可以在本教程中查看使用语义文本测试语义搜索的完整示例。
我们很乐意听听你使用语义文本的经验!请在论坛中告诉我们你的想法,或在 GitHub 存储库中打开问题。让我们一起让语义搜索更容易!
准备好自己尝试一下了吗?开始免费试用。
Elasticsearch 集成了 LangChain、Cohere 等工具。加入我们的高级语义搜索网络研讨会,构建你的下一个 GenAI 应用程序!
原文:Semantic search simplified with semantic_text — Elastic Search Labs
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。