加载中

使用 ELSER 进行语义搜索

Elastic Learned Sparse EncodeR(简称 ELSER)是 Elastic 训练的一个 NLP 模型,使你能够通过使用稀疏向量表示来执行语义搜索。语义搜索不是对搜索词进行字面匹配,而是根据搜索查询的意图和上下文含义来检索结果。

本教程中的说明展示了如何使用 ELSER 对你的数据执行语义搜索。

重要提示

如需了解在 Elastic Stack 中执行语义搜索的最简便方法,请参阅 semantic_text 端到端教程。

注意

在使用 ELSER 进行语义搜索时,每个字段仅考虑前 512 个提取的 Token。有关更多信息,请参考此页面

要使用 ELSER 执行语义搜索,你必须在集群中部署该 NLP 模型。请参考 ELSER 文档了解如何下载和部署该模型。

注意

如果关闭了部署自动扩缩容,在 Elastic Cloud Hosted 中部署和使用 ELSER 模型的最小专用 ML 节点大小为 4 GB。建议开启自动扩缩容,因为它允许你的部署根据需求动态调整资源。通过使用更多分配或每个分配更多线程可以获得更好的性能,这需要更大的 ML 节点。自动扩缩容会在需要时提供更大的节点。如果关闭了自动扩缩容,你必须自行提供合适大小的节点。

首先,必须创建目标索引的映射——包含模型根据你的文本创建的 Token 的索引。目标索引必须具有带有 sparse_vectorrank_features 字段类型的字段,以便对 ELSER 输出进行索引。

注意

ELSER 输出必须摄入到具有 sparse_vectorrank_features 字段类型的字段中。否则,Elasticsearch 会将 Token-权重对解释为文档中的大量字段。如果你遇到类似以下的错误:"Limit of total fields [1000] has been exceeded while adding new fields",则说明 ELSER 输出字段未正确映射,并且其字段类型不是 sparse_vectorrank_features

				PUT my-index
					{
  "mappings": {
    "properties": {
      "content_embedding": {
        "type": "sparse_vector"
      },
      "content": {
        "type": "text"
      }
    }
  }
}
		
  1. 包含生成的 Token 的字段名称。必须在下一步的推理管道配置中引用它。
  2. 包含 Token 的字段是一个 sparse_vector 字段。
  3. 用于创建稀疏向量表示的源字段名称。在此示例中,字段名称为 content。必须在下一步的推理管道配置中引用它。
  4. 字段类型,在此示例中为 text。

要了解如何优化空间,请参考通过从文档源中排除 ELSER Token 来节省磁盘空间,并配合使用推理处理器来使用 ELSER 对管道中正在摄入的数据进行推理。

				PUT _ingest/pipeline/elser-v2-test
					{
  "processors": [
    {
      "inference": {
        "model_id": ".elser_model_2",
        "input_output": [
          {
            "input_field": "content",
            "output_field": "content_embedding"
          }
        ]
      }
    }
  ]
}
		
  1. 配置对象,定义推理过程的 input_field 以及将包含推理结果的 output_field

在此步骤中,你加载稍后将在推理摄入管道中使用的、从中提取 Token 的数据。

使用 msmarco-passagetest2019-top1000 数据集,它是 MS MARCO 段落排序数据集的一个子集。它包含 200 个查询,每个查询都附带一个相关文本段落列表。所有不重复的段落及其 ID 都已从该数据集中提取并编译成一个 tsv 文件

重要提示

msmarco-passagetest2019-top1000 数据集未用于训练该模型。我们在本教程中使用这个示例数据集,是因为它易于获取以便进行演示。你可以使用其他数据集来测试工作流并熟悉它。

下载文件并使用 UI 中的文件上传器将其上传到你的集群。分析数据后,点击 Override settings。在 Edit field names 下,将第一列指定为 id,第二列指定为 content。点击 Apply,然后点击 Import。将索引命名为 test-data,然后点击 Import。上传完成后,你将看到一个名为 test-data 的索引,其中包含 182,469 个文档。

通过使用 ELSER 作为推理模型的推理管道对数据进行重新索引,从文本中创建 Token。

				POST _reindex?wait_for_completion=false
					{
  "source": {
    "index": "test-data",
    "size": 50
  },
  "dest": {
    "index": "my-index",
    "pipeline": "elser-v2-test"
  }
}
		
  1. 重新索引的默认批处理大小为 1000。将 size 减小为更小的数值可以使重新索引过程的更新更迅速,从而方便您密切跟踪进度并及早发现错误。

该调用返回一个用于监控进度的任务 ID

				GET _tasks/<task_id>
		

你还可以打开“已训练模型”UI,选择 ELSER 下的“管道”选项卡来跟踪进度。

