Azure Cosmos DB Java SDK v4 を使用するようにアプリケーションを移行する

適用対象: NoSQL

重要

この SDK の詳細については、Azure Cosmos DB Java SDK v4 のリリース ノートMaven リポジトリ、Azure Cosmos DB Java SDK v4 のパフォーマンスに関するヒント、Azure Cosmos DB Java SDK v4 のトラブルシューティング ガイドを参照してください。

重要

Azure Cosmos DB Java SDK v4 では、スループットが最大 20% 向上し、TCP を利用したダイレクト モードが用意され、最新のバックエンド サービス機能があるので、機会があり次第 v4 にアップグレードすることをお勧めします。 詳しくは、この記事を読み進めてください。

最新の Azure Cosmos DB Java SDK に更新して、Azure Cosmos DB が提供する最善のもの、つまり、競争力のあるパフォーマンス、ファイブ ナイン (99.999%) の可用性、比類のないリソース ガバナンスなどを備えたマネージド非リレーショナル データベースを手に入れます。 この記事では、古い Azure Cosmos DB Java SDK を使用している既存の Java アプリケーションを、NoSQL 用 API 用の新しい Azure Cosmos DB Java SDK 4.0 にアップグレードする方法について説明します。 Azure Cosmos DB Java SDK v4 は、com.azure.cosmos パッケージに対応しています。 次のいずれかの Azure Cosmos DB Java SDK からアプリケーションを移行する場合、このドキュメントに記載されている手順を使用できます。

  • Sync Java SDK 2.x.x
  • Async Java SDK 2.x.x
  • Java SDK 3.x.x

Azure Cosmos DB Java SDK とパッケージのマッピング

次の表では、さまざまな Azure Cosmos DB Java SDK、パッケージ名、リリース情報を示します。

Java SDK リリース日 バンドルされた API Maven Jar Java パッケージ名 API リファレンス リリース ノート 廃止日
Async 2.x.x 2018 年 6 月 Async(RxJava) com.microsoft.azure::azure-cosmosdb com.microsoft.azure.cosmosdb.rx API リリース ノート 2024 年 8 月 31 日
Sync 2.x.x 2018 年 9 月 同期 com.microsoft.azure::azure-documentdb com.microsoft.azure.cosmosdb API 2024 年 2 月 29 日
3.x.x 2019 年 7 月 Async(Reactor)/Sync com.microsoft.azure::azure-cosmos com.azure.data.cosmos API - 2024 年 8 月 31 日
4.0 2020 年 6 月 Async(Reactor)/Sync com.azure::azure-cosmos com.azure.cosmos API - -

SDK レベルの実装の変更

さまざまな SDK 間での主な実装の相違点を次に示します。

RxJava が Azure Cosmos DB Java SDK バージョン 3.x.x および 4.0 ではリアクターに置き換えられている

非同期プログラミングまたはリアクティブ プログラミングに慣れていない場合、非同期プログラミングとプロジェクト リアクターの概要については、「リアクター パターン ガイド」を参照してください。 このガイドは、以前に Azure Cosmos DB Sync Java SDK 2.x.x または Azure Cosmos DB Java SDK 3.x.x Sync API を使用している場合に役立つことがあります。

Azure Cosmos DB Async Java SDK 2.x.x を使用していて、4.0 SDK への移行を計画している場合、リアクターを使用するように RxJava のコードを変換するガイダンスについては、「リアクターと RxJava の比較ガイド」を参照してください。

Azure Cosmos DB Java SDK v4 は、Async API と Sync API の両方に対する直接接続モードを備えている

Azure Cosmos DB Sync Java SDK 2.x.x を使用している場合、Azure Cosmos DB Java SDK 4.0 では、Async API と Sync API の両方について、(HTTP ではなく) TCP に基づく直接接続モードが実装されていることに注意してください。

API レベルの変更

以前の SDK (Java SDK 3.x.x、Async Java SDK 2.x.x、Sync Java SDK 2.x.x) と比較した Azure Cosmos DB Java SDK 4.x.x での API レベルの変更点を次に示します。

Azure Cosmos DB Java SDK naming conventions

  • Azure Cosmos DB Java SDK 3.x.x と 4.0 では、クライアント リソースが Cosmos<resourceName> として参照されています。 たとえば、CosmosClientCosmosDatabaseCosmosContainer などです。 一方、バージョン 2.x.x の Azure Cosmos DB Java SDK には、一貫した名前付けスキームはありません。

  • Azure Cosmos DB Java SDK 3.x.x と 4.0 では、Sync API と Async API の両方が提供されています。

    • Java SDK 4.0: クラス名で Cosmos の後に Async が追加されていない限り、すべてのクラスは Sync API に属します。

    • Java SDK 3.x.x: クラス名で Cosmos の後に Async が追加されていない限り、すべてのクラスは Async API に属します。

    • Async Java SDK 2.x.x: クラス名は Sync Java SDK 2.x.x に似ていますが、名前は Async で始まります。

階層型の API 構造

