正在加载

使用 ELSER 进行语义搜索

Elastic Stack Serverless

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

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

重要事项

要以最简单的方式在 Elastic Stack 中执行语义搜索,请参阅semantic_text端到端教程。

注意

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

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

注意

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

首先,必须创建目标索引(包含模型基于您的文本创建的令牌的索引)的映射。 目标索引必须具有带有 sparse_vectorrank_features 字段类型的字段,以索引 ELSER 输出。

注意

ELSER 输出必须提取到具有 sparse_vectorrank_features 字段类型的字段中。 否则,Elasticsearch 会将令牌权重对解释为文档中的大量字段。 如果您收到类似于此的错误:"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. 包含生成的令牌的字段的名称。 必须在下一步的推理管道配置中引用它。
  2. 包含令牌的字段是一个 sparse_vector 字段。
  3. 从中创建稀疏向量表示的字段的名称。 在此示例中,字段的名称为 content。 必须在下一步的推理管道配置中引用它。
  4. 此示例中的字段类型为文本。

要了解如何优化空间,请参阅具有 推理处理器通过从文档源中排除 ELSER 令牌来节省磁盘空间,以使用 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

在此步骤中,您加载稍后在推理提取管道中使用的数据,以从中提取令牌。

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

重要事项

msmarco-passagetest2019-top1000 数据集未用于训练模型。 我们在本教程中使用此示例数据集,因为它易于访问以进行演示。 您可以使用不同的数据集来测试工作流程并熟悉它。

下载该文件并使用 UI 中的文件上传器将其上传到您的集群。 分析完数据后,单击覆盖设置。 在编辑字段名称下,将 id 分配给第一列,将 content 分配给第二列。 单击应用,然后单击导入。 将索引命名为 test-data,然后单击导入。 上传完成后,您将看到一个名为 test-data 的索引,其中包含 182,469 个文档。

通过使用 ELSER 作为推理模型的推理管道重新索引数据,从文本创建令牌。

 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 query,并提供与您的 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 个文档,按其相关性排序。 结果还包含每个相关搜索结果的提取令牌及其权重。 令牌是捕获相关性的学习关联,它们不是同义词。 要了解有关令牌的更多信息,请参阅此页面。 可以从源中排除令牌,请参阅 本节了解更多信息。

"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 中使用过滤器子句,或使用与 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 生成的令牌才能在 sparse_vector 查询中使用。 但是,没有必要在文档源中保留这些术语。 您可以使用 source exclude 映射从文档源中删除 ELSER 术语,从而节省磁盘空间。

警告

重新索引使用文档源来填充目标索引。一旦 ELSER 词条从源中排除,就无法通过重新索引恢复。 从源中排除这些令牌是一种节省空间的优化,只有在您确定将来不需要重新索引时才应应用! 仔细考虑这种权衡非常重要,并确保从源中排除 ELSER 词条符合您的特定需求和用例。 请仔细查看禁用 _source 字段_source 中包含/排除字段部分,以了解更多有关从 _source 中排除令牌可能造成的后果。

可以通过以下 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 查询可能会更快。

© . All rights reserved.