作者:来自 Elastic Mike Pellegrini

Semantic 字段会在摄取阶段将图像、音频、视频、PDF 和文本转换为多模态 embedding。你可以通过描述一个场景来找到对应的图片,也可以使用视频中的一帧来检索相关的视频片段,而这一切都只需依赖 Elasticsearch 中的一个字段即可完成。
Elasticsearch 中的多模态搜索如今与文本搜索拥有相同的使用方式:定义一个字段、索引内容,然后执行查询即可。
semantic 字段会在摄取阶段自动为图像、音频、视频和 PDF 生成 embedding。
所有模态都会映射到同一个共享的向量空间,因此你可以:
-
使用文本描述检索图片;
-
使用一句话匹配相关音频;
-
使用视频中的一帧查找相关视频;
而这一切都只需依赖同一个字段即可完成。
该功能作为技术预览版(Tech Preview)在 Elasticsearch 9.5 和 Serverless 中提供。技术预览功能可能会发生变化,并且不受正式发布(GA)功能支持 SLA 的覆盖。
调色板逐渐成形:Elasticsearch 中的多模态搜索如何从 semantic_text 演进而来
semantic 字段融合了过去几年我们推出的多项互补功能,将它们整合为一致的多模态搜索体验。
这些功能各自解决了语义搜索中的一个重要问题,而结合在一起之后,便实现了原生的多模态搜索。
第一笔来自 semantic_text。在它出现之前,实现语义搜索通常需要:
-
手动配置 mapping;
-
配置带有 ML 模型的 ingest pipeline;
-
手动对内容进行 chunk;
-
自行生成查询时的 embedding。
semantic_text 字段将这些复杂工作全部封装起来:
-
在摄取阶段自动执行 inference;
-
自动对长文档进行 chunk;
-
简化针对该字段编写的查询。
semantic_text 于 Elasticsearch 8.15 首次推出,并于 Elasticsearch 8.18 正式发布,如今已经成为平台语义搜索的基础。
随后,我们推出了支撑多模态搜索的模型。
jina-embeddings-v5-omni 是一系列多模态 embedding 模型,能够将:
-
文本
-
图像
-
视频
-
音频
-
PDF
统一编码到同一个向量空间中。
由于不同模态生成的 embedding 在语义空间中彼此兼容,因此可以将各种媒体存储在同一个索引中,并跨所有内容进行统一检索。
例如:
-
使用文本描述检索图片;
-
使用书面短语匹配音频;
而无需为每一种内容类型分别维护一套独立的处理 pipeline。有关这些 embedding 如何生成的更多信息,请参阅模型文档。
随后,我们在 Elasticsearch 9.4 中引入了 embedding query vector builder,用于在查询阶段处理多模态输入。
Query vector builder 是一种通用工具,可在请求执行过程中将输入转换为向量。
例如:
-
text_embeddingquery vector builder 用于仅支持文本的模型和文本输入; -
lookupquery vector builder 用于从已有文档中获取向量。
而新的 embedding query vector builder 则专门面向多模态模型设计,可接受多模态输入,包括:
-
文本;
-
Base64 编码的二进制内容。
因此,你可以使用最适合当前场景的输入模态发起查询,而 Elasticsearch 会在查询时自动生成对应的向量。
最后补齐的一块拼图是多模态摄取。
semantic_text 将自动生成 embedding 的能力带到了文本,而 semantic 字段则将这种自动化体验扩展到了:
-
图像;
-
音频;
-
视频;
-
PDF。
从内容摄取到查询,整个过程都可以自动完成。
绘制第一幅图:使用 semantic 字段创建索引
下面创建一个包含 semantic 字段的索引。
操作非常简单,只需将字段类型设置为 semantic,并指定希望使用的 inference endpoint 即可。
bash
`
1. PUT example-index
2. {
3. "mappings": {
4. "properties": {
5. "my_semantic_field": {
6. "type": "semantic",
7. "inference_id": ".jina-embeddings-v5-omni-small"
8. }
9. }
10. }
11. }
`AI写代码
在本示例中,我们使用 .jina-embeddings-v5-omni-small inference endpoint。
这是我们内置的 jina-embeddings-v5-omni inference service,在所有能够访问 Elastic Inference Service(EIS) 的环境中均可使用,包括:
-
Serverless
-
Elastic Cloud Hosted(ECH)
-
启用了 Cloud Connected Mode(CCM) 的 self-managed 部署
semantic字段需要使用一个采用embeddingtask type 的 inference endpoint ,因为embeddingtask type 专门用于多模态模型。
semantic字段并不是用来替代semantic_text。在以下场景中,仍应继续使用
semantic_text:
字段值仅包含文本。
使用
text_embedding或sparse_embeddingtask type。关于何时应使用
semantic而不是semantic_text,请参阅相关文档。
索引图像、音频、视频和 PDF
要索引图像,只需提供一个对象,其中:
-
type设置为image -
value包含采用 Base64 编码的 Data URL 格式的图像内容。
bash
`
1. PUT example-index/_doc/example_doc_1
2. {
3. "my_semantic_field": {
4. "type": "image",
5. "value": "data:image/jpeg;base64,<base64-encoded-image-bytes>"
6. }
7. }
`AI写代码
也支持对象数组,因此可以在同一个字段值中索引多张图片。
bash
`
1. PUT example-index/_doc/example_doc_2
2. {
3. "my_semantic_field": [
4. {
5. "type": "image",
6. "value": "data:image/jpeg;base64,<base64-encoded-image-bytes>"
7. },
8. {
9. "type": "image",
10. "value": "data:image/jpeg;base64,<base64-encoded-image-bytes>"
11. }
12. ]
13. }
`AI写代码
semantic 字段也支持文本值,与 semantic_text 一样。
你既可以单独提供文本值,也可以将文本值与图片值混合存储在同一个字段中:
bash
`
1. PUT example-index/_doc/example_doc_3
2. {
3. "my_semantic_field": "a cat on a windowsill" }
5. PUT example-index/_doc/example_doc_4
6. {
7. "my_semantic_field": [
8. "a cat on a windowsill",
9. {
10. "type": "image",
11. "value": "data:image/jpeg;base64,<base64-encoded-image-bytes>"
12. },
13. "a dog running in a park"
14. ]
15. }
`AI写代码
文本值的处理方式与 semantic_text 完全一致:较长的文本会根据 inference service 或字段 mapping 中配置的 chunking 设置 自动进行 chunk。
而图像等多模态内容则不会进行 chunk。每个多模态内容都会作为一个独立的 chunk 进行表示。
semantic 字段还支持其他模态,只需将 type 的值设置为对应的内容类型即可。
目前支持的类型包括:
-
image -
audio -
video -
pdf
例如,要索引一个视频,请求如下:
bash
`
1. PUT example-index/_doc/example_doc_5
2. {
3. "my_semantic_field": {
4. "type": "video",
5. "value": "data:video/mp4;base64,<base64-encoded-video-bytes>"
6. }
7. }
`AI写代码
不同模型支持的模态类型有所不同。
jina-embeddings-v5-omni模型支持上述列出的所有模态。请查阅你所使用模型的文档,以确定该模型支持哪些模态。
使用文本查询进行图像搜索和跨模态检索
要通过文本描述查找多模态内容,可以在 semantic 字段上执行 match 查询:
bash
`
1. GET example-index/_search
2. {
3. "query": {
4. "match": {
5. "my_semantic_field": "a cat on a windowsill"
6. }
7. }
8. }
`AI写代码
与 semantic_text 一样,Elasticsearch 会自动使用该字段关联的 inference endpoint 为查询文本生成 embedding。随后,Elasticsearch 会使用该查询 embedding 返回语义上相似的匹配结果。
这种查询方式让文本到图像(text-to-image)搜索变得非常简单:
只需索引一张图片,然后使用 match 查询,就可以通过文本描述检索该图片!
它同样适用于其他模态:
-
索引多模态输入;
-
使用描述性文本进行搜索;
-
检索相关内容。
使用图像、视频和其他多模态输入进行查询
我们也可以使用多模态输入进行搜索,方法是在 knn 查询中使用 embedding query vector builder。
例如,我们可以使用一张图片进行搜索:
bash
`
1. GET example-index/_search
2. {
3. "query": {
4. "knn": {
5. "field": "my_semantic_field",
6. "query_vector_builder": {
7. "embedding": {
8. "input": {
9. "type": "image",
10. "value": "data:image/jpeg;base64,<base64-encoded-image-bytes>"
11. }
12. }
13. }
14. }
15. }
16. }
`AI写代码
input 对象的格式与索引图像时提供的格式相同:
-
将
type设置为image; -
将
value设置为 Base64 编码的 data URL。
与使用文本描述进行查询类似,Elasticsearch 会自动使用该字段关联的 inference endpoint 为查询图像生成 embedding。
随后,Elasticsearch 会使用该查询 embedding 返回语义上相似的匹配结果。
与索引时一样,其他模态也受到支持,但仅限于你的 inference endpoint 所支持的模态类型。
例如,使用视频片段进行搜索时,请求如下:
bash
`
1. GET example-index/_search
2. {
3. "query": {
4. "knn": {
5. "field": "my_semantic_field",
6. "query_vector_builder": {
7. "embedding": {
8. "input": {
9. "type": "video",
10. "value": "data:video/mp4;base64,<base64-encoded-video-bytes>"
11. }
12. }
13. }
14. }
15. }
16. }
`AI写代码
扩展组合能力:高亮、retrievers 以及其他 semantic 字段功能
semantic 字段并不是从零开始构建的。它建立在与 semantic_text 相同的基础之上,继承了 semantic_text 的行为方式和易用性,并将这些能力扩展到了多模态内容。
实际上,这意味着你之前使用 semantic_text 时掌握的大部分内容都可以直接迁移过来。
如果你之前已经使用过 semantic_text,那么 semantic 字段会让你感到非常熟悉。
下面列出了一些可以直接使用的功能。完整列表请参阅相关文档。
高亮最佳匹配的 chunk
如果你在 semantic 字段中索引了多个值,可能希望知道:
哪个值与查询的匹配程度最高?
semantic highlighter 可以用于返回最相关的 chunk 作为高亮片段:
bash
`
1. GET example-index/_search
2. {
3. "query": {
4. "match": {
5. "my_semantic_field": "a cat on a windowsill"
6. }
7. },
8. "highlight": {
9. "fields": {
10. "my_semantic_field": {
11. "number_of_fragments": 2,
12. "order": "score"
13. }
14. }
15. }
16. }
`AI写代码
将 order 设置为 score 会按照相关性对返回的 fragments 进行排序,而 number_of_fragments 用于限制返回的 chunk 数量。
响应如下:
bash
`
1. {
2. "hits": {
3. "hits": [
4. {
5. "_index": "example-index",
6. "_id": "example_doc_4",
7. "_source": {...},
8. "highlight": {
9. "my_semantic_field": [
10. "a cat on a windowsill",
11. "data:image/jpeg;base64,<base64-encoded-image-bytes>"
12. ]
13. }
14. }
15. ]
16. }
17. }
`AI写代码
注意,经过高亮的多模态值会使用其 data URL 形式进行表示。
使用 index options 控制向量量化
semantic 字段会将其 embedding 存储在底层的 vector 字段中,而 index_options 可以用于控制该向量字段的索引方式。
例如,可以选择非默认的量化策略:
markdown
`
1. PUT example-index
2. {
3. "mappings": {
4. "properties": {
5. "my_semantic_field": {
6. "type": "semantic",
7. "inference_id": ".jina-embeddings-v5-omni-small",
8. "index_options": {
9. "dense_vector": {
10. "type": "int8_hnsw"
11. }
12. }
13. }
14. }
15. }
16. }
`AI写代码
Multi-field retrievers
semantic 字段支持 linear 和 rrf retrievers 所支持的 multi-field query format。
你无需为每个字段手动编写一个 inner retriever,只需提供一个统一的 query 以及一个 fields 列表即可,同时可以自由混合 lexical 字段和 semantic 字段:
bash
`
1. GET example-index/_search
2. {
3. "retriever": {
4. "linear": {
5. "query": "a cat on a windowsill",
6. "fields": ["title", "my_semantic_field"],
7. "normalizer": "minmax"
8. }
9. }
10. }
`AI写代码
该 retriever 会自动区分 lexical 字段和 semantic 字段,分别对每一组字段执行查询,并对结果进行归一化处理,使每一组字段对最终排序产生相同的贡献,从而避免 lexical 匹配结果压制 semantic 匹配结果。
Cross-cluster search
semantic 字段支持 cross-cluster search(CCS),因此可以在大型多集群部署中使用该字段。
只需使用标准的 <cluster>:<index> 格式列出要查询的索引即可:
bash
`
1. GET example-index,remote-cluster:remote-index/_search
2. {
3. "query": {
4. "match": {
5. "my_semantic_field": "a cat on a windowsill"
6. }
7. }
8. }
`AI写代码
跨索引和跨集群查询的字段可以混合使用不同的 inference endpoint,而这些 endpoint 可能会生成不同的 query embedding。
搜索请求会自动为每个被查询的字段应用正确的 query embedding。
从画布走向生产:优化用于生产环境的多模态 embedding
当你将多模态搜索从实验阶段投入生产时,多模态输入的大小会成为一个实际问题。
多模态数据通过 Base64 编码的 data URL 提供,并且这些数据会存储在索引中。这些字符串的大小可能会快速增长:
一个高分辨率文件可能膨胀到数 MB 的编码文本,从而带来以下影响:
-
磁盘上的索引大小会显著增加;
-
包含多模态数据的请求和响应会变大,增加传输时间以及 ingress/egress 成本;
-
更大的多模态输入会导致 inference 速度变慢。
好消息是,你并不需要保留这么高的保真度。
多模态 embedding 模型本身会在生成向量之前,将每个输入压缩为紧凑的表示。因此,一个更小、保真度更低的多模态输入(例如缩小尺寸后的图片或更低码率的音频片段),通常可以生成与原始完整输入非常相似的 embedding,并保持相近的搜索质量。
这同样适用于 PDF 输入。
PDF 通常会被多模态模型以视觉方式处理,因此只需要达到足够支持以下操作的质量即可:
-
图像 embedding;
-
OCR。
较长的 PDF 应该拆分为更小的输入 chunk,这样生成的 embedding 才能更准确地表示每个 chunk。
向模型提供较小的输入可以:
-
保持文档更加精简;
-
减少索引大小和响应大小;
-
加快 ingest 速度;
同时不会明显影响相关性。
Elasticsearch 通过一个保护机制进一步强化了这种最佳实践:
indices.inference.max_binary_input_size 集群设置限制每个 binary input 的大小,默认值为 1 MB。
任何超过该限制的单个值都会被拒绝,并返回明确错误。因此,过大的输入会在索引阶段直接暴露为可处理的问题,而不是悄悄导致索引膨胀。
在 self-hosted 和 ECH 环境中,可以通过 cluster settings API 调整该设置。
在 Serverless 环境中,该设置不可调整,1 MB 是 binary size 的固定上限。
在可能的情况下,也建议使用 source filtering ,将 semantic 字段从响应中排除。
例如:
bash
`
1. GET example-index/_search
2. {
3. "_source": {
4. "excludes": ["my_semantic_field"]
5. },
6. "query": {
7. "match": {
8. "my_semantic_field": "a cat on a windowsill"
9. }
10. }
11. }
`AI写代码
这样可以让响应更加小巧、性能更高,并且更容易解析,因为多模态数据不会随着每次响应一起返回。
试用 semantic 字段
semantic 字段已在 Elasticsearch 9.5 和 Serverless 中提供。
开始免费试用,并立即体验。
原文:Semantic field: one field for multimodal search in Elasticsearch | Elasticsearch Labs