Serverless Operations, inc

>_cd /blog/id_bkoep73dkw1b

title

Amazon OpenSearch Serverlessで_idが指定出来ない問題への対処方法

summary

Amazon OpenSearch Serverlessでは以下の3つのモードがありますが、それぞれでドキュメント内の_idの扱いが違います。

  • 検索コレクション(Search Collection): _id を指定してドキュメントを作成・取得することが可能です。​
  • 時系列コレクション(Time Series Collection): _id を指定してドキュメントを作成することはできません。 この制約は、時系列データの特性に合わせた設計によるものです。
  • ベクターサーチコレクション(Vector Search Collection):ベクトルによる検索性能を最適化するために特殊なインデックス構造を使っており、PUT /index/_doc/{_id} のような「ドキュメントIDを指定しての書き込み」は 許可されていません。

内部的な設計により_id指定が出来ないのはわかるのですが、どうしても扱いづらさは感じてしまいますし、ベクターサーチコレクションではドキュメントの更新や削除などが発生するケースもあるでしょう。この場合にどのようにIDを扱うべきかを本ブログではまとめています。

ベクターサーチコレクションで_idを指定してみる

以下のようなコードを書いて_idを指定してインデックスにドキュメントを投入してみましょう。

const ossClient = new Client({
  ...AwsSigv4Signer({
    region: process.env.AWS_REGION,
    service: ‘aoss’,
    getCredentials: () => {
      const credentialsProvider = defaultProvider()
      return credentialsProvider()
    },
  }),
  node: `https://${process.env.OPENSEARCHSERVERLESS_URL}.${process.env.AWS_REGION}.aoss.amazonaws.com`,
})

const indexName = ‘test-idx’
const docId = ‘example-doc-001’
const document = {
  document: {
    title: ‘タイトル‘,
    content: ‘テストテスト’
  },
}
  
// ドキュメントを登録 (put)
const putResponse = await ossClient.index({
  index: indexName,
  id: docId,
  body: document
})

console.log(‘Indexed document:’, putResponse)

すると以下のようなエラーを吐きます。Document ID is not supported と明確にエラーを吐いてくれいていますね。