次の 4.0 SDK コード スニペットで示すように、Azure Cosmos DB Java SDK 4.0 と 3.x.x では、クライアント、データベース、コンテナーが入れ子として編成された階層型 API 構造が導入されています。

CosmosContainer container = client.getDatabase("MyDatabaseName").getContainer("MyContainerName");

Azure Cosmos DB Java SDK のバージョン 2.x では、リソースとドキュメントに対するすべての操作は、クライアント インスタンスを介して実行されます。

ドキュメントの表現

Azure Cosmos DB Java SDK 4.0 では、カスタム POJO と JsonNodes が、Azure Cosmos DB のドキュメントを読み書きするための 2 つのオプションです。

Azure Cosmos DB Java SDK 3.x.x では、CosmosItemProperties オブジェクトがパブリック API によって公開され、ドキュメント表現として提供されます。 このクラスは、バージョン 4.0 では公開されなくなりました。

インポートする

  • Azure Cosmos DB Java SDK 4.0 のパッケージは、com.azure.cosmos で始まります

  • Azure Cosmos DB Java SDK 3.x.x のパッケージは、com.azure.data.cosmos で始まります

  • Azure Cosmos DB Java SDK 2.x.x Sync API のパッケージは、com.microsoft.azure.documentdb で始まります

  • Azure Cosmos DB Java SDK 4.0 では、入れ子になったパッケージ com.azure.cosmos.models に複数のクラスが配置されます。 これらのパッケージには次のものがあります。

    • CosmosContainerResponse
    • CosmosDatabaseResponse
    • CosmosItemResponse
    • 上記のすべてのパッケージに相当する Async API
    • CosmosContainerProperties
    • FeedOptions
    • PartitionKey
    • IndexingPolicy
    • IndexingMode など

アクセサー

Azure Cosmos DB Java SDK 4.0 では、インスタンス メンバーにアクセスするための get メソッドと set メソッドが公開されています。 たとえば、CosmosContainer インスタンスには、container.getId() メソッドと container.setId() メソッドがあります。

これは、fluent インターフェイスを公開する Azure Cosmos DB Java SDK 3.x.x とは異なります。 たとえば、CosmosSyncContainer インスタンスの container.id() は、id の値を取得または設定するためにオーバーロードされます。

コード スニペットの比較

リソースを作成する

次のコード スニペットは、4.0、3.x.x Async、2.x.x Sync、および 2.x.x Async API 間のリソース作成方法の違いを示しています。


// Create Async client.
// Building an async client is still a sync operation.
CosmosAsyncClient client = new CosmosClientBuilder()
        .endpoint("your.hostname")
        .key("yourmasterkey")
        .consistencyLevel(ConsistencyLevel.EVENTUAL)
        .buildAsyncClient();

// Create database with specified name
client.createDatabaseIfNotExists("YourDatabaseName")
        .flatMap(databaseResponse -> {
            testDatabaseAsync = client.getDatabase("YourDatabaseName");
            // Container properties - name and partition key
            CosmosContainerProperties containerProperties =
                    new CosmosContainerProperties("YourContainerName", "/id");

            // Provision manual throughput
            ThroughputProperties throughputProperties = ThroughputProperties.createManualThroughput(400);

            // Create container
            return database.createContainerIfNotExists(containerProperties, throughputProperties);
        }).flatMap(containerResponse -> {
    testContainerAsync = database.getContainer("YourContainerName");
    return Mono.empty();
}).subscribe();

項目の操作

次のコード スニペットは、4.0、3.x.x Async、2.x.x Sync、および 2.x.x Async API 間の項目操作の実行方法の違いを示しています。


// Container is created. Generate many docs to insert.
int number_of_docs = 50000;
ArrayList<JsonNode> docs = generateManyDocs(number_of_docs);

// Insert many docs into container...
Flux.fromIterable(docs)
        .flatMap(doc -> testContainerAsync.createItem(doc))
        .subscribe(); // ...Subscribing triggers stream execution.

インデックス作成

次のコード スニペットは、4.0、3.x.x Async、2.x.x Sync、および 2.x.x Async API 間のインデックス作成方法の違いを示しています。


CosmosContainerProperties containerProperties = new CosmosContainerProperties(containerName, "/lastName");

// Custom indexing policy
IndexingPolicy indexingPolicy = new IndexingPolicy();
indexingPolicy.setIndexingMode(IndexingMode.CONSISTENT);

// Included paths
List<IncludedPath> includedPaths = new ArrayList<>();
includedPaths.add(new IncludedPath("/*"));
indexingPolicy.setIncludedPaths(includedPaths);

// Excluded paths
List<ExcludedPath> excludedPaths = new ArrayList<>();
excludedPaths.add(new ExcludedPath("/name/*"));
indexingPolicy.setExcludedPaths(excludedPaths);

containerProperties.setIndexingPolicy(indexingPolicy);

ThroughputProperties throughputProperties = ThroughputProperties.createManualThroughput(400);

database.createContainerIfNotExists(containerProperties, throughputProperties);
CosmosAsyncContainer containerIfNotExists = database.getContainer(containerName);

ストアド プロシージャ

