From a67f824d7af2dcaf131c3e9ebf5b349948d62adc Mon Sep 17 00:00:00 2001 From: Andrew Feldman Date: Fri, 1 May 2020 07:29:58 -0700 Subject: [PATCH 1/2] Created skeleton of sync TTL sample; removed regions --- .../ttl/sync/SampleTTLQuickstart.java | 235 ++++++++++++++++++ 1 file changed, 235 insertions(+) create mode 100644 src/main/java/com/azure/cosmos/examples/ttl/sync/SampleTTLQuickstart.java diff --git a/src/main/java/com/azure/cosmos/examples/ttl/sync/SampleTTLQuickstart.java b/src/main/java/com/azure/cosmos/examples/ttl/sync/SampleTTLQuickstart.java new file mode 100644 index 0000000..59dd34b --- /dev/null +++ b/src/main/java/com/azure/cosmos/examples/ttl/sync/SampleTTLQuickstart.java @@ -0,0 +1,235 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.cosmos.examples.ttl.sync; + +import com.azure.cosmos.ConnectionPolicy; +import com.azure.cosmos.ConsistencyLevel; +import com.azure.cosmos.CosmosClient; +import com.azure.cosmos.CosmosClientBuilder; +import com.azure.cosmos.CosmosClientException; +import com.azure.cosmos.CosmosContainer; +import com.azure.cosmos.CosmosDatabase; +import com.azure.cosmos.CosmosPagedIterable; +import com.azure.cosmos.examples.changefeed.SampleChangeFeedProcessor; +import com.azure.cosmos.examples.common.AccountSettings; +import com.azure.cosmos.examples.common.Families; +import com.azure.cosmos.examples.common.Family; +import com.azure.cosmos.models.CosmosContainerProperties; +import com.azure.cosmos.models.CosmosItemRequestOptions; +import com.azure.cosmos.models.CosmosItemResponse; +import com.azure.cosmos.models.FeedOptions; +import com.azure.cosmos.models.PartitionKey; +import com.google.common.collect.Lists; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class SampleTTLQuickstart { + + private CosmosClient client; + + private final String databaseName = "AzureSampleFamilyDB"; + private final String containerName = "FamilyContainer"; + + private CosmosDatabase database; + private CosmosContainer container; + + protected static Logger logger = LoggerFactory.getLogger(SampleChangeFeedProcessor.class.getSimpleName()); + + public void close() { + client.close(); + } + + /** + * Run a Hello CosmosDB console application. + *

+ * This is a simple sample application intended to demonstrate Create, Read, Update, Delete (CRUD) operations + * with Azure Cosmos DB Java SDK, as applied to databases, containers and items. This sample will + * 1. Create synchronous client, database and container instances + * 2. Create several items + * 3. Upsert one of the items + * 4. Perform a query over the items + * 5. Delete an item + * 6. Delete the Cosmos DB database and container resources and close the client. * + */ + public static void main(String[] args) { + SampleTTLQuickstart p = new SampleTTLQuickstart(); + + try { + logger.info("Starting SYNC main"); + p.getStartedDemo(); + logger.info("Demo complete, please hold while resources are released"); + } catch (Exception e) { + e.printStackTrace(); + logger.error(String.format("Cosmos getStarted failed with %s", e)); + } finally { + logger.info("Closing the client"); + p.shutdown(); + } + } + + + private void getStartedDemo() throws Exception { + + logger.info("Using Azure Cosmos DB endpoint: " + AccountSettings.HOST); + + ConnectionPolicy defaultPolicy = ConnectionPolicy.getDefaultPolicy(); + // Setting the preferred location to Cosmos DB Account region + // West US is just an example. User should set preferred location to the Cosmos DB region closest to the application + defaultPolicy.setPreferredLocations(Lists.newArrayList("West US")); + + // Create sync client + client = new CosmosClientBuilder() + .setEndpoint(AccountSettings.HOST) + .setKey(AccountSettings.MASTER_KEY) + .setConnectionPolicy(defaultPolicy) + .setConsistencyLevel(ConsistencyLevel.EVENTUAL) + .buildClient(); + + + createDatabaseIfNotExists(); + createContainerIfNotExists(); + + // Setup family items to create + ArrayList familiesToCreate = new ArrayList<>(); + familiesToCreate.add(Families.getAndersenFamilyItem()); + familiesToCreate.add(Families.getWakefieldFamilyItem()); + familiesToCreate.add(Families.getJohnsonFamilyItem()); + familiesToCreate.add(Families.getSmithFamilyItem()); + + // Creates several items in the container + // Also applies an upsert operation to one of the items (create if not present, otherwise replace) + createFamilies(familiesToCreate); + + logger.info("Reading items."); + readItems(familiesToCreate); + + logger.info("Querying items."); + queryItems(); + + logger.info("Delete an item."); + deleteItem(familiesToCreate.get(0)); + } + + private void createDatabaseIfNotExists() throws Exception { + logger.info("Create database " + databaseName + " if not exists."); + + // Create database if not exists + database = client.createDatabaseIfNotExists(databaseName).getDatabase(); + + logger.info("Checking database " + database.getId() + " completed!\n"); + } + + private void createContainerIfNotExists() throws Exception { + logger.info("Create container " + containerName + " if not exists."); + + // Create container if not exists + CosmosContainerProperties containerProperties = + new CosmosContainerProperties(containerName, "/lastName"); + + // Create container with 400 RU/s + container = database.createContainerIfNotExists(containerProperties, 400).getContainer(); + + logger.info("Checking container " + container.getId() + " completed!\n"); + } + + private void createFamilies(List families) throws Exception { + double totalRequestCharge = 0; + for (Family family : families) { + + // Create item using container that we created using sync client + + // Use lastName as partitionKey for cosmos item + // Using appropriate partition key improves the performance of database operations + CosmosItemRequestOptions cosmosItemRequestOptions = new CosmosItemRequestOptions(); + CosmosItemResponse item = container.createItem(family, new PartitionKey(family.getLastName()), cosmosItemRequestOptions); + + // Get request charge and other properties like latency, and diagnostics strings, etc. + logger.info(String.format("Created item with request charge of %.2f within duration %s", + item.getRequestCharge(), item.getRequestLatency())); + + totalRequestCharge += item.getRequestCharge(); + } + logger.info(String.format("Created %d items with total request charge of %.2f", + families.size(), totalRequestCharge)); + + Family family_to_upsert = families.get(0); + logger.info(String.format("Upserting the item with id %s after modifying the isRegistered field...", family_to_upsert.getId())); + family_to_upsert.setRegistered(!family_to_upsert.isRegistered()); + + CosmosItemResponse item = container.upsertItem(family_to_upsert); + + // Get upsert request charge and other properties like latency, and diagnostics strings, etc. + logger.info(String.format("Upserted item with request charge of %.2f within duration %s", + item.getRequestCharge(), item.getRequestLatency())); + } + + private void readItems(ArrayList familiesToCreate) { + // Using partition key for point read scenarios. + // This will help fast look up of items because of partition key + familiesToCreate.forEach(family -> { + try { + CosmosItemResponse item = container.readItem(family.getId(), new PartitionKey(family.getLastName()), Family.class); + double requestCharge = item.getRequestCharge(); + Duration requestLatency = item.getRequestLatency(); + logger.info(String.format("Item successfully read with id %s with a charge of %.2f and within duration %s", + item.getResource().getId(), requestCharge, requestLatency)); + } catch (CosmosClientException e) { + e.printStackTrace(); + logger.info(String.format("Read Item failed with %s", e)); + } + }); + } + + private void queryItems() { + // Set some common query options + FeedOptions queryOptions = new FeedOptions(); + queryOptions.setMaxItemCount(10); + //queryOptions.setEnableCrossPartitionQuery(true); //No longer necessary in SDK v4 + // Set populate query metrics to get metrics around query executions + queryOptions.setPopulateQueryMetrics(true); + + CosmosPagedIterable familiesPagedIterable = container.queryItems( + "SELECT * FROM Family WHERE Family.lastName IN ('Andersen', 'Wakefield', 'Johnson')", queryOptions, Family.class); + + familiesPagedIterable.iterableByPage().forEach(cosmosItemPropertiesFeedResponse -> { + logger.info("Got a page of query result with " + + cosmosItemPropertiesFeedResponse.getResults().size() + " items(s)" + + " and request charge of " + cosmosItemPropertiesFeedResponse.getRequestCharge()); + + logger.info("Item Ids " + cosmosItemPropertiesFeedResponse + .getResults() + .stream() + .map(Family::getId) + .collect(Collectors.toList())); + }); + } + + private void deleteItem(Family item) { + container.deleteItem(item.getId(), new PartitionKey(item.getLastName()), new CosmosItemRequestOptions()); + } + + private void shutdown() { + try { + //Clean shutdown + logger.info("Deleting Cosmos DB resources"); + logger.info("-Deleting container..."); + if (container != null) + container.delete(); + logger.info("-Deleting database..."); + if (database != null) + database.delete(); + logger.info("-Closing the client..."); + } catch (Exception err) { + logger.error("Deleting Cosmos DB resources failed, will still attempt to close the client. See stack trace below."); + err.printStackTrace(); + } + client.close(); + logger.info("Done."); + } +} From 75d99187e36248526f2c33b0f6c0f772949af4f4 Mon Sep 17 00:00:00 2001 From: Andrew Feldman Date: Fri, 1 May 2020 08:00:21 -0700 Subject: [PATCH 2/2] TTL sync sample --- .../common/SimpleFamilyMemberPOJO.java | 31 +++++++++++++ .../ttl/sync/SampleTTLQuickstart.java | 46 ++++++++++++------- 2 files changed, 61 insertions(+), 16 deletions(-) create mode 100644 src/main/java/com/azure/cosmos/examples/common/SimpleFamilyMemberPOJO.java diff --git a/src/main/java/com/azure/cosmos/examples/common/SimpleFamilyMemberPOJO.java b/src/main/java/com/azure/cosmos/examples/common/SimpleFamilyMemberPOJO.java new file mode 100644 index 0000000..f5b086d --- /dev/null +++ b/src/main/java/com/azure/cosmos/examples/common/SimpleFamilyMemberPOJO.java @@ -0,0 +1,31 @@ +package com.azure.cosmos.examples.common; + +public class SimpleFamilyMemberPOJO { + private String lastName; + private String id; + private Integer ttl; + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getLastName() { + return lastName; + } + + public void setId(String id) { + this.id = id; + } + + public String getId() { + return id; + } + + public void setTtl(Integer ttl) { + this.ttl = ttl; + } + + public Integer getTtl() { + return ttl; + } +} diff --git a/src/main/java/com/azure/cosmos/examples/ttl/sync/SampleTTLQuickstart.java b/src/main/java/com/azure/cosmos/examples/ttl/sync/SampleTTLQuickstart.java index 59dd34b..7a59fa9 100644 --- a/src/main/java/com/azure/cosmos/examples/ttl/sync/SampleTTLQuickstart.java +++ b/src/main/java/com/azure/cosmos/examples/ttl/sync/SampleTTLQuickstart.java @@ -13,8 +13,10 @@ import com.azure.cosmos.CosmosPagedIterable; import com.azure.cosmos.examples.changefeed.SampleChangeFeedProcessor; import com.azure.cosmos.examples.common.AccountSettings; +import com.azure.cosmos.examples.common.CustomPOJO; import com.azure.cosmos.examples.common.Families; import com.azure.cosmos.examples.common.Family; +import com.azure.cosmos.examples.common.SimpleFamilyMemberPOJO; import com.azure.cosmos.models.CosmosContainerProperties; import com.azure.cosmos.models.CosmosItemRequestOptions; import com.azure.cosmos.models.CosmosItemResponse; @@ -27,6 +29,7 @@ import java.time.Duration; import java.util.ArrayList; import java.util.List; +import java.util.UUID; import java.util.stream.Collectors; public class SampleTTLQuickstart { @@ -95,25 +98,36 @@ private void getStartedDemo() throws Exception { createDatabaseIfNotExists(); createContainerIfNotExists(); - // Setup family items to create - ArrayList familiesToCreate = new ArrayList<>(); - familiesToCreate.add(Families.getAndersenFamilyItem()); - familiesToCreate.add(Families.getWakefieldFamilyItem()); - familiesToCreate.add(Families.getJohnsonFamilyItem()); - familiesToCreate.add(Families.getSmithFamilyItem()); + // Enable TTL for items in a container but do not set a default TTL + CosmosContainerProperties containerProperties = new CosmosContainerProperties(containerName, "/lastName"); + containerProperties.setDefaultTimeToLiveInSeconds(-1); + container.replace(containerProperties); - // Creates several items in the container - // Also applies an upsert operation to one of the items (create if not present, otherwise replace) - createFamilies(familiesToCreate); + // Enable TTL for items in a container and set a default TTL + containerProperties.setDefaultTimeToLiveInSeconds(90 * 60 * 60 * 24); + container.replace(containerProperties); - logger.info("Reading items."); - readItems(familiesToCreate); + // Set item TTL as a POJO field + SimpleFamilyMemberPOJO famPOJO = new SimpleFamilyMemberPOJO(); + famPOJO.setLastName("Andrews"); + famPOJO.setId(UUID.randomUUID().toString()); + famPOJO.setTtl(5); //5 sec TTL + container.createItem(famPOJO, new PartitionKey(famPOJO.getLastName()), new CosmosItemRequestOptions()); - logger.info("Querying items."); - queryItems(); + // Reset time-to-live - TTL value stays the same, this just resets the timer (reset _ts) + CosmosItemResponse itemResponseReset = container.upsertItem(famPOJO, new CosmosItemRequestOptions()); - logger.info("Delete an item."); - deleteItem(familiesToCreate.get(0)); + // Remove (null) the item TTL field to accept container default. + famPOJO.setTtl(null); + container.upsertItem(famPOJO, new CosmosItemRequestOptions()); + + // Set the item TTL field to -1 to disable TTL for that item + famPOJO.setTtl(-1); + container.upsertItem(famPOJO, new CosmosItemRequestOptions()); + + // Disable TTL on the container by deleting (nulling) the property + containerProperties.setDefaultTimeToLiveInSeconds(null); + container.replace(containerProperties); } private void createDatabaseIfNotExists() throws Exception { @@ -232,4 +246,4 @@ private void shutdown() { client.close(); logger.info("Done."); } -} +} \ No newline at end of file