亚马逊AWS官方博客

从自建 Elasticsearch 迁移到 Amazon OpenSearch Service 实践(二):向量索引迁移与 Amazon Bedrock 集成

摘要:本系列基于实际 POC 验证,完整介绍从自建 Elasticsearch 8.17 迁移到 Amazon OpenSearch Service 的实践,涵盖 Logstash 数据同步、向量索引迁移与 Amazon Bedrock Titan V2 集成、以及查询兼容性验证与 BBoss 框架应用层适配三个关键环节。作为系列开篇,本文先解决第一个挑战——数据迁移与同步;向量索引迁移与 Embedding 模型切换将在第二篇展开,查询兼容性与应用适配则在第三篇展开。


一、引言

本文是”从自建 Elasticsearch 迁移到 Amazon OpenSearch Service 实践”系列的第二篇。系列共三篇:(一)数据迁移与同步;(二)向量索引迁移与 Amazon Bedrock 集成;(三)查询兼容性验证与 BBoss 应用适配。第一篇已介绍如何将存量与增量数据迁移到 Amazon OpenSearch Service,本篇聚焦向量索引迁移的两条路线选择,并重点介绍如何在 Amazon OpenSearch Service 上集成 Amazon Bedrock Titan Text Embeddings V2。

二、背景回顾

在本系列第一篇《数据迁移与同步》中,介绍了从自建 Elasticsearch(以下简称 ES)迁移到 Amazon OpenSearch Service(以下简称 AOS)的方案选型与同步实践。对于普通索引,RFS/Logstash 即可完成数据搬运;但对于向量索引(dense_vector),迁移团队需要在一个关键问题上做出决策:是沿用原有 Embedding 模型,还是趁迁移机会更换模型?

这两种选择对应完全不同的迁移路径。本篇即围绕这两条路线展开,并以 Amazon Bedrock Titan Text Embeddings V2 为例,详细介绍路线 B 的落地方式——如何在 AOS 上集成 Bedrock 作为 Embedding Provider。

三、向量索引迁移:两条路线

向量索引的迁移取决于一个核心决策——是否更换 Embedding 模型,由此分为两条路线,如图所示:

[图1]

3.1 路线 A:保留原有 Embedding 模型,向量数据原样搬运

适用于:继续使用原有 Embedding 模型,迁移后向量搜索行为保持不变。

ES 8.x (dense_vector)  →  RFS backfill  →  AOS (knn_vector)
   向量数据原样搬运,仅 mapping 转换 + HNSW 图重建
步骤 操作
1. 在 AOS 预建向量索引 mapping 从 dense_vector 改为 knn_vector,指定引擎和 HNSW 参数
2. RFS / Logstash 搬运数据 向量数据(float 数组)原样写入,零损耗
3. 验证 k-NN 查询 改写查询语法后验证 Top-K 结果

3.1.1 为什么必须手动预建 mapping

建议在 AOS 手动预建索引,不依赖 RFS 的自动 metadata 转换。原因是 RFS 内置的转换逻辑是硬编码的,无法定制。查看 Migration Assistant 源码 es-vector-knn-metadata.js:

// 源码摘录: opensearch-migrations/.../es-vector-knn-metadata.js
const buildKnn = (def) => {
    const { dims, similarity, index_options: opts = {} } = def;
    const { m, ef_construction: efConstr } = opts;
    return {
        type: 'knn_vector',
        dimension: dims,
        method: {
            name: 'hnsw',
            engine: 'lucene',          // ← 硬编码 lucene
            space_type: mapSimilarity(similarity),
            parameters: {
                encoder: { name: "sq" }, // ← 硬编码 scalar quantization
                m: m,                    // ← ES 若未设置则为 undefined
                ef_construction: efConstr
            }
        }
    };
};

这段代码的问题:

问题 影响
引擎固定 lucene 无法选择 faiss(C++ SIMD 加速,大数据集下吞吐高 10%–50%)
编码器固定 SQ 需要最高精度时应使用 flat(无量化)
HNSW 参数来源不可靠 ES 的 dense_vector 通常不设置 index_options.m,转换后为 undefined,回退到引擎默认值

补充说明:ES 8.x 只有 Lucene 内置的 HNSW 实现,没有”选引擎”概念。迁移到 OpenSearch 时是重新选择目标引擎——lucene 行为最接近 ES 原实现(保守兼容),faiss 性能更优(生产推荐)。引擎选择只影响索引结构和搜索算法,不影响向量数据本身(float 数组通用)。