重新索引大型数据集可能需要很长时间。你可以仅使用数据集的子集来测试此工作流。方法是取消重新索引过程,仅为已重新索引的子集生成嵌入。以下 API 请求将取消重新索引任务

				POST _tasks/<task_id>/_cancel
		

要执行语义搜索,请使用 sparse_vector 查询,并提供查询文本以及与你的 ELSER 模型关联的推理 ID。下面的示例使用查询文本 "How to avoid muscle soreness after running?",其中 content_embedding 字段包含生成的 ELSER 输出

				GET my-index/_search
					{
   "query":{
      "sparse_vector":{
         "field": "content_embedding",
         "inference_id": "my-elser-endpoint",
         "query": "How to avoid muscle soreness after running?"
      }
   }
}
		

结果是来自 my-index 索引的、在语义上与你的查询文本最接近且按相关性排序的前 10 个文档。结果还包含每个相关搜索结果中提取的 Token 及其权重。Token 是捕获相关性的学得关联,它们不是同义词。要了解有关 Token 是什么的更多信息,请参考此页面。可以从源中排除 Token,请参考本节了解更多信息。

"hits": {
  "total": {
    "value": 10000,
    "relation": "gte"
  },
  "max_score": 26.199875,
  "hits": [
    {
      "_index": "my-index",
      "_id": "FPr9HYsBag9jXmT8lEpI",
      "_score": 26.199875,
      "_source": {
        "content_embedding": {
          "muscular": 0.2821541,
          "bleeding": 0.37929374,
          "foods": 1.1718726,
          "delayed": 1.2112266,
          "cure": 0.6848574,
          "during": 0.5886185,
          "fighting": 0.35022718,
          "rid": 0.2752442,
          "soon": 0.2967024,
          "leg": 0.37649947,
          "preparation": 0.32974035,
          "advance": 0.09652356,
          (...)
        },
        "id": 1713868,
        "model_id": ".elser_model_2",
        "content": "For example, if you go for a run, you will mostly use the muscles in your lower body. Give yourself 2 days to rest those muscles so they have a chance to heal before you exercise them again. Not giving your muscles enough time to rest can cause muscle damage, rather than muscle development."
      }
    },
    (...)
  ]
}
		

你可以在复合查询中将 sparse_vector 与其他查询结合使用。例如,在 Boolean 查询中使用 filter 子句,或者使用与 sparse_vector 查询相同(或不同)查询文本的全文本查询。这使你能够结合两个查询的搜索结果。

来自 sparse_vector 查询的搜索命中项的得分往往比其他 Elasticsearch 查询更高。可以通过使用 boost 参数增加或减少每个查询的相关性得分来对这些得分进行调整。sparse_vector 查询的召回率可能很高,其中包含长尾的不太相关的结果。使用 min_score 参数可以剪枝这些不太相关的文档。

				GET my-index/_search
					{
  "query": {
    "bool": {
      "should": [
        {
          "sparse_vector": {
            "field": "content_embedding",
            "inference_id": "my-elser-endpoint",
            "query": "How to avoid muscle soreness after running?",
            "boost": 1
          }
        },
        {
          "query_string": {
            "query": "toxins",
            "boost": 4
          }
        }
      ]
    }
  },
  "min_score": 10
}
		
  1. sparse_vectorquery_string 查询都位于 bool 查询的 should 子句中。
  2. sparse_vector 查询的 boost 值为 1,这是默认值。这意味着该查询结果的相关性得分不会被提升。
  3. query_string 查询的 boost 值为 4。该查询结果的相关性得分会增加,从而使它们在搜索结果中排名更高。
  4. 仅显示得分等于或高于 10 的结果。

必须对 ELSER 生成的 Token 进行索引,以便在 sparse_vector 查询中使用。但是,没有必要在文档源中保留这些词条。你可以使用源排除映射从文档源中移除 ELSER 词条,从而节省磁盘空间。

警告

重新索引使用文档源来填充目标索引。一旦从源中排除了 ELSER 词条,就无法通过重新索引将其恢复。从源中排除 Token 是一种节省空间的优化,只有在你确信未来不需要重新索引时才应应用!仔细权衡这一利弊非常重要,要确保从源中排除 ELSER 词条符合你的具体要求和用例。请仔细阅读禁用 _source 字段_source 中包含/排除字段部分,以了解从 _source 中排除 Token 可能带来的后果。

可以通过以下 API 调用来创建从 _source 字段中排除 content_embedding 的映射

				PUT my-index
					{
  "mappings": {
    "_source": {
      "excludes": [
        "content_embedding"
      ]
    },
    "properties": {
      "content_embedding": {
        "type": "sparse_vector"
      },
      "content": {
        "type": "text"
      }
    }
  }
}
		
注意

根据你的数据,使用 track_total_hits: false 时,sparse_vector 查询可能会更快。

© . This website operates independently and is not affiliated with or endorsed by Elasticsearch B.V. All brand names, logos, and trademarks are the property of their respective owners.