次のコード スニペットは、4.0、3.x.x Async、2.x.x Sync、および 2.x.x Async API 間のストアド プロシージャの作成方法の違いを示しています。


logger.info("Creating stored procedure...\n");

String sprocId = "createMyDocument";

String sprocBody = "function createMyDocument() {\n" +
        "var documentToCreate = {\"id\":\"test_doc\"}\n" +
        "var context = getContext();\n" +
        "var collection = context.getCollection();\n" +
        "var accepted = collection.createDocument(collection.getSelfLink(), documentToCreate,\n" +
        "    function (err, documentCreated) {\n" +
        "if (err) throw new Error('Error' + err.message);\n" +
        "context.getResponse().setBody(documentCreated.id)\n" +
        "});\n" +
        "if (!accepted) return;\n" +
        "}";

CosmosStoredProcedureProperties storedProcedureDef = new CosmosStoredProcedureProperties(sprocId, sprocBody);
container.getScripts()
        .createStoredProcedure(storedProcedureDef,
                new CosmosStoredProcedureRequestOptions()).block();

// ...

logger.info(String.format("Executing stored procedure %s...\n\n", sprocId));

CosmosStoredProcedureRequestOptions options = new CosmosStoredProcedureRequestOptions();
options.setPartitionKey(new PartitionKey("test_doc"));

container.getScripts()
        .getStoredProcedure(sprocId)
        .execute(null, options)
        .flatMap(executeResponse -> {
            logger.info(String.format("Stored procedure %s returned %s (HTTP %d), at cost %.3f RU.\n",
                    sprocId,
                    executeResponse.getResponseAsString(),
                    executeResponse.getStatusCode(),
                    executeResponse.getRequestCharge()));
            return Mono.empty();
        }).block();

Change Feed

次のコード スニペットでは、4.0 と 3.x.x の Async API での変更フィード操作の実行方法の違いを示します。


ChangeFeedProcessor changeFeedProcessorInstance =
        new ChangeFeedProcessorBuilder()
                .hostName(hostName)
                .feedContainer(feedContainer)
                .leaseContainer(leaseContainer)
                .handleChanges((List<JsonNode> docs) -> {
                    logger.info("--->setHandleChanges() START");

                    for (JsonNode document : docs) {
                        try {
                            //Change Feed hands the document to you in the form of a JsonNode
                            //As a developer you have two options for handling the JsonNode document provided to you by Change Feed
                            //One option is to operate on the document in the form of a JsonNode, as shown below. This is great
                            //especially if you do not have a single uniform data model for all documents.
                            logger.info("---->DOCUMENT RECEIVED: " + OBJECT_MAPPER.writerWithDefaultPrettyPrinter()
                                    .writeValueAsString(document));

                            //You can also transform the JsonNode to a POJO having the same structure as the JsonNode,
                            //as shown below. Then you can operate on the POJO.
                            CustomPOJO pojo_doc = OBJECT_MAPPER.treeToValue(document, CustomPOJO.class);
                            logger.info("----=>id: " + pojo_doc.getId());

                        } catch (JsonProcessingException e) {
                            e.printStackTrace();
                        }
                    }
                    logger.info("--->handleChanges() END");

                })
                .buildChangeFeedProcessor();

// ...

changeFeedProcessorInstance.start()
        .subscribeOn(Schedulers.elastic())
        .subscribe();

コンテナー レベルの Time-To-Live (TTL)

次のコード スニペットは、4.0、3.x.x Async、2.x.x Sync、および 2.x.x Async API 間の、コンテナー内のデータに対する Time-To-Live の作成方法の違いを示しています。


CosmosAsyncContainer container;

// Create a new container with TTL enabled with default expiration value
CosmosContainerProperties containerProperties = new CosmosContainerProperties("myContainer", "/myPartitionKey");
containerProperties.setDefaultTimeToLiveInSeconds(90 * 60 * 60 * 24);
ThroughputProperties throughputProperties = ThroughputProperties.createManualThroughput(400);
database.createContainerIfNotExists(containerProperties, throughputProperties).block();
container = database.getContainer("myContainer");

項目レベルの Time-To-Live (TTL)

次のコード スニペットは、4.0、3.x.x Async、2.x.x Sync、および 2.x.x Async API 間の項目に対する Time-To-Live の作成方法の違いを示しています。


// Include a property that serializes to "ttl" in JSON
class SalesOrder
{
    private String id;
    private String customerId;
    private Integer ttl;

    public SalesOrder(String id, String customerId, Integer ttl) {
        this.id = id;
        this.customerId = customerId;
        this.ttl = ttl;
    }

    public String getId() {return this.id;}
    public void setId(String new_id) {this.id = new_id;}
    public String getCustomerId() {return this.customerId;}
    public void setCustomerId(String new_cid) {this.customerId = new_cid;}
    public Integer getTtl() {return this.ttl;}
    public void setTtl(Integer new_ttl) {this.ttl = new_ttl;}

    //...
}


// Set the value to the expiration in seconds
SalesOrder salesOrder = new SalesOrder(
        "SO05",
        "CO18009186470",
        60 * 60 * 24 * 30  // Expire sales orders in 30 days
);

次のステップ