手动预建索引示例:

PUT /my-vector-index
{
  "settings": { "index.knn": true },
  "mappings": {
    "properties": {
      "content_vector": {
        "type": "knn_vector",
        "dimension": 1024,
        "method": {
          "name": "hnsw",
          "engine": "faiss",
          "space_type": "cosinesimil",
          "parameters": { "ef_construction": 128, "m": 24 }
        }
      }
    }
  }
}

预建索引后,Migration Assistant 的 metadata 阶段检测到目标索引已存在会跳过创建(官方文档:”any metadata items that do not already exist will be created on the target cluster”),RFS backfill 直接向已有索引写入文档。

3.1.2 HNSW 图会重建

即使向量数据完全相同,写入 AOS 后 HNSW 图也会重新构建——这是不可避免的:

差异来源 ES 8.x (Lucene 内置) AOS (faiss/lucene)
插入顺序 原始写入顺序 RFS 按 shard/segment 并行写入,顺序不同
邻居选择策略 Lucene diversifyNeighbors faiss: heuristic_neighbor_selection
层级分配 基于写入时随机数 基于新集群随机数
距离计算精度 Java float 运算 faiss: C++ SIMD 批量运算(浮点累加顺序略异)

实际影响:真实业务数据中 Top-5 结果几乎完全一致(分数差异 0.0–0.2%);仅当大量文档相似度极其接近时,排列可能出现微小差异(< 1%)。

3.1.3 向量索引写入压力大

与普通倒排索引不同,向量写入的额外开销:

  1. HNSW 图插入:每个向量插入需贪心搜索找最近邻 + 建立双向边,复杂度 O(ef_construction × log N)
  2. 内存占用:faiss 需加载整个图到 off-heap 内存(1024 维 × 4B × 200 万条 ≈ 8GB + 邻接表 ~400MB)
  3. merge 开销:segment merge 时 Lucene 引擎需重建合并后的图

建议:目标集群规格比普通索引场景加大 50%–100%。

3.1.4 路线 A 小结

路线 A 的核心是”数据不变,基础设施换”。适合以下场景:

  • 当前 Embedding 模型效果满意,无需更换
  • 向量数据量大,全量 re-embedding 成本高
  • 需要最快速度完成迁移,后续再考虑模型升级

3.2 路线 B:迁移时更换 Embedding 模型,全量重建向量索引

适用于:借迁移机会升级 Embedding 模型(如切换到 Amazon Bedrock Titan V2),或升级维度、更换模型厂商。

这是我们在客户迁移中最常见的选择——既然要做基础设施迁移,不如一步到位完成模型升级。迁移前后的架构对比如下:

ES + 第三方 Embedding 服务 AOS + Amazon Bedrock
写入自动 Embedding Ingest Pipeline + 第三方 Embedding API Ingest Pipeline + Bedrock API
查询自动 Embedding query_vector_builder + 第三方推理端点 Neural Search + ML Commons
模型 第三方 Embedding 模型 Titan Text Embeddings V2
配置方式 _inference API 注册模型端点 ML Commons connector 注册模型

架构模式不变(服务端自动 Embedding),只是 Provider 从第三方切换到 Amazon Bedrock。

ES (旧模型向量)     AOS (新模型向量)
     ↓                    ↑
  普通索引 ──RFS──→ 普通索引(照搬)
  向量索引 ──跳过──  向量索引(全量重建)
                          ↑
              文本字段 → Bedrock Titan V2 → 新向量
步骤 操作
1. RFS 只迁移普通索引 文本、结构化数据照搬(向量索引不搬或仅搬文本字段)
2. 在 AOS 预建新向量索引 新 mapping(维度可能不同,引擎选 faiss)
3. 批量 re-embedding 读取文本字段 → 调用新模型 → 写入新向量索引

3.2.1 为什么不能混用新旧模型的向量

不同 Embedding 模型的向量空间完全不同。即使维度相同(如都是 1024 维),同一段文本在不同模型中的向量表示也没有对应关系。混用会导致 k-NN 搜索结果不可预测——就像把中文和英文单词的 one-hot 编码混在同一个索引中做相似度搜索。

3.2.2 路线 B 的优势

对比项 路线 A(搬旧向量) 路线 B(全量重建)
模型质量 沿用旧模型 升级到更好的模型
维度灵活性 必须与原索引一致 可自由选择(768→1024)
写入压力 大量向量并行灌入 可控制 re-embedding 节奏
过渡期复杂度 低(搬完即可) 需要跑批量任务
后续维护 可能还需后续换模型 一步到位

