diff --git a/.doc_gen/metadata/entityresolution_metadata.yaml b/.doc_gen/metadata/entityresolution_metadata.yaml index b318b6c2a41..a992fe8359e 100644 --- a/.doc_gen/metadata/entityresolution_metadata.yaml +++ b/.doc_gen/metadata/entityresolution_metadata.yaml @@ -12,6 +12,14 @@ entityresolution_Hello: - description: snippet_tags: - entityres.java2_hello.main + JavaScript: + versions: + - sdk_version: 3 + github: javascriptv3/example_code/entityresolution + excerpts: + - description: + snippet_tags: + - javascript.v3.entity-resolution.hello services: entityresolution: {listMatchingWorkflows} entityresolution_DeleteSchemaMapping: @@ -24,6 +32,14 @@ entityresolution_DeleteSchemaMapping: - description: snippet_tags: - entityres.java2_delete_mappings.main + JavaScript: + versions: + - sdk_version: 3 + github: javascriptv3/example_code/entityresolution + excerpts: + - description: + snippet_tags: + - entity-resolution.JavaScriptv3.delete.schema-mapping services: entityresolution: {DeleteSchemaMapping} entityresolution_TagEntityResource: @@ -36,6 +52,14 @@ entityresolution_TagEntityResource: - description: snippet_tags: - entityres.java2_tag_resource.main + JavaScript: + versions: + - sdk_version: 3 + github: javascriptv3/example_code/entityresolution + excerpts: + - description: + snippet_tags: + - entity-resolution.JavaScriptv3.tag.entity-resource services: entityresolution: {TagEntityResource} entityresolution_CreateMatchingWorkflow: @@ -48,6 +72,14 @@ entityresolution_CreateMatchingWorkflow: - description: snippet_tags: - entityres.java2_create_matching_workflow.main + JavaScript: + versions: + - sdk_version: 3 + github: javascriptv3/example_code/entityresolution + excerpts: + - description: + snippet_tags: + - entity-resolution.JavaScriptv3.create-matching-workflow services: entityresolution: {CreateMatchingWorkflow} entityresolution_CheckWorkflowStatus: @@ -60,6 +92,14 @@ entityresolution_CheckWorkflowStatus: - description: snippet_tags: - entityres.java2_check_matching_workflow.main + JavaScript: + versions: + - sdk_version: 3 + github: javascriptv3/example_code/entityresolution + excerpts: + - description: + snippet_tags: + - entity-resolution.JavaScriptv3.check-workflow-status services: entityresolution: {CheckWorkflowStatus} entityresolution_StartMatchingJob: @@ -72,6 +112,14 @@ entityresolution_StartMatchingJob: - description: snippet_tags: - entityres.java2_start_job.main + JavaScript: + versions: + - sdk_version: 3 + github: javascriptv3/example_code/entityresolution + excerpts: + - description: + snippet_tags: + - entity-resolution.JavaScriptv3.start.matching-job services: entityresolution: {StartMatchingJob} entityresolution_GetMatchingJob: @@ -84,6 +132,14 @@ entityresolution_GetMatchingJob: - description: snippet_tags: - entityres.java2_get_job.main + JavaScript: + versions: + - sdk_version: 3 + github: javascriptv3/example_code/entityresolution + excerpts: + - description: + snippet_tags: + - entity-resolution.JavaScriptv3.get.matching-job services: entityresolution: {GetMatchingJob} entityresolution_DeleteMatchingWorkflow: @@ -96,6 +152,14 @@ entityresolution_DeleteMatchingWorkflow: - description: snippet_tags: - entityres.java2_delete_matching_workflow.main + JavaScript: + versions: + - sdk_version: 3 + github: javascriptv3/example_code/entityresolution + excerpts: + - description: + snippet_tags: + - entity-resolution.JavaScriptv3.delete-matching-workflow services: entityresolution: {DeleteMatchingWorkflow} entityresolution_ListSchemaMappings: @@ -108,6 +172,14 @@ entityresolution_ListSchemaMappings: - description: snippet_tags: - entityres.java2_list_mappings.main + JavaScript: + versions: + - sdk_version: 3 + github: javascriptv3/example_code/entityresolution + excerpts: + - description: + snippet_tags: + - entity-resolution.JavaScriptv3.list.schema-mapping services: entityresolution: {ListSchemaMappings} entityresolution_GetSchemaMapping: @@ -120,6 +192,14 @@ entityresolution_GetSchemaMapping: - description: snippet_tags: - entityres.java2_get_schema_mapping.main + JavaScript: + versions: + - sdk_version: 3 + github: javascriptv3/example_code/entityresolution + excerpts: + - description: + snippet_tags: + - entity-resolution.JavaScriptv3.get.schema-mapping services: entityresolution: {GetSchemaMapping} entityresolution_CreateSchemaMapping: @@ -132,6 +212,14 @@ entityresolution_CreateSchemaMapping: - description: snippet_tags: - entityres.java2_create_schema.main + JavaScript: + versions: + - sdk_version: 3 + github: javascriptv3/example_code/entityresolution + excerpts: + - description: + snippet_tags: + - entity-resolution.JavaScriptv3.create-schema-mapping services: entityresolution: {CreateSchemaMapping} entityresolution_Scenario: @@ -158,5 +246,14 @@ entityresolution_Scenario: - description: A wrapper class for &ERlong; SDK methods. snippet_tags: - entityres.java2_actions.main + JavaScript: + versions: + - sdk_version: 2 + github: javav2/example_code/entityresolution + sdkguide: + excerpts: + - description: Run an interactive scenario demonstrating &ERlong; features. + snippet_tags: + - entity-resolution.JavaScriptv3.scenario.basics services: entityresolution: {} diff --git a/javascriptv3/example_code/entityresolution/README.md b/javascriptv3/example_code/entityresolution/README.md new file mode 100644 index 00000000000..b165d48fdca --- /dev/null +++ b/javascriptv3/example_code/entityresolution/README.md @@ -0,0 +1,123 @@ +# AWS Entity Resolution code examples for the SDK for JavaScript (v3) + +## Overview + +Shows how to use the AWS SDK for JavaScript (v3) to work with AWS Entity Resolution. + + + + +_AWS Entity Resolution helps organizations extract, link, and organize information from multiple data sources._ + +## ⚠ Important + +* Running this code might result in charges to your AWS account. For more details, see [AWS Pricing](https://aws.amazon.com/pricing/) and [Free Tier](https://aws.amazon.com/free/). +* Running the tests might result in charges to your AWS account. +* We recommend that you grant your code least privilege. At most, grant only the minimum permissions required to perform the task. For more information, see [Grant least privilege](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege). +* This code is not tested in every AWS Region. For more information, see [AWS Regional Services](https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services). + + + + +## Code examples + +### Prerequisites + +For prerequisites, see the [README](../../README.md#Prerequisites) in the `javascriptv3` folder. + + + + + +### Get started + +- [Hello AWS Entity Resolution](hello.js#L4) (`listMatchingWorkflows`) + + +### Single actions + +Code excerpts that show you how to call individual service functions. + +- [CreateMatchingWorkflow](actions/create-matching-workflow.js#L4) +- [CreateSchemaMapping](actions/create-schema-mapping.js#L4) +- [DeleteMatchingWorkflow](actions/delete-matching-workflow.js#L4) +- [DeleteSchemaMapping](actions/delete-schema-mapping.js#L4) +- [GetMatchingJob](actions/get-matching-job.js#L4) +- [GetSchemaMapping](actions/get-schema-mapping.js#L4) +- [ListSchemaMappings](actions/list-schema-mappings.js#L4) +- [StartMatchingJob](actions/start-matching-job.js#L4) +- [TagEntityResource](actions/tag-entity-resource.js#L4) + + + + + +## Run the examples + +### Instructions + +**Note**: All code examples are written in ECMAscript 6 (ES6). For guidelines on converting to CommonJS, see +[JavaScript ES6/CommonJS syntax](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/sdk-examples-javascript-syntax.html). + +**Run a single action** + +```bash +node ./actions/ +``` + +**Run a scenario** + +Most scenarios can be run with the following command: +```bash +node ./scenarios/ +``` + +**Run with options** + +Some actions and scenarios can be run with options from the command line: +```bash +node ./scenarios/ --option1 --option2 +``` +[util.parseArgs](https://nodejs.org/api/util.html#utilparseargsconfig) is used to configure +these options. For the specific options available to each script, see the `parseArgs` usage +for that file. + + + + +#### Hello AWS Entity Resolution + +This example shows you how to get started using AWS Entity Resolution. + +```bash +node ./hello.js +``` + + +### Tests + +⚠ Running tests might result in charges to your AWS account. + + +To find instructions for running these tests, see the [README](../../README.md#Tests) +in the `javascriptv3` folder. + + + + + + +## Additional resources + +- [AWS Entity Resolution User Guide](https://docs.aws.amazon.com/entityresolution/latest/userguide/what-is-service.html) +- [AWS Entity Resolution API Reference](https://docs.aws.amazon.com/entityresolution/latest/apireference/Welcome.html) +- [SDK for JavaScript (v3) AWS Entity Resolution reference](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/entityresolution/) + + + + +--- + +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 diff --git a/javascriptv3/example_code/entityresolution/actions/check-workflow-status.js b/javascriptv3/example_code/entityresolution/actions/check-workflow-status.js new file mode 100644 index 00000000000..37b5ac415f5 --- /dev/null +++ b/javascriptv3/example_code/entityresolution/actions/check-workflow-status.js @@ -0,0 +1,38 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +// snippet-start:[entity-resolution.JavaScriptv3.check-workflow-status] + +//The default inputs for this demo are read from the ../inputs.json. + +import { fileURLToPath } from "node:url"; + +import { + GetMatchingJobCommand, + EntityResolutionClient, +} from "@aws-sdk/client-entityresolution"; +import data from "../inputs.json" with { type: "json" }; + +const region = "eu-west-1"; +const erClient = new EntityResolutionClient({ region: region }); + +export const main = async ({ workflowName, jobId }) => { + const getMatchingJobParams = { + workflowName: `${data.inputs.workflowName}`, + jobId: `${data.inputs.jobId}`, + }; + try { + const command = new GetMatchingJobCommand(getMatchingJobParams); + const response = await erClient.send(command); + console.log(`Job status: ${response.status}`); + } catch (error) { + console.log("error ", error.message); + } +}; + +// snippet-end:[entity-resolution.JavaScriptv3.check-workflow-status] + +// Invoke main function if this file was run directly. +if (process.argv[1] === fileURLToPath(import.meta.url)) { + main(); +} diff --git a/javascriptv3/example_code/entityresolution/actions/create-matching-workflow.js b/javascriptv3/example_code/entityresolution/actions/create-matching-workflow.js new file mode 100644 index 00000000000..5d053a82efc --- /dev/null +++ b/javascriptv3/example_code/entityresolution/actions/create-matching-workflow.js @@ -0,0 +1,78 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +// snippet-start:[entity-resolution.JavaScriptv3.create-matching-workflow] + +//The default inputs for this demo are read from the ../inputs.json. + +import { fileURLToPath } from "node:url"; + +import { + CreateMatchingWorkflowCommand, + EntityResolutionClient, +} from "@aws-sdk/client-entityresolution"; +import data from "../inputs.json" with { type: "json" }; + +const region = "eu-west-1"; +const erClient = new EntityResolutionClient({ region: region }); + +export const main = async () => { + const createMatchingWorkflowParams = { + roleArn: `${data.inputs.roleArn}`, + workflowName: `${data.inputs.workflowName}`, + description: "Created by using the AWS SDK for JavaScript (v3).", + inputSourceConfig: [ + { + inputSourceARN: `${data.inputs.JSONinputSourceARN}`, + schemaName: `${data.inputs.schemaNameJson}`, + applyNormalization: false, + }, + { + inputSourceARN: `${data.inputs.CSVinputSourceARN}`, + schemaName: `${data.inputs.schemaNameCSV}`, + applyNormalization: false, + }, + ], + outputSourceConfig: [ + { + outputS3Path: `s3://${data.inputs.myBucketName}/eroutput`, + output: [ + { + name: "id", + }, + { + name: "name", + }, + { + name: "email", + }, + { + name: "phone", + }, + ], + applyNormalization: false, + }, + ], + resolutionTechniques: { resolutionType: "ML_MATCHING" }, + }; + try { + const command = new CreateMatchingWorkflowCommand( + createMatchingWorkflowParams, + ); + const response = await erClient.send(command); + + console.log( + `Workflow created successfully.\n The workflow ARN is: ${response.workflowArn}`, + ); + } catch (caught) { + console.error(caught.message); + throw caught; + } +}; + +// snippet-end:[entity-resolution.JavaScriptv3.create-matching-workflow] + +// Invoke main function if this file was run directly. +if (process.argv[1] === fileURLToPath(import.meta.url)) { + main(); +} diff --git a/javascriptv3/example_code/entityresolution/actions/create-schema-mapping.js b/javascriptv3/example_code/entityresolution/actions/create-schema-mapping.js new file mode 100644 index 00000000000..43acdb709c9 --- /dev/null +++ b/javascriptv3/example_code/entityresolution/actions/create-schema-mapping.js @@ -0,0 +1,75 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +// snippet-start:[entity-resolution.JavaScriptv3.create-schema-mapping] + +//The default inputs for this demo are read from the ../inputs.json. + +import { fileURLToPath } from "node:url"; + +import { + CreateSchemaMappingCommand, + EntityResolutionClient, +} from "@aws-sdk/client-entityresolution"; +import data from "../inputs.json" with { type: "json" }; + +const region = "eu-west-1"; +const erClient = new EntityResolutionClient({ region: region }); + +export const main = async () => { + const createSchemaMappingParamsJson = { + schemaName: `${data.inputs.schemaNameJson}`, + mappedInputFields: [ + { + fieldName: "id", + type: "UNIQUE_ID", + }, + { + fieldName: "name", + type: "NAME", + }, + { + fieldName: "email", + type: "EMAIL_ADDRESS", + }, + ], + }; + const createSchemaMappingParamsCSV = { + schemaName: `${data.inputs.schemaNameCSV}`, + mappedInputFields: [ + { + fieldName: "id", + type: "UNIQUE_ID", + }, + { + fieldName: "name", + type: "NAME", + }, + { + fieldName: "email", + type: "EMAIL_ADDRESS", + }, + { + fieldName: "phone", + type: "PROVIDER_ID", + subType: "STRING", + }, + ], + }; + try { + const command = new CreateSchemaMappingCommand( + createSchemaMappingParamsJson, + ); + const response = await erClient.send(command); + console.log("The JSON schema mapping name is ", response.schemaName); + } catch (error) { + console.log("error ", error.message); + } +}; + +// snippet-end:[entity-resolution.JavaScriptv3.create-schema-mapping] + +// Invoke main function if this file was run directly. +if (process.argv[1] === fileURLToPath(import.meta.url)) { + main(); +} diff --git a/javascriptv3/example_code/entityresolution/actions/delete-matching-workflow.js b/javascriptv3/example_code/entityresolution/actions/delete-matching-workflow.js new file mode 100644 index 00000000000..c1a898c302e --- /dev/null +++ b/javascriptv3/example_code/entityresolution/actions/delete-matching-workflow.js @@ -0,0 +1,37 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +// snippet-start:[entity-resolution.JavaScriptv3.delete-matching-workflow] + +//The default inputs for this demo are read from the ../inputs.json. + +import { fileURLToPath } from "node:url"; + +import { + DeleteMatchingWorkflowCommand, + EntityResolutionClient, +} from "@aws-sdk/client-entityresolution"; +import data from "../inputs.json" with { type: "json" }; + +const region = "eu-west-1"; +const erClient = new EntityResolutionClient({ region: region }); + +export const main = async () => { + try { + const deleteWorkflowParams = { + workflowName: `${data.inputs.workflowName}`, + }; + const command = new DeleteMatchingWorkflowCommand(deleteWorkflowParams); + const response = await erClient.send(command); + console.log("Workflow deleted successfully!", response); + } catch (error) { + console.log("error ", error); + } +}; + +// snippet-end:[entity-resolution.JavaScriptv3.delete-matching-workflow] + +// Invoke main function if this file was run directly. +if (process.argv[1] === fileURLToPath(import.meta.url)) { + main(); +} diff --git a/javascriptv3/example_code/entityresolution/actions/delete-schema-mapping.js b/javascriptv3/example_code/entityresolution/actions/delete-schema-mapping.js new file mode 100644 index 00000000000..fb27803089b --- /dev/null +++ b/javascriptv3/example_code/entityresolution/actions/delete-schema-mapping.js @@ -0,0 +1,37 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +// snippet-start:[entity-resolution.JavaScriptv3.delete.schema-mapping] + +//The default inputs for this demo are read from the ../inputs.json. + +import { fileURLToPath } from "node:url"; + +import { + DeleteSchemaMappingCommand, + EntityResolutionClient, +} from "@aws-sdk/client-entityresolution"; +import data from "../inputs.json" with { type: "json" }; + +const region = "eu-west-1"; +const erClient = new EntityResolutionClient({ region: region }); + +export const main = async () => { + const deleteSchemaMapping = { + schemaName: `${data.inputs.schemaNameJson}`, + }; + try { + const command = new DeleteSchemaMappingCommand(deleteSchemaMapping); + const response = await erClient.send(command); + console.log("Schema mapping deleted successfully. ", response); + } catch (error) { + console.log("error ", error); + } +}; + +// snippet-end:[entity-resolution.JavaScriptv3.delete.schema-mapping] + +// Invoke main function if this file was run directly. +if (process.argv[1] === fileURLToPath(import.meta.url)) { + main(); +} diff --git a/javascriptv3/example_code/entityresolution/actions/get-matching-job.js b/javascriptv3/example_code/entityresolution/actions/get-matching-job.js new file mode 100644 index 00000000000..a26378260c7 --- /dev/null +++ b/javascriptv3/example_code/entityresolution/actions/get-matching-job.js @@ -0,0 +1,40 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +// snippet-start:[entity-resolution.JavaScriptv3.get.matching-job] + +//The default inputs for this demo are read from the ../inputs.json. + +import { fileURLToPath } from "node:url"; + +import { + GetMatchingJobCommand, + EntityResolutionClient, +} from "@aws-sdk/client-entityresolution"; +import data from "../inputs.json" with { type: "json" }; + +const region = "eu-west-1"; +const erClient = new EntityResolutionClient({ region: region }); + +export const main = async () => { + async function getInfo() { + const getJobInfoParams = { + workflowName: `${data.inputs.workflowName}`, + jobId: `${data.inputs.jobId}`, + }; + try { + const command = new GetMatchingJobCommand(getJobInfoParams); + const response = await erClient.send(command); + console.log(`Job status: ${response.status}`); + } catch (error) { + console.log("error ", error.message); + } + } +}; + +// snippet-end:[entity-resolution.JavaScriptv3.get.matching-job] + +// Invoke main function if this file was run directly. +if (process.argv[1] === fileURLToPath(import.meta.url)) { + main(); +} diff --git a/javascriptv3/example_code/entityresolution/actions/get-schema-mapping.js b/javascriptv3/example_code/entityresolution/actions/get-schema-mapping.js new file mode 100644 index 00000000000..8a5be1f2dd7 --- /dev/null +++ b/javascriptv3/example_code/entityresolution/actions/get-schema-mapping.js @@ -0,0 +1,42 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +// snippet-start:[entity-resolution.JavaScriptv3.get.schema-mapping] + +//The default inputs for this demo are read from the ../inputs.json. + +import { fileURLToPath } from "node:url"; + +import { + GetSchemaMappingCommand, + EntityResolutionClient, +} from "@aws-sdk/client-entityresolution"; +import data from "../inputs.json" with { type: "json" }; + +const region = "eu-west-1"; +const erClient = new EntityResolutionClient({ region: region }); + +export const main = async () => { + const getSchemaMappingJsonParams = { + schemaName: `${data.inputs.schemaNameJson}`, + }; + try { + const command = new GetSchemaMappingCommand(getSchemaMappingJsonParams); + const response = await erClient.send(command); + console.log(response); + console.log( + `Schema mapping for the JSON data:\n ${response.mappedInputFields[0]}`, + ); + console.log("Schema mapping ARN is: ", response.schemaArn); + } catch (caught) { + console.error(caught.message); + throw caught; + } +}; + +// snippet-end:[entity-resolution.JavaScriptv3.get.schema-mapping] + +// Invoke main function if this file was run directly. +if (process.argv[1] === fileURLToPath(import.meta.url)) { + main(); +} diff --git a/javascriptv3/example_code/entityresolution/actions/list-schema-mappings.js b/javascriptv3/example_code/entityresolution/actions/list-schema-mappings.js new file mode 100644 index 00000000000..e172d29f58c --- /dev/null +++ b/javascriptv3/example_code/entityresolution/actions/list-schema-mappings.js @@ -0,0 +1,46 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +// snippet-start:[entity-resolution.JavaScriptv3.list.schema-mapping] + +//The default inputs for this demo are read from the ../inputs.json. + +import { fileURLToPath } from "node:url"; + +import { + ListSchemaMappingsCommand, + EntityResolutionClient, +} from "@aws-sdk/client-entityresolution"; +import data from "../inputs.json" with { type: "json" }; + +const region = "eu-west-1"; +const erClient = new EntityResolutionClient({ region: region }); + +export const main = async () => { + async function getInfo() { + const listSchemaMappingsParams = { + workflowName: `${data.inputs.workflowName}`, + jobId: `${data.inputs.jobId}`, + }; + try { + const command = new ListSchemaMappingsCommand(listSchemaMappingsParams); + const response = await erClient.send(command); + const noOfSchemas = response.schemaList.length; + for (let i = 0; i < noOfSchemas; i++) { + console.log( + `Schema Mapping Name: ${response.schemaList[i].schemaName} `, + ); + } + } catch (caught) { + console.error(caught.message); + throw caught; + } + } + + // snippet-end:[entity-resolution.JavaScriptv3.list.schema-mapping] + + // Invoke main function if this file was run directly. + if (process.argv[1] === fileURLToPath(import.meta.url)) { + main(); + } +}; diff --git a/javascriptv3/example_code/entityresolution/actions/start-matching-job.js b/javascriptv3/example_code/entityresolution/actions/start-matching-job.js new file mode 100644 index 00000000000..2b0461f054a --- /dev/null +++ b/javascriptv3/example_code/entityresolution/actions/start-matching-job.js @@ -0,0 +1,38 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +// snippet-start:[entity-resolution.JavaScriptv3.start.matching-job] + +//The default inputs for this demo are read from the ../inputs.json. + +import { fileURLToPath } from "node:url"; +import { + StartMatchingJobCommand, + EntityResolutionClient, +} from "@aws-sdk/client-entityresolution"; +import data from "../inputs.json" with { type: "json" }; + +const region = "eu-west-1"; +const erClient = new EntityResolutionClient({ region: region }); + +export const main = async () => { + const matchingJobOfWorkflowParams = { + workflowName: `${data.inputs.workflowName}`, + }; + try { + const command = new StartMatchingJobCommand(matchingJobOfWorkflowParams); + const response = await erClient.send(command); + console.log(`Job ID: ${response.jobID} \n +The matching job was successfully started.`); + } catch (caught) { + console.error(caught.message); + throw caught; + } +}; + +// snippet-end:[entity-resolution.JavaScriptv3.start.matching-job] + +// Invoke main function if this file was run directly. +if (process.argv[1] === fileURLToPath(import.meta.url)) { + main(); +} diff --git a/javascriptv3/example_code/entityresolution/actions/tag-entity-resource.js b/javascriptv3/example_code/entityresolution/actions/tag-entity-resource.js new file mode 100644 index 00000000000..60572c1e10c --- /dev/null +++ b/javascriptv3/example_code/entityresolution/actions/tag-entity-resource.js @@ -0,0 +1,42 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +// snippet-start:[entity-resolution.JavaScriptv3.tag.entity-resource] + +//The default inputs for this demo are read from the ../inputs.json. + +import { fileURLToPath } from "node:url"; + +import { + TagResourceCommand, + EntityResolutionClient, +} from "@aws-sdk/client-entityresolution"; +import data from "../inputs.json" with { type: "json" }; + +const region = "eu-west-1"; +const erClient = new EntityResolutionClient({ region: region }); + +export const main = async () => { + const tagResourceCommandParams = { + resourceArn: `${data.inputs.schemaArn}`, + tags: { + tag1: "tag1Value", + tag2: "tag2Value", + }, + }; + try { + const command = new TagResourceCommand(tagResourceCommandParams); + const response = await erClient.send(command); + console.log("Successfully tagged the resource."); + } catch (caught) { + console.error(caught.message); + throw caught; + } +}; + +// snippet-end:[entity-resolution.JavaScriptv3.tag.entity-resource] + +// Invoke main function if this file was run directly. +if (process.argv[1] === fileURLToPath(import.meta.url)) { + main(); +} diff --git a/javascriptv3/example_code/entityresolution/data.csv b/javascriptv3/example_code/entityresolution/data.csv new file mode 100644 index 00000000000..1ed995993e2 --- /dev/null +++ b/javascriptv3/example_code/entityresolution/data.csv @@ -0,0 +1,5 @@ +id,name,email,phone +1,Jane B.,Doe,jane.doe@example.com,555-876-9846 +2,John Doe Jr.,john.doe@example.com,555-654-3210 +3,María García,maría_garcia@company.com,555-567-1234 +4,Mary Major,mary_major@company.com,555-222-3333 \ No newline at end of file diff --git a/javascriptv3/example_code/entityresolution/data.json b/javascriptv3/example_code/entityresolution/data.json new file mode 100644 index 00000000000..01f35f7fc93 --- /dev/null +++ b/javascriptv3/example_code/entityresolution/data.json @@ -0,0 +1,5 @@ +[ + { "id": "1", "name": "Jane Doe", "email": "jane.doe@example.com" }, + { "id": "2", "name": "John Doe", "email": "john.doe@example.com" }, + { "id": "3", "name": "Jorge Souza", "email": "jorge_souza@example.com" } +] diff --git a/javascriptv3/example_code/entityresolution/hello.js b/javascriptv3/example_code/entityresolution/hello.js new file mode 100644 index 00000000000..7f709c7d952 --- /dev/null +++ b/javascriptv3/example_code/entityresolution/hello.js @@ -0,0 +1,37 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +// snippet-start:[javascript.v3.entity-resolution.hello] +import { fileURLToPath } from "node:url"; +import { + EntityResolutionClient, + ListMatchingWorkflowsCommand, +} from "@aws-sdk/client-entityresolution"; + +export const main = async () => { + const region = "eu-west-1"; + const erClient = new EntityResolutionClient({ region: region }); + try { + const command = new ListMatchingWorkflowsCommand({}); + const response = await erClient.send(command); + const workflowSummaries = response.workflowSummaries; + for (const workflowSummary of workflowSummaries) { + console.log(`Attribute name: ${workflowSummaries[0].workflowName} `); + } + if (workflowSummaries.length === 0) { + console.log("No matching workflows found."); + } + } catch (error) { + console.error( + `An error occurred in listing the workflow summaries: ${error.message} \n Exiting program.`, + ); + return; + } +}; + +// snippet-end:[javascript.v3.entity-resolution.hello] + +// Invoke main function if this file was run directly. +if (process.argv[1] === fileURLToPath(import.meta.url)) { + main(); +} diff --git a/javascriptv3/example_code/entityresolution/inputs.json b/javascriptv3/example_code/entityresolution/inputs.json new file mode 100644 index 00000000000..03874f0f32e --- /dev/null +++ b/javascriptv3/example_code/entityresolution/inputs.json @@ -0,0 +1,14 @@ +{ + "inputs": { + "schemaNameJson": "json-AWSSchema", + "schemaNameCSV": "csv-AWSSchema", + "workflowName": "AWSWorkFlow", + "jobId": "JobId", + "entityResolutionStack": "EntityResolutionBasicsStack", + "schemaArn": "mySchemaARN", + "JSONinputSourceARN": "arn:aws:glue:us-east-1:123456789012:table/my-database/my-table", + "CSVinputSourceARN": "arn:aws:glue:us-east-1:123456789012:table/my-glue-database-name/my-glue-table-name", + "roleArn": "EntityResolutionRoleARN", + "myBucketName": "my-bucket-123.example-bucket" + } +} diff --git a/javascriptv3/example_code/entityresolution/package.json b/javascriptv3/example_code/entityresolution/package.json new file mode 100644 index 00000000000..40f60acc4dc --- /dev/null +++ b/javascriptv3/example_code/entityresolution/package.json @@ -0,0 +1,21 @@ +{ + "name": "@aws-doc-sdk-examples/javascript-entity-resolution-basics", + "version": "1.0.0", + "description": "Code samples for interacting with AWS Entity Resolutions via the AWS SDK for JavaScript (v3)", + "author": "Brian Murray (brmur@amazon.com)", + "license": "Apache-2.0", + "type": "module", + "scripts": { + "integration-test": "vitest run integration --reporter=junit --outputFile=test_results/entity-resolution-test-results.junit.xml" + }, + "dependencies": { + "@aws-doc-sdk-examples/lib": "^1.0.1", + "@aws-sdk/client-entityresolution": "^3.163.0", + "@aws-sdk/client-cloudformation": "^3.797.0", + "@aws-sdk/client-s3": "^3.797.0" + }, + "devDependencies": { + "prettier": "3.5.3", + "vitest": "^1.6.1" + } +} diff --git a/javascriptv3/example_code/entityresolution/scenarios/entity-resolution-basics.js b/javascriptv3/example_code/entityresolution/scenarios/entity-resolution-basics.js new file mode 100644 index 00000000000..d5fa6825993 --- /dev/null +++ b/javascriptv3/example_code/entityresolution/scenarios/entity-resolution-basics.js @@ -0,0 +1,706 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +/* +Before running this JavaScript code example, set up your development environment, including your credentials. +This demo illustrates how to use the AWS SDK for JavaScript (v3) to work with AWS Entity Resolution. + +The default inputs for this demo are read from the ../inputs.json. + +For more information, see the following documentation topic: + +https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/getting-started.html +*/ +// snippet-start:[entity-resolution.JavaScriptv3.scenario.basics] + +import { + Scenario, + ScenarioAction, + ScenarioInput, + ScenarioOutput, +} from "@aws-doc-sdk-examples/lib/scenario/index.js"; +import { + CloudFormationClient, + CreateStackCommand, + DeleteStackCommand, + DescribeStacksCommand, + waitUntilStackExists, + waitUntilStackCreateComplete, +} from "@aws-sdk/client-cloudformation"; +import { + EntityResolutionClient, + CreateSchemaMappingCommand, + CreateMatchingWorkflowCommand, + GetMatchingJobCommand, + StartMatchingJobCommand, + GetSchemaMappingCommand, + ListSchemaMappingsCommand, + TagResourceCommand, + DeleteMatchingWorkflowCommand, + DeleteSchemaMappingCommand, + ConflictException, + ValidationException, +} from "@aws-sdk/client-entityresolution"; +import { + DeleteObjectsCommand, + DeleteBucketCommand, + PutObjectCommand, + S3Client, + ListObjectsCommand, +} from "@aws-sdk/client-s3"; +import { wait } from "@aws-doc-sdk-examples/lib/utils/util-timers.js"; + +import { readFile } from "node:fs/promises"; +import { parseArgs } from "node:util"; +import { readFileSync } from "node:fs"; +import { fileURLToPath } from "node:url"; +import { dirname } from "node:path"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); +const stackName = `${data.inputs.entityResolutionStack}`; + +/*The inputs for this example can be edited in the ../input.json.*/ +import data from "../inputs.json" with { type: "json" }; +const skipWhenErrors = (state) => state.errors.length > 0; +/** + * Used repeatedly to have the user press enter. + * @type {ScenarioInput} + */ +/* v8 ignore next 3 */ +const pressEnter = new ScenarioInput("continue", "Press Enter to continue", { + type: "input", + verbose: "false", + skipWhen: skipWhenErrors, +}); + +const region = "eu-west-1"; + +const entityResolutionClient = new EntityResolutionClient({ region: region }); +const cloudFormationClient = new CloudFormationClient({ region: region }); +const s3Client = new S3Client({ region: region }); + +const greet = new ScenarioOutput( + "greet", + "AWS Entity Resolution is a fully-managed machine learning service provided by " + + "Amazon Web Services (AWS) that helps organizations extract, link, and " + + "organize information from multiple data sources. It leverages natural " + + "language processing and deep learning models to identify and resolve " + + "entities, such as people, places, organizations, and products, " + + "across structured and unstructured data.\n" + + "\n" + + "With Entity Resolution, customers can build robust data integration " + + "pipelines to combine and reconcile data from multiple systems, databases, " + + "and documents. The service can handle ambiguous, incomplete, or conflicting " + + "information, and provide a unified view of entities and their relationships. " + + "This can be particularly valuable in applications such as customer 360, " + + "fraud detection, supply chain management, and knowledge management, where " + + "accurate entity identification is crucial.\n" + + "\n" + + "The `EntityResolutionAsyncClient` interface in the AWS SDK for Java 2.x " + + "provides a set of methods to programmatically interact with the AWS Entity " + + "Resolution service. This allows developers to automate the entity extraction, " + + "linking, and deduplication process as part of their data processing workflows. " + + "With Entity Resolution, organizations can unlock the value of their data, " + + "improve decision-making, and enhance customer experiences by having a reliable, " + + "comprehensive view of their key entities.", + + { header: true }, +); +const displayBuildCloudFormationStack = new ScenarioOutput( + "displayBuildCloudFormationStack", + "To prepare the AWS resources needed for this scenario application, the next step uploads " + + "a CloudFormation template whose resulting stack creates the following resources:\n" + + "- An AWS Glue Data Catalog table \n" + + "- An AWS IAM role \n" + + "- An AWS S3 bucket \n" + + "- An AWS Entity Resolution Schema \n" + + "It can take a couple minutes for the Stack to finish creating the resources.", +); + +const sdkBuildCloudFormationStack = new ScenarioAction( + "sdkBuildCloudFormationStack", + async (/** @type {State} */ state) => { + try { + const data = readFileSync( + `${__dirname}/../../../../resources/cfn/entity-resolution-basics/entity-resolution-basics-template.yml`, + "utf8", + ); + await cloudFormationClient.send( + new CreateStackCommand({ + StackName: stackName, + TemplateBody: data, + Capabilities: ["CAPABILITY_IAM"], + }), + ); + await waitUntilStackExists( + { client: cloudFormationClient }, + { StackName: stackName }, + ); + await waitUntilStackCreateComplete( + { client: cloudFormationClient }, + { StackName: stackName }, + ); + const stack = await cloudFormationClient.send( + new DescribeStacksCommand({ + StackName: stackName, + }), + ); + + state.entityResolutionRole = stack.Stacks[0].Outputs[1]; + state.jsonGlueTable = stack.Stacks[0].Outputs[2]; + state.CSVGlueTable = stack.Stacks[0].Outputs[3]; + state.glueDataBucket = stack.Stacks[0].Outputs[0]; + state.stackName = stack.StackName; + console.log(state.glueDataBucket); + console.log( + `The ARN of the EntityResolution Role is ${state.entityResolutionRole.OutputValue}`, + ); + console.log( + `The ARN of the Json Glue Table is ${state.jsonGlueTable.OutputValue}`, + ); + console.log( + `The ARN of the CSV Glue Table is ${state.CSVGlueTable.OutputValue}`, + ); + console.log( + `The name of the Glue Data Bucket is ${state.glueDataBucket.OutputValue}\n`, + ); + } catch (caught) { + console.error(caught.message); + throw caught; + } + try { + console.log( + `Uploading the following JSON in ../data.json to the ${state.glueDataBucket.OutputValue} S3 bucket...`, + ); + const bucketName = state.glueDataBucket.OutputValue; + + const putObjectParams = { + Bucket: bucketName, + Key: "jsonData/data.json", + Body: await readFileSync( + `${__dirname}/../../../../javascriptv3/example_code/entityresolution/data.json`, + ), + }; + const command = new PutObjectCommand(putObjectParams); + const response = await s3Client.send(command); + console.log( + `../data.json file data uploaded to the ${state.glueDataBucket.OutputValue} S3 bucket.\n`, + ); + } catch (caught) { + console.error(caught.message); + throw caught; + } + try { + console.log( + `Uploading the CSV data in ../data.csv to the ${state.glueDataBucket.OutputValue} S3 bucket...`, + ); + + const bucketName = state.glueDataBucket.OutputValue; + const putObjectParams = { + Bucket: bucketName, + Key: "csvData/data.csv", + Body: await readFileSync( + `${__dirname}/../../../../javascriptv3/example_code/entityresolution/data.csv`, + ), + }; + const command = new PutObjectCommand(putObjectParams); + const response = await s3Client.send(command); + console.log( + `../data.csv file data uploaded to the ${state.glueDataBucket.OutputValue} S3 bucket.`, + ); + } catch (caught) { + console.error(caught.message); + throw caught; + } + }, +); + +const displayCreateSchemaMapping = new ScenarioOutput( + "displayCreateSchemaMapping", + "1. Create Schema Mapping" + + "Entity Resolution schema mapping aligns and integrates data from " + + "multiple sources by identifying and matching corresponding entities " + + "like customers or products. It unifies schemas, resolves conflicts, " + + "and uses machine learning to link related entities, enabling a " + + "consolidated, accurate view for improved data quality and decision-making." + + "\n" + + "In this example, the schema mapping lines up with the fields in the JSON and CSV objects. That is, " + + " it contains these fields: id, name, and email. ", +); + +const sdkCreateSchemaMapping = new ScenarioAction( + "sdkCreateSchemaMapping", + async (/** @type {State} */ state) => { + const createSchemaMappingParamsJson = { + schemaName: `${data.inputs.schemaNameJson}`, + mappedInputFields: [ + { + fieldName: "id", + type: "UNIQUE_ID", + }, + { + fieldName: "name", + type: "NAME", + }, + { + fieldName: "email", + type: "EMAIL_ADDRESS", + }, + ], + }; + const createSchemaMappingParamsCSV = { + schemaName: `${data.inputs.schemaNameCSV}`, + mappedInputFields: [ + { + fieldName: "id", + type: "UNIQUE_ID", + }, + { + fieldName: "name", + type: "NAME", + }, + { + fieldName: "email", + type: "EMAIL_ADDRESS", + }, + { + fieldName: "phone", + type: "PROVIDER_ID", + subType: "STRING", + }, + ], + }; + try { + const command = new CreateSchemaMappingCommand( + createSchemaMappingParamsJson, + ); + const response = await entityResolutionClient.send(command); + state.schemaNameJson = response.schemaName; + state.schemaArn = response.schemaArn; + state.idOutputAttribute = response.mappedInputFields[0].fieldName; + state.nameOutputAttribute = response.mappedInputFields[1].fieldName; + state.emailOutputAttribute = response.mappedInputFields[2].fieldName; + + console.log("The JSON schema mapping name is ", state.schemaNameJson); + } catch (caught) { + if (caught instanceof ConflictException) { + console.error( + `The schema mapping already exists: ${caught.message} \n Exiting program.`, + ); + return; + } + } + try { + const command = new CreateSchemaMappingCommand( + createSchemaMappingParamsCSV, + ); + const response = await entityResolutionClient.send(command); + state.schemaNameCSV = response.schemaName; + state.phoneOutputAttribute = response.mappedInputFields[3].fieldName; + console.log("The CSV schema mapping name is ", state.schemaNameCSV); + } catch (caught) { + if (caught instanceof ConflictException) { + console.error( + `An unexpected error occurred while creating the geofence collection: ${caught.message} \n Exiting program.`, + ); + return; + } + } + }, +); +const displayCreateMatchingWorkflow = new ScenarioOutput( + "displayCreateMatchingWorkflow", + "2. Create an AWS Entity Resolution Workflow. " + + "An Entity Resolution matching workflow identifies and links records " + + "across datasets that represent the same real-world entity, such as " + + "customers or products. Using techniques like schema mapping, " + + "data profiling, and machine learning algorithms, " + + "it evaluates attributes like names or emails to detect duplicates " + + "or relationships, even with variations or inconsistencies. " + + "The workflow outputs consolidated, de-duplicated data." + + "\n" + + "We will use the machine learning-based matching technique.", +); + +const sdkCreateMatchingWorkflow = new ScenarioAction( + "sdkCreateMatchingWorkflow", + async (/** @type {State} */ state) => { + const createMatchingWorkflowParams = { + roleArn: `${state.entityResolutionRole.OutputValue}`, + workflowName: `${data.inputs.workflowName}`, + description: "Created by using the AWS SDK for JavaScript (v3).", + inputSourceConfig: [ + { + inputSourceARN: `${state.jsonGlueTable.OutputValue}`, + schemaName: `${data.inputs.schemaNameJson}`, + applyNormalization: false, + }, + { + inputSourceARN: `${state.CSVGlueTable.OutputValue}`, + schemaName: `${data.inputs.schemaNameCSV}`, + applyNormalization: false, + }, + ], + outputSourceConfig: [ + { + outputS3Path: `s3://${state.glueDataBucket.OutputValue}/eroutput`, + output: [ + { + name: state.idOutputAttribute, + }, + { + name: state.nameOutputAttribute, + }, + { + name: state.emailOutputAttribute, + }, + { + name: state.phoneOutputAttribute, + }, + ], + applyNormalization: false, + }, + ], + resolutionTechniques: { resolutionType: "ML_MATCHING" }, + }; + try { + const command = new CreateMatchingWorkflowCommand( + createMatchingWorkflowParams, + ); + const response = await entityResolutionClient.send(command); + state.workflowArn = response.workflowArn; + console.log( + `Workflow created successfully.\n The workflow ARN is: ${response.workflowArn}`, + ); + } catch (caught) { + if (caught instanceof ConflictException) { + console.error( + `The matching workflow already exists: ${caught.message} \n Exiting program.`, + ); + return; + } + if (caught instanceof ValidationException) { + console.error( + `There was a validation exception: ${caught.message} \n Exiting program.`, + ); + return; + } + } + }, +); +const displayMatchingJobOfWorkflow = new ScenarioOutput( + "displayMatchingJobOfWorkflow", + "3. Start the matching job of the workflow", +); + +const sdkMatchingJobOfWorkflow = new ScenarioAction( + "sdk", + async (/** @type {State} */ state) => { + const matchingJobOfWorkflowParams = { + workflowName: `${data.inputs.workflowName}`, + }; + try { + const command = new StartMatchingJobCommand(matchingJobOfWorkflowParams); + const response = await entityResolutionClient.send(command); + state.jobID = response.jobId; + console.log(`Job ID: ${state.jobID} \n +The matching job was successfully started.`); + } catch (caught) { + if (caught instanceof ConflictException) { + console.error( + `The matching workflow already exists: ${caught.message} \n Exiting program.`, + ); + return; + } + } + }, +); + +const displayGetDetailsforJob = new ScenarioOutput( + "displayGetDetailsforJob", + `4. While the matching job is running, let's look at other API methods. First, let's get details for the job `, +); + +const sdkGetDetailsforJob = new ScenarioAction( + "sdkGetDetailsforJob", + async (/** @type {State} */ state) => { + const getDetailsforJobParams = { + workflowName: `${data.inputs.workflowName}`, + jobId: `${state.jobID}`, + }; + try { + const command = new GetMatchingJobCommand(getDetailsforJobParams); + const response = await entityResolutionClient.send(command); + state.Status = response.status; + state.response = response; + console.log(`Job status: ${state.Status} `); + } catch (caught) { + console.error(caught.message); + throw caught; + } + }, +); + +const displayGetSchemaMappingJson = new ScenarioOutput( + "displayGetSchemaMappingJson", + "5. Get the schema mapping for the JSON data.", +); + +const sdkGetSchemaMappingJson = new ScenarioAction( + "sdkGetSchemaMappingJson", + async (/** @type {State} */ state) => { + const getSchemaMappingJsonParams = { + schemaName: `${data.inputs.schemaNameJson}`, + }; + try { + const command = new GetSchemaMappingCommand(getSchemaMappingJsonParams); + const response = await entityResolutionClient.send(command); + console.log("Schema·mapping·ARN·is:·", response.schemaArn); + const resultMappings = response.mappedInputFields; + const noOfResultMappings = resultMappings.length; + for (let i = 0; i < noOfResultMappings; i++) { + console.log( + `Attribute name: ${resultMappings[i].fieldName} `, + `Attribute type: ${resultMappings[i].type}`, + ); + } + } catch (caught) { + console.error(caught.message); + throw caught; + } + }, +); + +const displayListSchemaMappings = new ScenarioOutput( + "displayListSchemaMappings", + "6. List Schema Mappings.", +); + +const sdkListSchemaMappings = new ScenarioAction( + "sdkListSchemaMappings", + async (/** @type {State} */ state) => { + try { + const command = new ListSchemaMappingsCommand({}); + const response = await entityResolutionClient.send(command); + const noOfSchemas = response.schemaList.length; + for (let i = 0; i < noOfSchemas; i++) { + console.log( + `Schema Mapping Name: ${response.schemaList[i].schemaName} `, + ); + } + } catch (caught) { + console.error(caught.message); + throw caught; + } + }, +); + +const displayTagTheJsonSchema = new ScenarioOutput( + "display", + "7. Tag the resource. \n" + + "Tags can help you organize and categorize your Entity Resolution resources. " + + "You can also use them to scope user permissions by granting a user permission " + + "to access or change only resources with certain tag values. " + + "In Entity Resolution, SchemaMapping and MatchingWorkflow can be tagged. For this example, " + + "the SchemaMapping is tagged.", +); + +const sdkTagTheJsonSchema = new ScenarioAction( + "sdkGetSchemaMappingJson", + async (/** @type {State} */ state) => { + const tagResourceCommandParams = { + resourceArn: state.schemaArn, + tags: { + tag1: "tag1Value", + tag2: "tag2Value", + }, + }; + try { + const command = new TagResourceCommand(tagResourceCommandParams); + const response = await entityResolutionClient.send(command); + console.log("Successfully tagged the resource."); + } catch (caught) { + console.error(caught.message); + throw caught; + } + }, +); + +const displayGetJobInfo = new ScenarioOutput( + "displayGetJobInfo", + "8. View the results of the AWS Entity Resolution Workflow.\n " + + "Please perform this task manually in the AWS Management Console. ", +); + +const displayDeleteResources = new ScenarioOutput( + "displayDeleteResources", + "9. Delete the resources \n" + + "You cannot delete a workflow that is in a running state. So this will take ~30 minutes.\n" + + "If you don't want to delete the resources, simply exit this application.", +); + +const sdkDeleteResources = new ScenarioAction( + "sdkDeleteResources", + async (/** @type {State} */ state) => { + console.log( + "You selected to delete the resources. This will take about 30 minutes.", + ); + await wait(1800); + const bucketName = state.glueDataBucket.OutputValue; + try { + const emptyBucket = async ({ bucketName }) => { + const listObjectsCommand = new ListObjectsCommand({ + Bucket: bucketName, + }); + const { Contents } = await s3Client.send(listObjectsCommand); + const keys = Contents.map((c) => c.Key); + + const deleteObjectsCommand = new DeleteObjectsCommand({ + Bucket: bucketName, + Delete: { Objects: keys.map((key) => ({ Key: key })) }, + }); + await s3Client.send(deleteObjectsCommand); + console.log(`Bucket ${bucketName} emptied successfully.\n`); + }; + await emptyBucket({ bucketName }); + } catch (error) { + console.log("error ", error); + } + try { + const deleteBucket = async ({ bucketName }) => { + const command = new DeleteBucketCommand({ Bucket: bucketName }); + await s3Client.send(command); + console.log(`Bucket ${bucketName} deleted successfully.\n`); + }; + await deleteBucket({ bucketName }); + } catch (error) { + console.log("error ", error); + } + try { + console.log( + "Now we will delete the CloudFormation stack, which deletes the resources that were created at the beginning of the scenario.", + ); + const deleteStackParams = { StackName: `${state.stackName}` }; + const command = new DeleteStackCommand(deleteStackParams); + const response = await cloudFormationClient.send(command); + console.log("CloudFormation stack deleted successfully."); + } catch (error) { + console.log("error ", error); + } + try { + const deleteWorkflowParams = { + workflowName: `${data.inputs.workflowName}`, + }; + const command = new DeleteMatchingWorkflowCommand(deleteWorkflowParams); + const response = await entityResolutionClient.send(command); + console.log("Workflow deleted successfully!"); + } catch (caught) { + if (caught instanceof ConflictException) { + console.error( + `Job associated with workflow ${data.inputs.workflowName} is still running, so can't be deleted. + Neither can schemas ${data.inputs.schemaNameJson} and ${data.inputs.schemaNameCSV} associated with it. Please confirm this workflow is finished in the AWS Management Console, then delete it manually.`, + ); + throw caught; + } + } + try { + const deleteJSONschemaMapping = { + schemaName: `${data.inputs.schemaNameJson}`, + }; + const command = new DeleteSchemaMappingCommand(deleteJSONschemaMapping); + const response = await entityResolutionClient.send(command); + console.log("Schema mapping deleted successfully. "); + } catch (caught) { + if (caught instanceof ConflictException) { + console.error( + `The schema ${data.inputs.schemaNameJson} can't be deleted because it is associated with workflow + ${data.inputs.workflowName}, which is still running. Please confirm this workflow is finished in the AWS Management Console, then delete it manually.`, + ); + throw caught; + } + } + try { + const deleteCSVschemaMapping = { + schemaName: `${data.inputs.schemaNameCSV}`, + }; + const command = new DeleteSchemaMappingCommand(deleteCSVschemaMapping); + const response = await entityResolutionClient.send(command); + console.log("Schema mapping deleted successfully."); + } catch (caught) { + if (caught instanceof ConflictException) { + console.error( + `The schema ${data.inputs.schemaNameCSV} can't be deleted because it is associated with workflow ${data.inputs.workflowName}, which is still running. Please confirm this workflow is finished in the AWS Management Console, then delete it manually.`, + ); + throw caught; + } + } + }, + { + skipWhen: (/** @type {State} */ state) => + state.confirmDeleteResources === "", + }, +); + +const goodbye = new ScenarioOutput( + "goodbye", + "Thank you for checking out the Amazon Location Service Use demo. We hope you " + + "learned something new, or got some inspiration for your own apps today!" + + " For more Amazon Location Services examples in different programming languages, have a look at: " + + "https://docs.aws.amazon.com/code-library/latest/ug/location_code_examples.html", +); + +const myScenario = new Scenario("Entity Resolution Basics Scenario", [ + greet, + pressEnter, + displayBuildCloudFormationStack, + sdkBuildCloudFormationStack, + pressEnter, + displayCreateSchemaMapping, + sdkCreateSchemaMapping, + pressEnter, + displayCreateMatchingWorkflow, + sdkCreateMatchingWorkflow, + pressEnter, + displayMatchingJobOfWorkflow, + sdkMatchingJobOfWorkflow, + pressEnter, + displayGetDetailsforJob, + sdkGetDetailsforJob, + pressEnter, + displayGetSchemaMappingJson, + sdkGetSchemaMappingJson, + pressEnter, + displayListSchemaMappings, + sdkListSchemaMappings, + pressEnter, + displayTagTheJsonSchema, + sdkTagTheJsonSchema, + pressEnter, + displayGetJobInfo, + pressEnter, + displayDeleteResources, + pressEnter, + sdkDeleteResources, + pressEnter, + goodbye, +]); + +/** @type {{ stepHandlerOptions: StepHandlerOptions }} */ +export const main = async (stepHandlerOptions) => { + await myScenario.run(stepHandlerOptions); +}; + +// Invoke main function if this file was run directly. +if (process.argv[1] === fileURLToPath(import.meta.url)) { + const { values } = parseArgs({ + options: { + yes: { + type: "boolean", + short: "y", + }, + }, + }); + main({ confirmAll: values.yes }); +} +// snippet-end:[entity-resolution.JavaScriptv3.scenario.basics] diff --git a/javascriptv3/example_code/entityresolution/tests/check-workflow-status.integration.test.js b/javascriptv3/example_code/entityresolution/tests/check-workflow-status.integration.test.js new file mode 100644 index 00000000000..eacfabd77e1 --- /dev/null +++ b/javascriptv3/example_code/entityresolution/tests/check-workflow-status.integration.test.js @@ -0,0 +1,59 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { describe, it } from "vitest"; +import { main } from "../actions/check-workflow-status.js"; +import data from "../inputs.json"; + +describe("test check-workflow-status", () => { + it( + "should not re-throw service exceptions", + async () => { + await main({ + workflowName: `${data.inputs.workflowName}`, + jobId: `${data.inputs.jobId}`, + }); + }, + { timeout: 600000 }, + ); +}); + +/* +{ + roleArn: `${data.inputs.roleArn}`, + workflowName: `${data.inputs.workflowName}`, + description: "Created by using the AWS SDK for JavaScript (v3).", + inputSourceConfig: [ + { + inputSourceARN: `${data.inputs.JSONinputSourceARN}`, + schemaName: `${data.inputs.schemaNameJson}`, + applyNormalization: false, + }, + { + inputSourceARN: `${data.inputs.CSVinputSourceARN}`, + schemaName: `${data.inputs.schemaNameCSV}`, + applyNormalization: false, + }, + ], + outputSourceConfig: [ + { + outputS3Path: `s3://" + ${data.inputs.bucketName} + "/eroutput`, + output: [ + { + name: "id", + }, + { + name: "name", + }, + { + name: "email", + }, + { + name: "phone", + }, + ], + applyNormalization: false, + }, + ], + resolutionTechniques: { resolutionType: "ML_MATCHING" }, + }*/ diff --git a/javascriptv3/example_code/entityresolution/tests/create-schema-mapping.integration.test.js b/javascriptv3/example_code/entityresolution/tests/create-schema-mapping.integration.test.js new file mode 100644 index 00000000000..dbe17576111 --- /dev/null +++ b/javascriptv3/example_code/entityresolution/tests/create-schema-mapping.integration.test.js @@ -0,0 +1,32 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { describe, it } from "vitest"; +import { main } from "../actions/delete-matching-workflow.js"; +import data from "../inputs.json"; + +describe("test delete-matching-workflow", () => { + it( + "should not re-throw service exceptions", + async () => { + await main({ + schemaName: `${data.inputs.schemaNameJson}`, + mappedInputFields: [ + { + fieldName: "id", + type: "UNIQUE_ID", + }, + { + fieldName: "name", + type: "NAME", + }, + { + fieldName: "email", + type: "EMAIL_ADDRESS", + }, + ], + }); + }, + { timeout: 600000 }, + ); +}); diff --git a/javascriptv3/example_code/entityresolution/tests/delete-matching-workflow.integration.test.js b/javascriptv3/example_code/entityresolution/tests/delete-matching-workflow.integration.test.js new file mode 100644 index 00000000000..5ac231066a2 --- /dev/null +++ b/javascriptv3/example_code/entityresolution/tests/delete-matching-workflow.integration.test.js @@ -0,0 +1,18 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { describe, it } from "vitest"; +import { main } from "../actions/delete-matching-workflow.js"; +import data from "../inputs.json"; + +describe("test delete-matching-workflow", () => { + it( + "should not re-throw service exceptions", + async () => { + await main({ + workflowName: `${data.inputs.workflowName}`, + }); + }, + { timeout: 600000 }, + ); +}); diff --git a/javascriptv3/example_code/entityresolution/tests/delete-schema-mapping.integration.test.js b/javascriptv3/example_code/entityresolution/tests/delete-schema-mapping.integration.test.js new file mode 100644 index 00000000000..168e76af7dd --- /dev/null +++ b/javascriptv3/example_code/entityresolution/tests/delete-schema-mapping.integration.test.js @@ -0,0 +1,18 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { describe, it } from "vitest"; +import { main } from "../actions/delete-schema-mapping.js"; +import data from "../inputs.json"; + +describe("test delete-schema-mapping", () => { + it( + "should not re-throw service exceptions", + async () => { + await main({ + schemaName: `${data.inputs.schemaNameJson}`, + }); + }, + { timeout: 600000 }, + ); +}); diff --git a/javascriptv3/example_code/entityresolution/tests/entity-resolution-basics.integration.test.js b/javascriptv3/example_code/entityresolution/tests/entity-resolution-basics.integration.test.js new file mode 100644 index 00000000000..abd5e689458 --- /dev/null +++ b/javascriptv3/example_code/entityresolution/tests/entity-resolution-basics.integration.test.js @@ -0,0 +1,15 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { describe, it } from "vitest"; +import { main } from "../scenarios/entity-resolution-basics.js"; + +describe("Entity Resolution basic scenario", () => { + it( + "should run without error", + async () => { + await main({ confirmAll: true }); + }, + { timeout: 600000 }, + ); +}); diff --git a/javascriptv3/example_code/entityresolution/tests/get-matching-job.integration.test.js b/javascriptv3/example_code/entityresolution/tests/get-matching-job.integration.test.js new file mode 100644 index 00000000000..b6fdffcbf11 --- /dev/null +++ b/javascriptv3/example_code/entityresolution/tests/get-matching-job.integration.test.js @@ -0,0 +1,19 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { describe, it } from "vitest"; +import { main } from "../actions/get-matching-job.js"; +import data from "../inputs.json"; + +describe("test get-matching-job", () => { + it( + "should not re-throw service exceptions", + async () => { + await main({ + workflowName: `${data.inputs.workflowName}`, + jobId: `${data.inputs.jobId}`, + }); + }, + { timeout: 600000 }, + ); +}); diff --git a/javascriptv3/example_code/entityresolution/tests/hello.integration.test.js b/javascriptv3/example_code/entityresolution/tests/hello.integration.test.js new file mode 100644 index 00000000000..e1073db1030 --- /dev/null +++ b/javascriptv3/example_code/entityresolution/tests/hello.integration.test.js @@ -0,0 +1,15 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { describe, it } from "vitest"; +import { main } from "../hello.js"; + +describe("test entity-resolution hello", () => { + it( + "should not re-throw service exceptions", + async () => { + await main({}); + }, + { timeout: 600000 }, + ); +}); diff --git a/javascriptv3/example_code/entityresolution/tests/list-schema-mappings.integration.test.js b/javascriptv3/example_code/entityresolution/tests/list-schema-mappings.integration.test.js new file mode 100644 index 00000000000..4d32af31e06 --- /dev/null +++ b/javascriptv3/example_code/entityresolution/tests/list-schema-mappings.integration.test.js @@ -0,0 +1,19 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { describe, it } from "vitest"; +import { main } from "../actions/list-schema-mappings.js"; +import data from "../inputs.json"; + +describe("test list-schema-mappings", () => { + it( + "should not re-throw service exceptions", + async () => { + await main({ + workflowName: `${data.inputs.workflowName}`, + jobId: `${data.inputs.jobId}`, + }); + }, + { timeout: 600000 }, + ); +}); diff --git a/resources/cfn/entity-resolution-basics/entity-resolution-basics-template.yml b/resources/cfn/entity-resolution-basics/entity-resolution-basics-template.yml new file mode 100644 index 00000000000..4c106c05881 --- /dev/null +++ b/resources/cfn/entity-resolution-basics/entity-resolution-basics-template.yml @@ -0,0 +1,262 @@ +Resources: + ErBucket6EA35F9D: + Type: AWS::S3::Bucket + Properties: + BucketName: erbucketf684533d2680435fa99d24b1bdaf5179 + UpdateReplacePolicy: Delete + DeletionPolicy: Delete + Metadata: + aws:cdk:path: EntityResolutionCdkStack/ErBucket/Resource + GlueDatabase: + Type: AWS::Glue::Database + Properties: + CatalogId: + Ref: AWS::AccountId + DatabaseInput: + Name: entity_resolution_db + Metadata: + aws:cdk:path: EntityResolutionCdkStack/GlueDatabase + jsongluetable: + Type: AWS::Glue::Table + Properties: + CatalogId: + Ref: AWS::AccountId + DatabaseName: + Ref: GlueDatabase + TableInput: + Name: jsongluetable + StorageDescriptor: + Columns: + - Name: id + Type: string + - Name: name + Type: string + - Name: email + Type: string + InputFormat: org.apache.hadoop.mapred.TextInputFormat + Location: + Fn::Join: + - "" + - - s3:// + - Ref: ErBucket6EA35F9D + - /jsonData/ + OutputFormat: org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat + SerdeInfo: + Parameters: + serialization.format: "1" + SerializationLibrary: org.openx.data.jsonserde.JsonSerDe + TableType: EXTERNAL_TABLE + DependsOn: + - GlueDatabase + Metadata: + aws:cdk:path: EntityResolutionCdkStack/jsongluetable + csvgluetable: + Type: AWS::Glue::Table + Properties: + CatalogId: + Ref: AWS::AccountId + DatabaseName: + Ref: GlueDatabase + TableInput: + Name: csvgluetable + StorageDescriptor: + Columns: + - Name: id + Type: string + - Name: name + Type: string + - Name: email + Type: string + - Name: phone + Type: string + InputFormat: org.apache.hadoop.mapred.TextInputFormat + Location: + Fn::Join: + - "" + - - s3:// + - Ref: ErBucket6EA35F9D + - /csvData/ + OutputFormat: org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat + SerdeInfo: + Parameters: + serialization.format: "1" + SerializationLibrary: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe + TableType: EXTERNAL_TABLE + DependsOn: + - GlueDatabase + Metadata: + aws:cdk:path: EntityResolutionCdkStack/csvgluetable + EntityResolutionRoleB51A51D3: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + Service: entityresolution.amazonaws.com + Version: "2012-10-17" + ManagedPolicyArns: + - Fn::Join: + - "" + - - "arn:" + - Ref: AWS::Partition + - :iam::aws:policy/AmazonS3FullAccess + - Fn::Join: + - "" + - - "arn:" + - Ref: AWS::Partition + - :iam::aws:policy/AWSEntityResolutionConsoleFullAccess + - Fn::Join: + - "" + - - "arn:" + - Ref: AWS::Partition + - :iam::aws:policy/AWSGlueConsoleFullAccess + - Fn::Join: + - "" + - - "arn:" + - Ref: AWS::Partition + - :iam::aws:policy/service-role/AWSGlueServiceRole + Metadata: + aws:cdk:path: EntityResolutionCdkStack/EntityResolutionRole/Resource + EntityResolutionRoleDefaultPolicy586C8066: + Type: AWS::IAM::Policy + Properties: + PolicyDocument: + Statement: + - Action: + - entityresolution:GetMatchingWorkflow + - entityresolution:StartMatchingWorkflow + Effect: Allow + Resource: "*" + Version: "2012-10-17" + PolicyName: EntityResolutionRoleDefaultPolicy586C8066 + Roles: + - Ref: EntityResolutionRoleB51A51D3 + Metadata: + aws:cdk:path: EntityResolutionCdkStack/EntityResolutionRole/DefaultPolicy/Resource + CDKMetadata: + Type: AWS::CDK::Metadata + Properties: + Analytics: v2:deflate64:H4sIAAAAAAAA/02MzQ7CIBCEn6V3WPuTvoD15EVTvZstRbOWgimgMYR3t4WLp5n5ZjI1VE0LZYEfy8U4cUUDhItDMbEV3YJtIOy9mKRj3V1nF9lDeQlhBQd0OKCVW3nFQcnICGcIvVGJJT0bReK7xexiZL20xi8ibU7evXy6/6ed0SM5MjqyI75xV1dQQls8LRFfvHY0S+iz/gCPIXoRxAAAAA== + Metadata: + aws:cdk:path: EntityResolutionCdkStack/CDKMetadata/Default + Condition: CDKMetadataAvailable +Outputs: + EntityResolutionRoleArn: + Description: The ARN of the EntityResolution Role + Value: + Fn::GetAtt: + - EntityResolutionRoleB51A51D3 + - Arn + JsonErGlueTableArn: + Description: The ARN of the Json Glue Table + Value: + Fn::Join: + - "" + - - "arn:aws:glue:" + - Ref: AWS::Region + - ":" + - Ref: AWS::AccountId + - :table/ + - Ref: GlueDatabase + - /jsongluetable + CsvErGlueTableArn: + Description: The ARN of the CSV Glue Table + Value: + Fn::Join: + - "" + - - "arn:aws:glue:" + - Ref: AWS::Region + - ":" + - Ref: AWS::AccountId + - :table/ + - Ref: GlueDatabase + - /csvgluetable + GlueDataBucketName: + Description: The name of the Glue Data Bucket + Value: + Ref: ErBucket6EA35F9D +Conditions: + CDKMetadataAvailable: + Fn::Or: + - Fn::Or: + - Fn::Equals: + - Ref: AWS::Region + - af-south-1 + - Fn::Equals: + - Ref: AWS::Region + - ap-east-1 + - Fn::Equals: + - Ref: AWS::Region + - ap-northeast-1 + - Fn::Equals: + - Ref: AWS::Region + - ap-northeast-2 + - Fn::Equals: + - Ref: AWS::Region + - ap-south-1 + - Fn::Equals: + - Ref: AWS::Region + - ap-southeast-1 + - Fn::Equals: + - Ref: AWS::Region + - ap-southeast-2 + - Fn::Equals: + - Ref: AWS::Region + - ca-central-1 + - Fn::Equals: + - Ref: AWS::Region + - cn-north-1 + - Fn::Equals: + - Ref: AWS::Region + - cn-northwest-1 + - Fn::Or: + - Fn::Equals: + - Ref: AWS::Region + - eu-central-1 + - Fn::Equals: + - Ref: AWS::Region + - eu-north-1 + - Fn::Equals: + - Ref: AWS::Region + - eu-south-1 + - Fn::Equals: + - Ref: AWS::Region + - eu-west-1 + - Fn::Equals: + - Ref: AWS::Region + - eu-west-2 + - Fn::Equals: + - Ref: AWS::Region + - eu-west-3 + - Fn::Equals: + - Ref: AWS::Region + - il-central-1 + - Fn::Equals: + - Ref: AWS::Region + - me-central-1 + - Fn::Equals: + - Ref: AWS::Region + - me-south-1 + - Fn::Equals: + - Ref: AWS::Region + - sa-east-1 + - Fn::Or: + - Fn::Equals: + - Ref: AWS::Region + - us-east-1 + - Fn::Equals: + - Ref: AWS::Region + - us-east-2 + - Fn::Equals: + - Ref: AWS::Region + - us-west-1 + - Fn::Equals: + - Ref: AWS::Region + - us-west-2 +Parameters: + BootstrapVersion: + Type: AWS::SSM::Parameter::Value + Default: /cdk-bootstrap/hnb659fds/version + Description: Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]