教程:使用 ELSER 进行语义搜索
编辑教程:使用 ELSER 进行语义搜索编辑
Elastic Learned Sparse EncodeR - 或 ELSER - 是由 Elastic 训练的 NLP 模型,它允许您通过使用稀疏向量表示来执行语义搜索。语义搜索不是对搜索词进行字面匹配,而是根据搜索查询的意图和上下文含义检索结果。
本教程中的说明将向您展示如何使用 ELSER 对您的数据执行语义搜索。
使用 ELSER 进行语义搜索时,每个字段仅考虑前 512 个提取的标记。有关更多信息,请参阅 此页面。
要求编辑
要使用 ELSER 执行语义搜索,您必须在集群中部署 NLP 模型。请参阅 ELSER 文档 了解如何下载和部署模型。
如果 部署自动扩展 已关闭,则在 Elasticsearch Service 中部署和使用 ELSER 模型的最小专用 ML 节点大小为 4 GB。建议打开自动扩展,因为它允许您的部署根据需求动态调整资源。通过使用更多分配或每个分配更多线程可以实现更好的性能,这需要更大的 ML 节点。自动扩展在需要时提供更大的节点。如果自动扩展已关闭,您必须自己提供大小合适的节点。
创建索引映射编辑
首先,必须创建目标索引的映射 - 包含模型根据您的文本创建的标记的索引。目标索引必须具有一个使用 sparse_vector
或 rank_features
字段类型来索引 ELSER 输出的字段。
ELSER 输出必须被摄取到具有 sparse_vector
或 rank_features
字段类型的字段中。否则,Elasticsearch 会将标记-权重对解释为文档中的大量字段。如果您遇到类似于此 "Limit of total fields [1000] has been exceeded while adding new fields"
的错误,则 ELSER 输出字段映射不正确,并且其字段类型不同于 sparse_vector
或 rank_features
。
response = client.indices.create( index: 'my-index', body: { mappings: { properties: { content_embedding: { type: 'sparse_vector' }, content: { type: 'text' } } } } ) puts response
PUT my-index { "mappings": { "properties": { "content_embedding": { "type": "sparse_vector" }, "content": { "type": "text" } } } }
包含生成的标记的字段的名称。它必须在下一步的推理管道配置中引用。 |
|
包含标记的字段是一个 |
|
用于创建稀疏向量表示的字段的名称。在本例中,字段的名称为 |
|
在本例中为文本的字段类型。 |
要了解如何优化空间,请参阅 通过从文档源中排除 ELSER 标记来节省磁盘空间 部分。
使用推理处理器创建摄取管道编辑
使用 推理处理器 创建一个 摄取管道,以使用 ELSER 对在管道中被摄取的数据进行推理。
response = client.ingest.put_pipeline( id: 'elser-v2-test', body: { processors: [ { inference: { model_id: '.elser_model_2', input_output: [ { input_field: 'content', output_field: 'content_embedding' } ] } } ] } ) puts response
PUT _ingest/pipeline/elser-v2-test { "processors": [ { "inference": { "model_id": ".elser_model_2", "input_output": [ { "input_field": "content", "output_field": "content_embedding" } ] } } ] }
加载数据编辑
在此步骤中,您将加载稍后在推理摄取管道中使用的数据,以从中提取标记。
使用 msmarco-passagetest2019-top1000
数据集,它是 MS MARCO Passage Ranking 数据集的子集。它包含 200 个查询,每个查询都附带一个相关文本段落的列表。所有唯一的段落及其 ID 已从该数据集中提取并编译到一个 tsv 文件 中。
重要:msmarco-passagetest2019-top1000
数据集未用于训练模型。它仅在本教程中用作易于访问的示例数据集,用于演示目的。您可以使用不同的数据集来测试工作流程并熟悉它。
下载文件并使用机器学习 UI 中的 数据可视化器 将其上传到您的集群。将名称 id
分配给第一列,将 content
分配给第二列。索引名称为 test-data
。上传完成后,您将看到一个名为 test-data
的索引,其中包含 182469 个文档。
通过推理摄取管道摄取数据编辑
通过使用 ELSER 作为推理模型的推理管道重新索引数据,从文本中创建标记。
response = client.reindex( wait_for_completion: false, body: { source: { index: 'test-data', size: 50 }, dest: { index: 'my-index', pipeline: 'elser-v2-test' } } ) puts response
POST _reindex?wait_for_completion=false { "source": { "index": "test-data", "size": 50 }, "dest": { "index": "my-index", "pipeline": "elser-v2-test" } }
该调用返回一个任务 ID 以监控进度
GET _tasks/<task_id>
您也可以打开“已训练模型”UI,选择 ELSER 下的“管道”选项卡以跟踪进度。
使用 text_expansion
查询进行语义搜索编辑
要执行语义搜索,请使用 text_expansion
查询,并提供查询文本和 ELSER 模型 ID。以下示例使用查询文本“如何避免跑步后的肌肉酸痛?”,content_embedding
字段包含生成的 ELSER 输出
response = client.search( index: 'my-index', body: { query: { text_expansion: { content_embedding: { model_id: '.elser_model_2', model_text: 'How to avoid muscle soreness after running?' } } } } ) puts response
GET my-index/_search { "query":{ "text_expansion":{ "content_embedding":{ "model_id":".elser_model_2", "model_text":"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." } }, (...) ] }
将语义搜索与其他查询结合使用编辑
您可以在 复合查询 中将 text_expansion
与其他查询结合使用。例如,在 布尔 中使用过滤子句,或使用与 text_expansion
查询相同(或不同)的查询文本进行全文查询。这使您能够将来自两个查询的搜索结果结合起来。
来自 text_expansion
查询的搜索命中率往往比其他 Elasticsearch 查询得分更高。可以通过使用 boost
参数增加或减少每个查询的相关性得分来规范这些得分。在存在大量不太相关的结果的尾部时,text_expansion
查询的召回率可能很高。使用 min_score
参数来修剪这些不太相关的文档。
response = client.search( index: 'my-index', body: { query: { bool: { should: [ { text_expansion: { content_embedding: { model_text: 'How to avoid muscle soreness after running?', model_id: '.elser_model_2', boost: 1 } } }, { query_string: { query: 'toxins', boost: 4 } } ] } }, min_score: 10 } ) puts response
GET my-index/_search { "query": { "bool": { "should": [ { "text_expansion": { "content_embedding": { "model_text": "How to avoid muscle soreness after running?", "model_id": ".elser_model_2", "boost": 1 } } }, { "query_string": { "query": "toxins", "boost": 4 } } ] } }, "min_score": 10 }
|
|
|
|
|
|
仅显示得分等于或高于 |
优化性能编辑
通过从文档源中排除 ELSER 标记来节省磁盘空间编辑
由 ELSER 生成的标记必须被索引才能在 text_expansion 查询 中使用。但是,没有必要将这些术语保留在文档源中。您可以使用 源排除 映射来从文档源中删除 ELSER 术语,从而节省磁盘空间。
重新索引使用文档源来填充目标索引。 一旦 ELSER 术语从源中排除,它们就无法 通过重新索引恢复。 从源中排除标记是一种节省空间的优化,只有在您确定将来不需要重新索引时才应应用! 重要的是要仔细考虑这种权衡,并确保从源中排除 ELSER 术语符合您的特定需求和用例。 查看 禁用 _source
字段 和 从 _source
中包含/排除字段 部分,以详细了解从 _source
中排除标记的可能后果。
可以通过以下 API 调用创建将 content_embedding
从 _source
字段中排除的映射
response = client.indices.create( index: 'my-index', body: { mappings: { _source: { excludes: [ 'content_embedding' ] }, properties: { content_embedding: { type: 'sparse_vector' }, content: { type: 'text' } } } } ) puts response
PUT my-index { "mappings": { "_source": { "excludes": [ "content_embedding" ] }, "properties": { "content_embedding": { "type": "sparse_vector" }, "content": { "type": "text" } } } }
根据您的数据,文本扩展查询在 track_total_hits: false
时可能更快。
进一步阅读编辑
交互式示例编辑
elasticsearch-labs
存储库有一个使用 Elasticsearch Python 客户端运行 ELSER 驱动的语义搜索 的交互式示例。