3.2.3 路线 B 小结

路线 B 的核心是”迁移即模型升级”。具体如何接入 Bedrock Titan V2 作为新的 Embedding Provider,分为应用端调用和 Neural Search 两种方式,下一节详细介绍。

3.3 路线选择建议

场景 推荐路线
向量数据量大、模型效果好、无换模型需求 路线 A
希望升级模型 / 换厂商 / 提升向量质量 路线 B
当前使用第三方 Embedding 服务,想降成本 路线 B(切换到 Bedrock)
时间紧、先迁移再说 路线 A(后续再升级模型)

四、在 AOS 上集成 Amazon Bedrock Titan V2

无论是路线 B 的全量重建,还是路线 A 迁移后的后续模型升级,最终都需要在 AOS 上接入新的 Embedding 模型。本节以 Amazon Bedrock Titan Text Embeddings V2 为例,介绍两种集成方式,二者的数据流对比如图所示:

[图2]

4.1 方式一:应用端调用 Bedrock API

应用端掌控向量生成时机,适合批量 re-embedding 和写入:

import json, boto3
bedrock = boto3.client("bedrock-runtime", region_name="us-west-2")
MODEL_ID = "amazon.titan-embed-text-v2:0"
def bedrock_embed(text):
    response = bedrock.invoke_model(
        modelId=MODEL_ID,
        contentType="application/json",
        accept="application/json",
        body=json.dumps({
            "inputText": text[:8000],
            "dimensions": 1024,
            "normalize": True
        })
    )
    return json.loads(response["body"].read())["embedding"]

批量重建时可在应用端并行调用 Bedrock 并配合 bulk 写入,吞吐显著优于逐条经由 Ingest Pipeline。这是路线 B 全量 re-embedding 的推荐做法。

4.2 方式二:Neural Search(服务端自动 Embedding)

AOS 支持通过 ML Commons 注册 Bedrock connector,实现写入和查询时自动生成 Embedding。应用端完全不感知向量:

写入:应用 → 文本文档 → AOS Ingest Pipeline → Bedrock Titan V2 → 向量 + 文档存入索引
查询:应用 → query_text → AOS Neural Search → Bedrock Titan V2 → 向量 → k-NN 搜索 → 返回结果

Neural Search 适合增量写入和在线查询场景(不适合大批量初始化灌数据)。

以下是完整的配置步骤:

4.2.1 步骤 1:创建 IAM 角色

创建一个 IAM 角色,允许 OpenSearch 服务调用 Bedrock:

// 信任策略
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": { "Service": "es.amazonaws.com" },
    "Action": "sts:AssumeRole"
  }]
}
创建角色并附加 Bedrock 调用权限:
bash
aws iam create-role \
  --role-name opensearch-bedrock-connector-role \
  --assume-role-policy-document file://trust-policy.json \
  --description "Role for OpenSearch to invoke Bedrock Titan Embedding model"
aws iam put-role-policy \
  --role-name opensearch-bedrock-connector-role \
  --policy-name BedrockInvokeModelPolicy \
  --policy-document '{
    "Version": "2012-10-17",
    "Statement": [{
      "Effect": "Allow",
      "Action": ["bedrock:InvokeModel"],
      "Resource": "arn:aws:bedrock:us-west-2::foundation-model/amazon.titan-embed-text-v2:0"
    }]
  }'

4.2.2 步骤 2:配置 OpenSearch 安全角色映射

使用 fine-grained access control 时,需要将操作用户映射到 ml_full_accessall_access 角色。

curl -u "admin:<password>" -X PUT \
  "https://<endpoint>/_plugins/_security/api/rolesmapping/ml_full_access" \
  -H "Content-Type: application/json" \
  -d '{"users": ["admin", "arn:aws:iam::<account-id>:user/<username>"]}'
curl -u "admin:<password>" -X PUT \
  "https://<endpoint>/_plugins/_security/api/rolesmapping/all_access" \
  -H "Content-Type: application/json" \
  -d '{"users": ["admin", "arn:aws:iam::<account-id>:user/<username>"]}'

4.2.3 步骤 3:创建 ML Connector

使用 AWS SigV4 签名请求创建连接器(需要 awscurl 工具):