{
    “errorType”: “ResponseError”,
    “errorMessage”: “illegal_argument_exception: [illegal_argument_exception] Reason: Document ID is not supported in create/index operation request”,
    “name”: “ResponseError”,
    “meta”: {
        “body”: {
            “error”: {
                “root_cause”: [
                    {
                        “type”: “illegal_argument_exception”,
                        “reason”: “Document ID is not supported in create/index operation request”
                    }
                ],
                “type”: “illegal_argument_exception”,
                “reason”: “Document ID is not supported in create/index operation request”
            },
            “status”: 400
        },
        “statusCode”: 400,
        “headers”: {
            “date”: “Mon, 14 Apr 2025 12:31:43 GMT”,
            “content-type”: “application/json; charset=UTF-8”,
            “content-length”: “261”,
            “x-envoy-upstream-service-time”: “2822”,
            “server”: “aoss-amazon-i”,
            “x-request-id”: “4453d9a2-989a-9675-9ec9-e6dc986a7605”
        },
        “meta”: {
            “context”: null,
            “request”: {
                “params”: {
                    “method”: “PUT”,
                    “path”: “/test-idx/_doc/example-doc-001”,
                    “querystring”: “”,
                    “body”: “{\“document\“:{\“title\“:\“タイトル\“,\“content\“:\“テストテスト\“}}“,
                    “headers”: {
                        “user-agent”: “opensearch-js/3.5.1 (linux 5.10.234-246.921.amzn2.x86_64-x64; Node.js v22.14.0)“,
                        “content-type”: “application/json”,
                        “content-length”: “68"
                    },
                    “timeout”: 30000
                },
                “options”: {},
                “id”: 1

今度はGETで_idを指定してデータを取得してみましょう。作成したドキュメントの返り値から_idを取得してそれをキーにGETを試みます。

const putResponse = await ossClient.index({
  index: indexName,
  body: document
})

const getResponse = await ossClient.get({
  index: indexName,
  id: putResponse.body._id
})

以下のようにIDを直接指定しても404エラーが返ってきてデータが取得できません。

{
    “errorType”: “ResponseError”,
    “errorMessage”: “Response Error”,
    “name”: “ResponseError”,
    “meta”: {
        “body”: {
            “_index”: “test-idx”,
            “_id”: “1%3A0%3AVu9ONJYB5NNi1KOe2cRi”,
            “found”: false
        },
        “statusCode”: 404,
        “headers”: {
            “date”: “Mon, 14 Apr 2025 12:38:26 GMT”,
            “content-type”: “application/json; charset=UTF-8”,
            “content-length”: “72”,
            “x-envoy-upstream-service-time”: “1070”,
            “server”: “aoss-amazon-s”,
            “x-request-id”: “05d98277-bbd6-98ae-9b66-056a05d4fb08”
        },
        “meta”: {
            “context”: null,
            “request”: {
                “params”: {
                    “method”: “GET”,
                    “path”: “/test-idx/_doc/1%253A0%253AVu9ONJYB5NNi1KOe2cRi”,
                    “querystring”: “”,
                    “body”: “”,
                    “headers”: {
                        “user-agent”: “opensearch-js/3.5.1 (linux 5.10.234-246.921.amzn2.x86_64-x64; Node.js v22.14.0)”
                    },
                    “timeout”: 30000
                },
                “options”: {},
                “id”: 2
            },

どのようにしてドキュメントデータの更新や削除を行うのか

インデックスを運用していると当然ながら元データの更新や削除が発生したタイミングでOpenSearch側のインデックスのデータも同期が取れなければなりません。_idがクライアントから指定できれば割と簡単にできるのですが、少し工夫が必要となります。検索が可能となる仮のIDのプロパティを作成して、それに対してsearchを行い、OpenSearchの内部的な_idを取得。それを元にしてデータの削除や更新が可能となります。

例えば以下のようにdocumentの中にidというプロパティを作ってしまいます。もちろん、OpenSearch Serverless側では一意性のチェックはしてくれないため、アプリケーション側で管理が必要となります。

{
  "document": {
    "id": "abc123",
    "title": "タイトル",
    "content": "テストテスト"
  }
}

そしてこのidをキーにしてデータを取得。OpenSearch Serverlessの内部的な_idを取得。特定のドキュメントのupdateが可能となります。

const response = await ossClient.search({
  index: indexName,
  body: {
    query: {
      term: {
        ‘document.id.keyword’: {
          value: ‘abc123’,
        },
      },
    },
  },
})

await ossClient.update({
  index: indexName,
  id: response.body.hits.hits[0]._id,
  body: {
    doc: {
      document:{title: ‘あああああ’}
    },
  },
})

削除についても同様です。searchクエリでマッチしたデータから内部的な_idを取得。それを元にドキュメントの削除を行います。

const response = await ossClient.search({
  index: indexName,
  body: {
    query: {
      term: {
        ‘document.id.keyword’: {
          value: ‘abc123’,
        },
      },
    },
  },
})

const deleteResponse = await ossClient.delete({
  index: indexName,
  id: response.body.hits.hits[0]._id,
})

console.log(deleteResponse)

以下の様に削除が完了しました。

body: {
  _index: ‘test-idx’,
  _id: ‘1%3A0%3AzwxhNJYBRgKqg5cIjGaP’,
  _version: 3,
  result: ‘deleted’,
  _shards: { total: 0, successful: 0, failed: 0 },
  _seq_no: 0,
  _primary_term: 0
},
statusCode: 200,

_idを用いてのPUTやGETが出来ないのはとても違和感がありますが、上記のようにすることでOpenSearch Serverless内のドキュメントの削除や更新は可能になります。

Written by
CEO

堀家 隆宏

Takahiro Horike

  • Facebook->
  • X->
  • GitHub->

Share

Facebook->X->
Back
to list
<-