awscurl --service es --region us-west-2 \
  -X POST "${OPENSEARCH_ENDPOINT}/_plugins/_ml/connectors/_create" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Amazon Bedrock Titan Embedding Connector",
  "description": "Connector for Amazon Titan Text Embeddings V2 model",
  "version": 1,
  "protocol": "aws_sigv4",
  "parameters": {
    "region": "us-west-2",
    "service_name": "bedrock",
    "model": "amazon.titan-embed-text-v2:0"
  },
  "credential": {
    "roleArn": "arn:aws:iam::<account-id>:role/opensearch-bedrock-connector-role"
  },
  "actions": [{
    "action_type": "predict",
    "method": "POST",
    "url": "https://bedrock-runtime.us-west-2.amazonaws.com/model/amazon.titan-embed-text-v2:0/invoke",
    "headers": {
      "content-type": "application/json",
      "x-amz-content-sha256": "required"
    },
    "request_body": "{\"inputText\": \"${parameters.inputText}\"}",
    "pre_process_function": "\n    StringBuilder builder = new StringBuilder();\n    builder.append(\"{\\\"parameters\\\":{\\\"inputText\\\":\\\"\");\n    builder.append(params.text_docs[0]);\n    builder.append(\"\\\"}}\" );\n    def result = builder.toString();\n    return result;\n  ",
    "post_process_function": "\n    def name = \"sentence_embedding\";\n    def dataType = \"FLOAT32\";\n    if (params.embedding != null) {\n      def shape = [params.embedding.length];\n      def json = \"{\" +\n        \"\\\"name\\\":\\\"\" + name + \"\\\",\" +\n        \"\\\"data_type\\\":\\\"\" + dataType + \"\\\",\" +\n        \"\\\"shape\\\":\" + shape + \",\" +\n        \"\\\"data\\\":\" + params.embedding +\n        \"}\";\n      return json;\n    }\n    return \"{\\\"error\\\":\\\"No embedding returned\\\"}\";\n  "
  }]
}'

ℹ️ 注意:

创建 connector 等 ML 操作需要使用 AWS SigV4 签名(awscurl),不能仅用基本认证。操作用户还需要 iam:PassRole 权限。

4.2.4 步骤 4:注册并部署模型

# 注册模型
awscurl --service es --region us-west-2 \
  -X POST "${OPENSEARCH_ENDPOINT}/_plugins/_ml/models/_register" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Titan Embedding V2",
  "function_name": "remote",
  "description": "Amazon Titan Text Embeddings V2 via Bedrock",
  "connector_id": "<connector_id>"
}'
# 部署模型
awscurl --service es --region us-west-2 \
  -X POST "${OPENSEARCH_ENDPOINT}/_plugins/_ml/models/<model_id>/_deploy" \
  -H "Content-Type: application/json"

4.2.5 步骤 5:创建 Ingest Pipeline

配置写入时自动生成向量的 Pipeline:

awscurl --service es --region us-west-2 \
  -X PUT "${OPENSEARCH_ENDPOINT}/_ingest/pipeline/titan-embedding-pipeline" \
  -H "Content-Type: application/json" \
  -d '{
  "description": "Pipeline for generating Titan text embeddings",
  "processors": [{
    "text_embedding": {
      "model_id": "<model_id>",
      "field_map": { "text": "embedding" }
    }
  }]
}'

4.2.6 步骤 6:创建 k-NN 向量索引

awscurl --service es --region us-west-2 \
  -X PUT "${OPENSEARCH_ENDPOINT}/titan-embedding-index" \
  -H "Content-Type: application/json" \
  -d '{
  "settings": {
    "index": { "knn": true, "default_pipeline": "titan-embedding-pipeline" }
  },
  "mappings": {
    "properties": {
      "text": { "type": "text" },
      "embedding": {
        "type": "knn_vector",
        "dimension": 1024,
        "method": { "name": "hnsw", "space_type": "l2", "engine": "faiss" }
      }
    }
  }
}'

4.2.7 Neural Search 验证

配置完成后,插入文档时会自动生成 Embedding,查询时使用 Neural 语法:

POST titan-embedding-index/_search
{
  "query": {
    "neural": {
      "embedding": {
        "query_text": "What is a search engine service on AWS?",
        "model_id": "<model_id>",
        "k": 3
      }
    }
  },
  "_source": ["text"],
  "size": 3
}

实测语义搜索结果验证:

查询 Top1 结果 得分
“What is a search engine service on AWS?” Amazon OpenSearch is a managed search and analytics service. 0.4744
“container deployment and orchestration” Kubernetes is a container orchestration platform for deploying applications. 0.4121
“AI and large language models” Machine learning models can generate text embeddings for semantic search. 0.4561

结果表明 Titan Embedding V2 能够准确捕获语义相关性,Top1 结果均与查询意图高度匹配。

4.2.8 两种方式对比

应用端调用 Bedrock Neural Search(服务端)
适用场景 批量 re-embedding、需要精确控制吞吐 增量写入、在线查询
吞吐 高(应用端并行 + bulk) 受 Bedrock API 延迟限制(~100ms/次)
应用改动 需在写入逻辑中调用 Bedrock 应用端只传文本,无需感知向量
查询延迟 只有 k-NN 搜索延迟 Bedrock 调用 + k-NN 搜索
推荐用途 路线 B 全量重建阶段 重建完成后的日常写入和查询

实践建议:路线 B 可以两种方式结合使用——初始全量 re-embedding 用应用端并行调用(高吞吐),完成后日常增量写入切换到 Neural Search Pipeline(免运维)。

4.2.9 Neural Search 配置资源汇总

资源类型 说明
IAM 角色 opensearch-bedrock-connector-role,允许 OpenSearch 调用 Bedrock
ML Connector AWS SigV4 协议连接 Bedrock Runtime
ML Model Remote 类型,通过 Connector 调用 Titan Embedding V2
Ingest Pipeline 写入时自动调用模型生成 1024 维向量
k-NN 索引 HNSW + faiss 引擎,绑定 Pipeline

五、迁移后的向量搜索精度评估

本节仅适用于路线 A(向量数据原样搬运)。路线 B 全量重建后不存在新旧精度对比问题。

向量数据迁移到 AOS 后,由于 HNSW 图结构差异,k-NN 搜索的 Top-K 结果可能出现微小排列差异。实测情况如下:

数据规模 分数差异 Top-K 一致性
1024 维 Embedding(真实数据) 0.0–0.2% Top5 完全一致
大量随机相似向量 < 1% Top-K 排列可能不同

实践建议:

  • 使用业务真实数据评估 Top-K 对业务指标(点击率、转化率)的实际影响
  • 若需更高一致性,可增大 AOS 的 ef_search 参数以扩大搜索范围(代价是查询延迟略增)
  • k-NN 查询语法的具体改写方式,将在本系列第三篇展开

六、小结

本文围绕向量索引迁移的核心决策——是否更换 Embedding 模型——给出了两条清晰的路线:

  • 路线 A(保留原模型):向量数据原样搬运,重点在于手动预建 mapping(控制引擎和 HNSW 参数)、理解 HNSW 图重建带来的微小精度差异、以及应对向量写入的资源压力
  • 路线 B(换模型重建):迁移即模型升级,这是实际客户中最常见的选择。普通索引照搬,向量索引全量重建

对于路线 B 的落地,本文以 Amazon Bedrock Titan Text Embeddings V2 为例,详细介绍了应用端调用和 Neural Search 两种集成方式。两种方式可结合使用:全量重建阶段用应用端并行调用保障吞吐,日常增量写入切换到 Neural Search Pipeline 实现免运维。

本系列第三篇将聚焦查询兼容性验证与基于 BBoss 框架的低改动应用适配,介绍如何在不改动业务代码的前提下完成 ES 与 AOS 的查询切换。

➡️ 下一步行动:

相关产品:

相关文章:

七、相关链接

*前述特定亚马逊云科技生成式人工智能相关的服务目前在亚马逊云科技海外区域可用。亚马逊云科技中国区域相关云服务由西云数据和光环新网运营,具体信息以中国区域官网为准。

本篇作者

邢悦

亚马逊云科技迁移解决方案架构师,主要负责企业上云跨云迁移相关的技术支持工作。在制造、保险、物流等行业拥有10多年的研发和架构设计经验。

苏志勇

亚马逊云科技迁移解决方案架构师,主要负责企业上云跨云迁移相关的技术支持工作。曾担任研发工程师、解决方案架构师等职位,在 IT 专业服务和企业应用架构方面拥有多年的实践经验。

马佳

亚马逊云科技解决方案架构师,负责基于亚马逊云科技云平台解决方案的设计和咨询,亚马逊云科技人工智能机器学习领域成员。在机器学习、深度学习及自动驾驶感知领域,拥有丰富的理论及算法实践工程经验。


AWS 架构师中心:云端创新的引领者

探索 AWS 架构师中心,获取经实战验证的最佳实践与架构指南,助您高效构建安全、可靠的云上应用