From 963b78de54e6f1a656b9439f375c4a7e29a4c5f2 Mon Sep 17 00:00:00 2001 From: Norbert Funke Date: Fri, 29 Sep 2023 14:46:50 -0400 Subject: [PATCH 1/4] split java and python, uploaded parquet writer --- .../multithreaded-writer/.gitignore | 0 .../{ => java}/multithreaded-writer/README.md | 0 .../SampleLambdaFromS3CsvIngestion/README.md | 0 .../deployment/.gitignore | 0 .../deployment/1-create-bucket.sh | 0 .../deployment/2-build-upload.sh | 0 .../deployment/cloudformation-lambda.yaml | 0 .../SampleLambdaFromS3CsvIngestion/pom.xml | 0 .../sample/lambda/EnvVariablesHelper.java | 0 .../amazonaws/sample/lambda/EventInfo.java | 0 .../com/amazonaws/sample/lambda/Handler.java | 0 .../amazonaws/sample/lambda/HandlerState.java | 0 .../src/main/resources/log4j2.xml | 0 .../amazonaws/sample/lambda/HandlerTest.java | 0 .../SampleLocalCsvIngestion/README.md | 0 .../SampleLocalCsvIngestion/pom.xml | 0 .../amazonaws/sample/csv/ingestion/Main.java | 0 .../csv/ingestion/SampleCsvIngestion.java | 0 .../sample/csv/mapping/SampleCsvMapper.java | 0 .../sample/csv/mapping/SampleCsvRow.java | 0 .../src/main/resources/log4j2.xml | 0 .../src/main/resources/sample_withHeader.csv | 0 .../TimestreamMultithreadedWriter/pom.xml | 0 .../multithreaded/TimestreamWriter.java | 0 .../multithreaded/TimestreamWriterConfig.java | 0 .../multithreaded/TimestreamWriterImpl.java | 0 .../multithreaded/TimestreamWriterWorker.java | 0 .../metrics/TimestreamInsertionMetrics.java | 0 .../metrics/TimestreamWriterMetrics.java | 0 .../util/LogMetricsPublisher.java | 0 .../util/TimestreamInitializer.java | 0 tools/{ => java}/multithreaded-writer/pom.xml | 0 ...sample-lambda-from-s3-csv-ingestion.drawio | 0 .../sample-lambda-from-s3-csv-ingestion.png | Bin .../sample-local-csv-ingestion-diagram.drawio | 0 .../sample-local-csv-ingestion-diagram.png | Bin ...stream-multithreaded-writer-diagram.drawio | 0 ...imestream-multithreaded-writer-diagram.png | Bin .../continuous-ingestor/README.md | 0 .../continuous-ingestor/TestRunbook.ipynb | 0 .../continuous-ingestor/__init__.py | 0 .../continuous-ingestor/requirements.txt | 0 .../continuous-ingestor/sinsawsnr.png | Bin ...le_continuous_data_ingestor_application.py | 0 tools/{ => python}/kinesis_ingestor/README.md | 0 .../{ => python}/kinesis_ingestor/__init__.py | 0 .../timestream_kinesis_data_gen.py | 0 tools/python/parquet-writer/README.md | 92 +++++++ .../parquet_multi_process_lambda_function.py | 251 ++++++++++++++++++ tools/python/parquet-writer/value.parquet | Bin 0 -> 103283 bytes .../perf-scale-workload/README.md | 0 .../perf-scale-workload/config.ini | 0 .../perf-scale-workload/config_row_count.ini | 0 .../continuous_ingester.py | 0 .../devops_cleanup_resources.py | 0 .../devops_ingestion_driver.py | 0 .../devops_query_driver.py | 0 .../{ => python}/perf-scale-workload/model.py | 0 .../perf-scale-workload/query_executer.py | 0 .../query_execution_utils.py | 0 .../perf-scale-workload/requirements.txt | 0 .../perf-scale-workload/summarize_results.py | 0 .../perf-scale-workload/timestreamquery.py | 0 .../perf-scale-workload/timestreamwrite.py | 0 64 files changed, 343 insertions(+) rename tools/{ => java}/multithreaded-writer/.gitignore (100%) rename tools/{ => java}/multithreaded-writer/README.md (100%) rename tools/{ => java}/multithreaded-writer/SampleLambdaFromS3CsvIngestion/README.md (100%) rename tools/{ => java}/multithreaded-writer/SampleLambdaFromS3CsvIngestion/deployment/.gitignore (100%) rename tools/{ => java}/multithreaded-writer/SampleLambdaFromS3CsvIngestion/deployment/1-create-bucket.sh (100%) rename tools/{ => java}/multithreaded-writer/SampleLambdaFromS3CsvIngestion/deployment/2-build-upload.sh (100%) rename tools/{ => java}/multithreaded-writer/SampleLambdaFromS3CsvIngestion/deployment/cloudformation-lambda.yaml (100%) rename tools/{ => java}/multithreaded-writer/SampleLambdaFromS3CsvIngestion/pom.xml (100%) rename tools/{ => java}/multithreaded-writer/SampleLambdaFromS3CsvIngestion/src/main/java/com/amazonaws/sample/lambda/EnvVariablesHelper.java (100%) rename tools/{ => java}/multithreaded-writer/SampleLambdaFromS3CsvIngestion/src/main/java/com/amazonaws/sample/lambda/EventInfo.java (100%) rename tools/{ => java}/multithreaded-writer/SampleLambdaFromS3CsvIngestion/src/main/java/com/amazonaws/sample/lambda/Handler.java (100%) rename tools/{ => java}/multithreaded-writer/SampleLambdaFromS3CsvIngestion/src/main/java/com/amazonaws/sample/lambda/HandlerState.java (100%) rename tools/{ => java}/multithreaded-writer/SampleLambdaFromS3CsvIngestion/src/main/resources/log4j2.xml (100%) rename tools/{ => java}/multithreaded-writer/SampleLambdaFromS3CsvIngestion/src/test/java/com/amazonaws/sample/lambda/HandlerTest.java (100%) rename tools/{ => java}/multithreaded-writer/SampleLocalCsvIngestion/README.md (100%) rename tools/{ => java}/multithreaded-writer/SampleLocalCsvIngestion/pom.xml (100%) rename tools/{ => java}/multithreaded-writer/SampleLocalCsvIngestion/src/main/java/com/amazonaws/sample/csv/ingestion/Main.java (100%) rename tools/{ => java}/multithreaded-writer/SampleLocalCsvIngestion/src/main/java/com/amazonaws/sample/csv/ingestion/SampleCsvIngestion.java (100%) rename tools/{ => java}/multithreaded-writer/SampleLocalCsvIngestion/src/main/java/com/amazonaws/sample/csv/mapping/SampleCsvMapper.java (100%) rename tools/{ => java}/multithreaded-writer/SampleLocalCsvIngestion/src/main/java/com/amazonaws/sample/csv/mapping/SampleCsvRow.java (100%) rename tools/{ => java}/multithreaded-writer/SampleLocalCsvIngestion/src/main/resources/log4j2.xml (100%) rename tools/{ => java}/multithreaded-writer/SampleLocalCsvIngestion/src/main/resources/sample_withHeader.csv (100%) rename tools/{ => java}/multithreaded-writer/TimestreamMultithreadedWriter/pom.xml (100%) rename tools/{ => java}/multithreaded-writer/TimestreamMultithreadedWriter/src/main/java/com/amazonaws/sample/timestream/multithreaded/TimestreamWriter.java (100%) rename tools/{ => java}/multithreaded-writer/TimestreamMultithreadedWriter/src/main/java/com/amazonaws/sample/timestream/multithreaded/TimestreamWriterConfig.java (100%) rename tools/{ => java}/multithreaded-writer/TimestreamMultithreadedWriter/src/main/java/com/amazonaws/sample/timestream/multithreaded/TimestreamWriterImpl.java (100%) rename tools/{ => java}/multithreaded-writer/TimestreamMultithreadedWriter/src/main/java/com/amazonaws/sample/timestream/multithreaded/TimestreamWriterWorker.java (100%) rename tools/{ => java}/multithreaded-writer/TimestreamMultithreadedWriter/src/main/java/com/amazonaws/sample/timestream/multithreaded/metrics/TimestreamInsertionMetrics.java (100%) rename tools/{ => java}/multithreaded-writer/TimestreamMultithreadedWriter/src/main/java/com/amazonaws/sample/timestream/multithreaded/metrics/TimestreamWriterMetrics.java (100%) rename tools/{ => java}/multithreaded-writer/TimestreamMultithreadedWriter/src/main/java/com/amazonaws/sample/timestream/multithreaded/util/LogMetricsPublisher.java (100%) rename tools/{ => java}/multithreaded-writer/TimestreamMultithreadedWriter/src/main/java/com/amazonaws/sample/timestream/multithreaded/util/TimestreamInitializer.java (100%) rename tools/{ => java}/multithreaded-writer/pom.xml (100%) rename tools/{ => java}/multithreaded-writer/sample-lambda-from-s3-csv-ingestion.drawio (100%) rename tools/{ => java}/multithreaded-writer/sample-lambda-from-s3-csv-ingestion.png (100%) rename tools/{ => java}/multithreaded-writer/sample-local-csv-ingestion-diagram.drawio (100%) rename tools/{ => java}/multithreaded-writer/sample-local-csv-ingestion-diagram.png (100%) rename tools/{ => java}/multithreaded-writer/timestream-multithreaded-writer-diagram.drawio (100%) rename tools/{ => java}/multithreaded-writer/timestream-multithreaded-writer-diagram.png (100%) rename tools/{ => python}/continuous-ingestor/README.md (100%) rename tools/{ => python}/continuous-ingestor/TestRunbook.ipynb (100%) rename tools/{ => python}/continuous-ingestor/__init__.py (100%) rename tools/{ => python}/continuous-ingestor/requirements.txt (100%) rename tools/{ => python}/continuous-ingestor/sinsawsnr.png (100%) rename tools/{ => python}/continuous-ingestor/timestream_sample_continuous_data_ingestor_application.py (100%) rename tools/{ => python}/kinesis_ingestor/README.md (100%) rename tools/{ => python}/kinesis_ingestor/__init__.py (100%) rename tools/{ => python}/kinesis_ingestor/timestream_kinesis_data_gen.py (100%) create mode 100644 tools/python/parquet-writer/README.md create mode 100644 tools/python/parquet-writer/parquet_multi_process_lambda_function.py create mode 100644 tools/python/parquet-writer/value.parquet rename tools/{ => python}/perf-scale-workload/README.md (100%) rename tools/{ => python}/perf-scale-workload/config.ini (100%) rename tools/{ => python}/perf-scale-workload/config_row_count.ini (100%) rename tools/{ => python}/perf-scale-workload/continuous_ingester.py (100%) rename tools/{ => python}/perf-scale-workload/devops_cleanup_resources.py (100%) rename tools/{ => python}/perf-scale-workload/devops_ingestion_driver.py (100%) rename tools/{ => python}/perf-scale-workload/devops_query_driver.py (100%) rename tools/{ => python}/perf-scale-workload/model.py (100%) rename tools/{ => python}/perf-scale-workload/query_executer.py (100%) rename tools/{ => python}/perf-scale-workload/query_execution_utils.py (100%) rename tools/{ => python}/perf-scale-workload/requirements.txt (100%) rename tools/{ => python}/perf-scale-workload/summarize_results.py (100%) rename tools/{ => python}/perf-scale-workload/timestreamquery.py (100%) rename tools/{ => python}/perf-scale-workload/timestreamwrite.py (100%) diff --git a/tools/multithreaded-writer/.gitignore b/tools/java/multithreaded-writer/.gitignore similarity index 100% rename from tools/multithreaded-writer/.gitignore rename to tools/java/multithreaded-writer/.gitignore diff --git a/tools/multithreaded-writer/README.md b/tools/java/multithreaded-writer/README.md similarity index 100% rename from tools/multithreaded-writer/README.md rename to tools/java/multithreaded-writer/README.md diff --git a/tools/multithreaded-writer/SampleLambdaFromS3CsvIngestion/README.md b/tools/java/multithreaded-writer/SampleLambdaFromS3CsvIngestion/README.md similarity index 100% rename from tools/multithreaded-writer/SampleLambdaFromS3CsvIngestion/README.md rename to tools/java/multithreaded-writer/SampleLambdaFromS3CsvIngestion/README.md diff --git a/tools/multithreaded-writer/SampleLambdaFromS3CsvIngestion/deployment/.gitignore b/tools/java/multithreaded-writer/SampleLambdaFromS3CsvIngestion/deployment/.gitignore similarity index 100% rename from tools/multithreaded-writer/SampleLambdaFromS3CsvIngestion/deployment/.gitignore rename to tools/java/multithreaded-writer/SampleLambdaFromS3CsvIngestion/deployment/.gitignore diff --git a/tools/multithreaded-writer/SampleLambdaFromS3CsvIngestion/deployment/1-create-bucket.sh b/tools/java/multithreaded-writer/SampleLambdaFromS3CsvIngestion/deployment/1-create-bucket.sh similarity index 100% rename from tools/multithreaded-writer/SampleLambdaFromS3CsvIngestion/deployment/1-create-bucket.sh rename to tools/java/multithreaded-writer/SampleLambdaFromS3CsvIngestion/deployment/1-create-bucket.sh diff --git a/tools/multithreaded-writer/SampleLambdaFromS3CsvIngestion/deployment/2-build-upload.sh b/tools/java/multithreaded-writer/SampleLambdaFromS3CsvIngestion/deployment/2-build-upload.sh similarity index 100% rename from tools/multithreaded-writer/SampleLambdaFromS3CsvIngestion/deployment/2-build-upload.sh rename to tools/java/multithreaded-writer/SampleLambdaFromS3CsvIngestion/deployment/2-build-upload.sh diff --git a/tools/multithreaded-writer/SampleLambdaFromS3CsvIngestion/deployment/cloudformation-lambda.yaml b/tools/java/multithreaded-writer/SampleLambdaFromS3CsvIngestion/deployment/cloudformation-lambda.yaml similarity index 100% rename from tools/multithreaded-writer/SampleLambdaFromS3CsvIngestion/deployment/cloudformation-lambda.yaml rename to tools/java/multithreaded-writer/SampleLambdaFromS3CsvIngestion/deployment/cloudformation-lambda.yaml diff --git a/tools/multithreaded-writer/SampleLambdaFromS3CsvIngestion/pom.xml b/tools/java/multithreaded-writer/SampleLambdaFromS3CsvIngestion/pom.xml similarity index 100% rename from tools/multithreaded-writer/SampleLambdaFromS3CsvIngestion/pom.xml rename to tools/java/multithreaded-writer/SampleLambdaFromS3CsvIngestion/pom.xml diff --git a/tools/multithreaded-writer/SampleLambdaFromS3CsvIngestion/src/main/java/com/amazonaws/sample/lambda/EnvVariablesHelper.java b/tools/java/multithreaded-writer/SampleLambdaFromS3CsvIngestion/src/main/java/com/amazonaws/sample/lambda/EnvVariablesHelper.java similarity index 100% rename from tools/multithreaded-writer/SampleLambdaFromS3CsvIngestion/src/main/java/com/amazonaws/sample/lambda/EnvVariablesHelper.java rename to tools/java/multithreaded-writer/SampleLambdaFromS3CsvIngestion/src/main/java/com/amazonaws/sample/lambda/EnvVariablesHelper.java diff --git a/tools/multithreaded-writer/SampleLambdaFromS3CsvIngestion/src/main/java/com/amazonaws/sample/lambda/EventInfo.java b/tools/java/multithreaded-writer/SampleLambdaFromS3CsvIngestion/src/main/java/com/amazonaws/sample/lambda/EventInfo.java similarity index 100% rename from tools/multithreaded-writer/SampleLambdaFromS3CsvIngestion/src/main/java/com/amazonaws/sample/lambda/EventInfo.java rename to tools/java/multithreaded-writer/SampleLambdaFromS3CsvIngestion/src/main/java/com/amazonaws/sample/lambda/EventInfo.java diff --git a/tools/multithreaded-writer/SampleLambdaFromS3CsvIngestion/src/main/java/com/amazonaws/sample/lambda/Handler.java b/tools/java/multithreaded-writer/SampleLambdaFromS3CsvIngestion/src/main/java/com/amazonaws/sample/lambda/Handler.java similarity index 100% rename from tools/multithreaded-writer/SampleLambdaFromS3CsvIngestion/src/main/java/com/amazonaws/sample/lambda/Handler.java rename to tools/java/multithreaded-writer/SampleLambdaFromS3CsvIngestion/src/main/java/com/amazonaws/sample/lambda/Handler.java diff --git a/tools/multithreaded-writer/SampleLambdaFromS3CsvIngestion/src/main/java/com/amazonaws/sample/lambda/HandlerState.java b/tools/java/multithreaded-writer/SampleLambdaFromS3CsvIngestion/src/main/java/com/amazonaws/sample/lambda/HandlerState.java similarity index 100% rename from tools/multithreaded-writer/SampleLambdaFromS3CsvIngestion/src/main/java/com/amazonaws/sample/lambda/HandlerState.java rename to tools/java/multithreaded-writer/SampleLambdaFromS3CsvIngestion/src/main/java/com/amazonaws/sample/lambda/HandlerState.java diff --git a/tools/multithreaded-writer/SampleLambdaFromS3CsvIngestion/src/main/resources/log4j2.xml b/tools/java/multithreaded-writer/SampleLambdaFromS3CsvIngestion/src/main/resources/log4j2.xml similarity index 100% rename from tools/multithreaded-writer/SampleLambdaFromS3CsvIngestion/src/main/resources/log4j2.xml rename to tools/java/multithreaded-writer/SampleLambdaFromS3CsvIngestion/src/main/resources/log4j2.xml diff --git a/tools/multithreaded-writer/SampleLambdaFromS3CsvIngestion/src/test/java/com/amazonaws/sample/lambda/HandlerTest.java b/tools/java/multithreaded-writer/SampleLambdaFromS3CsvIngestion/src/test/java/com/amazonaws/sample/lambda/HandlerTest.java similarity index 100% rename from tools/multithreaded-writer/SampleLambdaFromS3CsvIngestion/src/test/java/com/amazonaws/sample/lambda/HandlerTest.java rename to tools/java/multithreaded-writer/SampleLambdaFromS3CsvIngestion/src/test/java/com/amazonaws/sample/lambda/HandlerTest.java diff --git a/tools/multithreaded-writer/SampleLocalCsvIngestion/README.md b/tools/java/multithreaded-writer/SampleLocalCsvIngestion/README.md similarity index 100% rename from tools/multithreaded-writer/SampleLocalCsvIngestion/README.md rename to tools/java/multithreaded-writer/SampleLocalCsvIngestion/README.md diff --git a/tools/multithreaded-writer/SampleLocalCsvIngestion/pom.xml b/tools/java/multithreaded-writer/SampleLocalCsvIngestion/pom.xml similarity index 100% rename from tools/multithreaded-writer/SampleLocalCsvIngestion/pom.xml rename to tools/java/multithreaded-writer/SampleLocalCsvIngestion/pom.xml diff --git a/tools/multithreaded-writer/SampleLocalCsvIngestion/src/main/java/com/amazonaws/sample/csv/ingestion/Main.java b/tools/java/multithreaded-writer/SampleLocalCsvIngestion/src/main/java/com/amazonaws/sample/csv/ingestion/Main.java similarity index 100% rename from tools/multithreaded-writer/SampleLocalCsvIngestion/src/main/java/com/amazonaws/sample/csv/ingestion/Main.java rename to tools/java/multithreaded-writer/SampleLocalCsvIngestion/src/main/java/com/amazonaws/sample/csv/ingestion/Main.java diff --git a/tools/multithreaded-writer/SampleLocalCsvIngestion/src/main/java/com/amazonaws/sample/csv/ingestion/SampleCsvIngestion.java b/tools/java/multithreaded-writer/SampleLocalCsvIngestion/src/main/java/com/amazonaws/sample/csv/ingestion/SampleCsvIngestion.java similarity index 100% rename from tools/multithreaded-writer/SampleLocalCsvIngestion/src/main/java/com/amazonaws/sample/csv/ingestion/SampleCsvIngestion.java rename to tools/java/multithreaded-writer/SampleLocalCsvIngestion/src/main/java/com/amazonaws/sample/csv/ingestion/SampleCsvIngestion.java diff --git a/tools/multithreaded-writer/SampleLocalCsvIngestion/src/main/java/com/amazonaws/sample/csv/mapping/SampleCsvMapper.java b/tools/java/multithreaded-writer/SampleLocalCsvIngestion/src/main/java/com/amazonaws/sample/csv/mapping/SampleCsvMapper.java similarity index 100% rename from tools/multithreaded-writer/SampleLocalCsvIngestion/src/main/java/com/amazonaws/sample/csv/mapping/SampleCsvMapper.java rename to tools/java/multithreaded-writer/SampleLocalCsvIngestion/src/main/java/com/amazonaws/sample/csv/mapping/SampleCsvMapper.java diff --git a/tools/multithreaded-writer/SampleLocalCsvIngestion/src/main/java/com/amazonaws/sample/csv/mapping/SampleCsvRow.java b/tools/java/multithreaded-writer/SampleLocalCsvIngestion/src/main/java/com/amazonaws/sample/csv/mapping/SampleCsvRow.java similarity index 100% rename from tools/multithreaded-writer/SampleLocalCsvIngestion/src/main/java/com/amazonaws/sample/csv/mapping/SampleCsvRow.java rename to tools/java/multithreaded-writer/SampleLocalCsvIngestion/src/main/java/com/amazonaws/sample/csv/mapping/SampleCsvRow.java diff --git a/tools/multithreaded-writer/SampleLocalCsvIngestion/src/main/resources/log4j2.xml b/tools/java/multithreaded-writer/SampleLocalCsvIngestion/src/main/resources/log4j2.xml similarity index 100% rename from tools/multithreaded-writer/SampleLocalCsvIngestion/src/main/resources/log4j2.xml rename to tools/java/multithreaded-writer/SampleLocalCsvIngestion/src/main/resources/log4j2.xml diff --git a/tools/multithreaded-writer/SampleLocalCsvIngestion/src/main/resources/sample_withHeader.csv b/tools/java/multithreaded-writer/SampleLocalCsvIngestion/src/main/resources/sample_withHeader.csv similarity index 100% rename from tools/multithreaded-writer/SampleLocalCsvIngestion/src/main/resources/sample_withHeader.csv rename to tools/java/multithreaded-writer/SampleLocalCsvIngestion/src/main/resources/sample_withHeader.csv diff --git a/tools/multithreaded-writer/TimestreamMultithreadedWriter/pom.xml b/tools/java/multithreaded-writer/TimestreamMultithreadedWriter/pom.xml similarity index 100% rename from tools/multithreaded-writer/TimestreamMultithreadedWriter/pom.xml rename to tools/java/multithreaded-writer/TimestreamMultithreadedWriter/pom.xml diff --git a/tools/multithreaded-writer/TimestreamMultithreadedWriter/src/main/java/com/amazonaws/sample/timestream/multithreaded/TimestreamWriter.java b/tools/java/multithreaded-writer/TimestreamMultithreadedWriter/src/main/java/com/amazonaws/sample/timestream/multithreaded/TimestreamWriter.java similarity index 100% rename from tools/multithreaded-writer/TimestreamMultithreadedWriter/src/main/java/com/amazonaws/sample/timestream/multithreaded/TimestreamWriter.java rename to tools/java/multithreaded-writer/TimestreamMultithreadedWriter/src/main/java/com/amazonaws/sample/timestream/multithreaded/TimestreamWriter.java diff --git a/tools/multithreaded-writer/TimestreamMultithreadedWriter/src/main/java/com/amazonaws/sample/timestream/multithreaded/TimestreamWriterConfig.java b/tools/java/multithreaded-writer/TimestreamMultithreadedWriter/src/main/java/com/amazonaws/sample/timestream/multithreaded/TimestreamWriterConfig.java similarity index 100% rename from tools/multithreaded-writer/TimestreamMultithreadedWriter/src/main/java/com/amazonaws/sample/timestream/multithreaded/TimestreamWriterConfig.java rename to tools/java/multithreaded-writer/TimestreamMultithreadedWriter/src/main/java/com/amazonaws/sample/timestream/multithreaded/TimestreamWriterConfig.java diff --git a/tools/multithreaded-writer/TimestreamMultithreadedWriter/src/main/java/com/amazonaws/sample/timestream/multithreaded/TimestreamWriterImpl.java b/tools/java/multithreaded-writer/TimestreamMultithreadedWriter/src/main/java/com/amazonaws/sample/timestream/multithreaded/TimestreamWriterImpl.java similarity index 100% rename from tools/multithreaded-writer/TimestreamMultithreadedWriter/src/main/java/com/amazonaws/sample/timestream/multithreaded/TimestreamWriterImpl.java rename to tools/java/multithreaded-writer/TimestreamMultithreadedWriter/src/main/java/com/amazonaws/sample/timestream/multithreaded/TimestreamWriterImpl.java diff --git a/tools/multithreaded-writer/TimestreamMultithreadedWriter/src/main/java/com/amazonaws/sample/timestream/multithreaded/TimestreamWriterWorker.java b/tools/java/multithreaded-writer/TimestreamMultithreadedWriter/src/main/java/com/amazonaws/sample/timestream/multithreaded/TimestreamWriterWorker.java similarity index 100% rename from tools/multithreaded-writer/TimestreamMultithreadedWriter/src/main/java/com/amazonaws/sample/timestream/multithreaded/TimestreamWriterWorker.java rename to tools/java/multithreaded-writer/TimestreamMultithreadedWriter/src/main/java/com/amazonaws/sample/timestream/multithreaded/TimestreamWriterWorker.java diff --git a/tools/multithreaded-writer/TimestreamMultithreadedWriter/src/main/java/com/amazonaws/sample/timestream/multithreaded/metrics/TimestreamInsertionMetrics.java b/tools/java/multithreaded-writer/TimestreamMultithreadedWriter/src/main/java/com/amazonaws/sample/timestream/multithreaded/metrics/TimestreamInsertionMetrics.java similarity index 100% rename from tools/multithreaded-writer/TimestreamMultithreadedWriter/src/main/java/com/amazonaws/sample/timestream/multithreaded/metrics/TimestreamInsertionMetrics.java rename to tools/java/multithreaded-writer/TimestreamMultithreadedWriter/src/main/java/com/amazonaws/sample/timestream/multithreaded/metrics/TimestreamInsertionMetrics.java diff --git a/tools/multithreaded-writer/TimestreamMultithreadedWriter/src/main/java/com/amazonaws/sample/timestream/multithreaded/metrics/TimestreamWriterMetrics.java b/tools/java/multithreaded-writer/TimestreamMultithreadedWriter/src/main/java/com/amazonaws/sample/timestream/multithreaded/metrics/TimestreamWriterMetrics.java similarity index 100% rename from tools/multithreaded-writer/TimestreamMultithreadedWriter/src/main/java/com/amazonaws/sample/timestream/multithreaded/metrics/TimestreamWriterMetrics.java rename to tools/java/multithreaded-writer/TimestreamMultithreadedWriter/src/main/java/com/amazonaws/sample/timestream/multithreaded/metrics/TimestreamWriterMetrics.java diff --git a/tools/multithreaded-writer/TimestreamMultithreadedWriter/src/main/java/com/amazonaws/sample/timestream/multithreaded/util/LogMetricsPublisher.java b/tools/java/multithreaded-writer/TimestreamMultithreadedWriter/src/main/java/com/amazonaws/sample/timestream/multithreaded/util/LogMetricsPublisher.java similarity index 100% rename from tools/multithreaded-writer/TimestreamMultithreadedWriter/src/main/java/com/amazonaws/sample/timestream/multithreaded/util/LogMetricsPublisher.java rename to tools/java/multithreaded-writer/TimestreamMultithreadedWriter/src/main/java/com/amazonaws/sample/timestream/multithreaded/util/LogMetricsPublisher.java diff --git a/tools/multithreaded-writer/TimestreamMultithreadedWriter/src/main/java/com/amazonaws/sample/timestream/multithreaded/util/TimestreamInitializer.java b/tools/java/multithreaded-writer/TimestreamMultithreadedWriter/src/main/java/com/amazonaws/sample/timestream/multithreaded/util/TimestreamInitializer.java similarity index 100% rename from tools/multithreaded-writer/TimestreamMultithreadedWriter/src/main/java/com/amazonaws/sample/timestream/multithreaded/util/TimestreamInitializer.java rename to tools/java/multithreaded-writer/TimestreamMultithreadedWriter/src/main/java/com/amazonaws/sample/timestream/multithreaded/util/TimestreamInitializer.java diff --git a/tools/multithreaded-writer/pom.xml b/tools/java/multithreaded-writer/pom.xml similarity index 100% rename from tools/multithreaded-writer/pom.xml rename to tools/java/multithreaded-writer/pom.xml diff --git a/tools/multithreaded-writer/sample-lambda-from-s3-csv-ingestion.drawio b/tools/java/multithreaded-writer/sample-lambda-from-s3-csv-ingestion.drawio similarity index 100% rename from tools/multithreaded-writer/sample-lambda-from-s3-csv-ingestion.drawio rename to tools/java/multithreaded-writer/sample-lambda-from-s3-csv-ingestion.drawio diff --git a/tools/multithreaded-writer/sample-lambda-from-s3-csv-ingestion.png b/tools/java/multithreaded-writer/sample-lambda-from-s3-csv-ingestion.png similarity index 100% rename from tools/multithreaded-writer/sample-lambda-from-s3-csv-ingestion.png rename to tools/java/multithreaded-writer/sample-lambda-from-s3-csv-ingestion.png diff --git a/tools/multithreaded-writer/sample-local-csv-ingestion-diagram.drawio b/tools/java/multithreaded-writer/sample-local-csv-ingestion-diagram.drawio similarity index 100% rename from tools/multithreaded-writer/sample-local-csv-ingestion-diagram.drawio rename to tools/java/multithreaded-writer/sample-local-csv-ingestion-diagram.drawio diff --git a/tools/multithreaded-writer/sample-local-csv-ingestion-diagram.png b/tools/java/multithreaded-writer/sample-local-csv-ingestion-diagram.png similarity index 100% rename from tools/multithreaded-writer/sample-local-csv-ingestion-diagram.png rename to tools/java/multithreaded-writer/sample-local-csv-ingestion-diagram.png diff --git a/tools/multithreaded-writer/timestream-multithreaded-writer-diagram.drawio b/tools/java/multithreaded-writer/timestream-multithreaded-writer-diagram.drawio similarity index 100% rename from tools/multithreaded-writer/timestream-multithreaded-writer-diagram.drawio rename to tools/java/multithreaded-writer/timestream-multithreaded-writer-diagram.drawio diff --git a/tools/multithreaded-writer/timestream-multithreaded-writer-diagram.png b/tools/java/multithreaded-writer/timestream-multithreaded-writer-diagram.png similarity index 100% rename from tools/multithreaded-writer/timestream-multithreaded-writer-diagram.png rename to tools/java/multithreaded-writer/timestream-multithreaded-writer-diagram.png diff --git a/tools/continuous-ingestor/README.md b/tools/python/continuous-ingestor/README.md similarity index 100% rename from tools/continuous-ingestor/README.md rename to tools/python/continuous-ingestor/README.md diff --git a/tools/continuous-ingestor/TestRunbook.ipynb b/tools/python/continuous-ingestor/TestRunbook.ipynb similarity index 100% rename from tools/continuous-ingestor/TestRunbook.ipynb rename to tools/python/continuous-ingestor/TestRunbook.ipynb diff --git a/tools/continuous-ingestor/__init__.py b/tools/python/continuous-ingestor/__init__.py similarity index 100% rename from tools/continuous-ingestor/__init__.py rename to tools/python/continuous-ingestor/__init__.py diff --git a/tools/continuous-ingestor/requirements.txt b/tools/python/continuous-ingestor/requirements.txt similarity index 100% rename from tools/continuous-ingestor/requirements.txt rename to tools/python/continuous-ingestor/requirements.txt diff --git a/tools/continuous-ingestor/sinsawsnr.png b/tools/python/continuous-ingestor/sinsawsnr.png similarity index 100% rename from tools/continuous-ingestor/sinsawsnr.png rename to tools/python/continuous-ingestor/sinsawsnr.png diff --git a/tools/continuous-ingestor/timestream_sample_continuous_data_ingestor_application.py b/tools/python/continuous-ingestor/timestream_sample_continuous_data_ingestor_application.py similarity index 100% rename from tools/continuous-ingestor/timestream_sample_continuous_data_ingestor_application.py rename to tools/python/continuous-ingestor/timestream_sample_continuous_data_ingestor_application.py diff --git a/tools/kinesis_ingestor/README.md b/tools/python/kinesis_ingestor/README.md similarity index 100% rename from tools/kinesis_ingestor/README.md rename to tools/python/kinesis_ingestor/README.md diff --git a/tools/kinesis_ingestor/__init__.py b/tools/python/kinesis_ingestor/__init__.py similarity index 100% rename from tools/kinesis_ingestor/__init__.py rename to tools/python/kinesis_ingestor/__init__.py diff --git a/tools/kinesis_ingestor/timestream_kinesis_data_gen.py b/tools/python/kinesis_ingestor/timestream_kinesis_data_gen.py similarity index 100% rename from tools/kinesis_ingestor/timestream_kinesis_data_gen.py rename to tools/python/kinesis_ingestor/timestream_kinesis_data_gen.py diff --git a/tools/python/parquet-writer/README.md b/tools/python/parquet-writer/README.md new file mode 100644 index 00000000..fd178b7f --- /dev/null +++ b/tools/python/parquet-writer/README.md @@ -0,0 +1,92 @@ +# multi-processing-timestream + + + +## Getting started + +To make it easy for you to get started with GitLab, here's a list of recommended next steps. + +Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)! + +## Add your files + +- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files +- [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command: + +``` +cd existing_repo +git remote add origin https://gitlab.aws.dev/wwso-timestream-ssa/multi-processing-timestream.git +git branch -M main +git push -uf origin main +``` + +## Integrate with your tools + +- [ ] [Set up project integrations](https://gitlab.aws.dev/wwso-timestream-ssa/multi-processing-timestream/-/settings/integrations) + +## Collaborate with your team + +- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/) +- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html) +- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically) +- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/) +- [ ] [Automatically merge when pipeline succeeds](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html) + +## Test and Deploy + +Use the built-in continuous integration in GitLab. + +- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html) +- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing(SAST)](https://docs.gitlab.com/ee/user/application_security/sast/) +- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html) +- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/) +- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html) + +*** + +# Editing this README + +When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thank you to [makeareadme.com](https://www.makeareadme.com/) for this template. + +## Suggestions for a good README +Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information. + +## Name +Choose a self-explaining name for your project. + +## Description +Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors. + +## Badges +On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge. + +## Visuals +Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method. + +## Installation +Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection. + +## Usage +Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README. + +## Support +Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc. + +## Roadmap +If you have ideas for releases in the future, it is a good idea to list them in the README. + +## Contributing +State if you are open to contributions and what your requirements are for accepting them. + +For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self. + +You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser. + +## Authors and acknowledgment +Show your appreciation to those who have contributed to the project. + +## License +For open source projects, say how it is licensed. + +## Project status +If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers. diff --git a/tools/python/parquet-writer/parquet_multi_process_lambda_function.py b/tools/python/parquet-writer/parquet_multi_process_lambda_function.py new file mode 100644 index 00000000..94b2352b --- /dev/null +++ b/tools/python/parquet-writer/parquet_multi_process_lambda_function.py @@ -0,0 +1,251 @@ +import random +import time +import boto3 +import datetime +import glob +import numpy as np + +import pandas as pd + +data_frame = None + +# from multiprocessing.sharedctypes import Value, Array +from multiprocessing import Process, Lock + +from botocore.config import Config + +epoch = datetime.datetime.utcfromtimestamp(0) + +def unix_time_millis(dt): + # epoch = datetime.datetime.utcfromtimestamp(0) + return int((dt - pd.Timestamp("1970-01-01")).total_seconds() * 1000.0) + +def load_parquet(folder_name): + rows = [] + + for file_name in glob.glob(folder_name + '/value.parquet'): + + df = pd.read_parquet(file_name) + print(df) + df_records = df.to_records() + + for df_record in df_records: + time = unix_time_millis(df_record['time']) + signal = df_record['signal'] + value = df_record['value'] + source = df_record['source'] + # print(df_record) + row = { + 'time': time, + 'signal': signal, + 'value': value, + 'source': source + } + rows.append(row) + + return rows + +class Generator: + INTERVAL = 0.001 # Seconds + INTERVAL_MILLI = 1 + BATCH_SIZE = 100 + + table_name = '' + database_name = '' + + def prepare_common_attributes(self): + common_attributes = { + #'Dimensions': [ + # {'Name': 'country', 'Value': COUNTRY.replace('${', '$ {')}, + # {'Name': 'country', 'Value': COUNTRY} #, + #{'Name': 'city', 'Value': CITY}, + #{'Name': 'hostname', 'Value': HOSTNAME} + #], + 'MeasureName': self.measure_name, + 'MeasureValueType': 'MULTI' + } + print(common_attributes) + #print(COUNTRY) + #self.variable_test(COUNTRY) + return common_attributes + + def prepare_record(self, current_time): + record = { + 'Time': str(current_time), + 'MeasureValues': [], + 'Dimensions':[] + } + return record + + def prepare_measure(self, measure_name, measure_value): + measure = { + 'Name': measure_name, + 'Value': str(measure_value), + 'Type': 'DOUBLE' + } + return measure + + def prepare_dimension(self, name, value): + dimension = { + 'Name': name, + 'Value': str(value) #, + #'DimensionValueType': 'VARCHAR' + } + return dimension + + def write_records(self, records, common_attributes): + try: + result = self.write_client.write_records(DatabaseName=self.database_name, + TableName=self.table_name, + CommonAttributes=common_attributes, + Records=records) + status = result['ResponseMetadata']['HTTPStatusCode'] + #print("Processed %d records. WriteRecords HTTPStatusCode: %s" % + # (len(records), status)) + except Exception as err: + print("Error:", err) + print(records) + + def unix_time_millis(self, dt): + epoch = datetime.datetime.utcfromtimestamp(0) + return (dt - epoch).total_seconds() * 1000.0 + + def write_buffer(self, buffer, common_attributes): + start_time = time.time() + total_records = 0 + for records in buffer: + elapsed_time = time.time() - start_time + self.write_records(records, common_attributes) + total_records += len(records) + if elapsed_time == 0.0: + elapsed_time = 0.00001 + rps = total_records/elapsed_time + print(f'{total_records} written rps = {rps}') + + + # User can change this based on there record dimension/measure value + def create_record(self, item): + current_time = str(item['time']) + source = item['source'] + value = item['value'] + signal = item['signal'] + + record = self.prepare_record(current_time) + + record['Dimensions'].append(self.prepare_dimension('source', source)) + record['Dimensions'].append(self.prepare_dimension('signal', signal)) + # add more Dimensions from item as needed + + record['MeasureValues'].append(self.prepare_measure('value', value)) + # append more MeasureValues as measure columns as needed + + return record + + def generate_data(self, pid, region, database_name, table_name, data): + self.data = data + + self.database_name = database_name + self.table_name = table_name + print(f'writing data to database {self.database_name} table {self.table_name}') + + session = boto3.Session(region_name=region) + self.write_client = session.client('timestream-write', config=Config( + read_timeout=20, max_pool_connections=5000, retries={'max_attempts': 10})) + + self.measure_name = 'metric-' + str(pid % 8192) + common_attributes = self.prepare_common_attributes() + + records = [] + + total_records = 0 + + launch_time = time.time() + + for item in data: + print(item) + record = self.create_record(item) + + records.append(record) + + if len(records) == self.BATCH_SIZE: + total_records += len(records) + + self.write_records(records, common_attributes) + + records = [] + + if self.INTERVAL > 0.0: + time.sleep(self.INTERVAL) + + if len(records) > 0: + total_records += len(records) + + self.write_records(records, common_attributes) + + total_time = time.time() - launch_time + + if total_time == 0: + total_time = 0.00001 + rps = total_records / total_time + print(f'Total Records in thread: {total_records:,} in {rps} rps') + + return total_records + + +def lambda_handler(event, context): + + folder_name = event['folder'] + records = load_parquet(folder_name) + + lambda_time = time.time() + + pid = 1 + + max_threads = event['threads'] + + processes = [] + record_counts = [] + + for i in range(0, max_threads): + id = i + process = Process(target=thread_handler, args=(id, event, context, records)) + process.start() + print( + f'[{pid}] process_record: Started process #{i} with pid={process.pid} to dump data chunk to timestream') + processes.append(process) + + # Wait for all processes to complete + for process in processes: + process.join() + + end_time = time.time() + total_time = end_time - lambda_time + + s_lambda_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(lambda_time)) + s_end_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(end_time)) + print(f'{s_lambda_time} - {s_end_time}') + + return + +def thread_handler(pid, event, context, records): + generator = Generator() + region = event['region'] + database = event['database'] + table = event['table'] + threads = int(event['threads']) + generator.generate_data(pid, region, database, table, records) + + return + +if __name__ == '__main__': + event = { + 'threads': 1, + 'region': 'us-east-1', + 'database': 'sandbox-w-642', + 'table': 'ingestion-parquet2', + 'folder': './' + } + context = {} + lambda_handler(event, context) + + diff --git a/tools/python/parquet-writer/value.parquet b/tools/python/parquet-writer/value.parquet new file mode 100644 index 0000000000000000000000000000000000000000..41558567d959cfc2122a27413f88643a08ae03d6 GIT binary patch literal 103283 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 literal 0 HcmV?d00001 diff --git a/tools/perf-scale-workload/README.md b/tools/python/perf-scale-workload/README.md similarity index 100% rename from tools/perf-scale-workload/README.md rename to tools/python/perf-scale-workload/README.md diff --git a/tools/perf-scale-workload/config.ini b/tools/python/perf-scale-workload/config.ini similarity index 100% rename from tools/perf-scale-workload/config.ini rename to tools/python/perf-scale-workload/config.ini diff --git a/tools/perf-scale-workload/config_row_count.ini b/tools/python/perf-scale-workload/config_row_count.ini similarity index 100% rename from tools/perf-scale-workload/config_row_count.ini rename to tools/python/perf-scale-workload/config_row_count.ini diff --git a/tools/perf-scale-workload/continuous_ingester.py b/tools/python/perf-scale-workload/continuous_ingester.py similarity index 100% rename from tools/perf-scale-workload/continuous_ingester.py rename to tools/python/perf-scale-workload/continuous_ingester.py diff --git a/tools/perf-scale-workload/devops_cleanup_resources.py b/tools/python/perf-scale-workload/devops_cleanup_resources.py similarity index 100% rename from tools/perf-scale-workload/devops_cleanup_resources.py rename to tools/python/perf-scale-workload/devops_cleanup_resources.py diff --git a/tools/perf-scale-workload/devops_ingestion_driver.py b/tools/python/perf-scale-workload/devops_ingestion_driver.py similarity index 100% rename from tools/perf-scale-workload/devops_ingestion_driver.py rename to tools/python/perf-scale-workload/devops_ingestion_driver.py diff --git a/tools/perf-scale-workload/devops_query_driver.py b/tools/python/perf-scale-workload/devops_query_driver.py similarity index 100% rename from tools/perf-scale-workload/devops_query_driver.py rename to tools/python/perf-scale-workload/devops_query_driver.py diff --git a/tools/perf-scale-workload/model.py b/tools/python/perf-scale-workload/model.py similarity index 100% rename from tools/perf-scale-workload/model.py rename to tools/python/perf-scale-workload/model.py diff --git a/tools/perf-scale-workload/query_executer.py b/tools/python/perf-scale-workload/query_executer.py similarity index 100% rename from tools/perf-scale-workload/query_executer.py rename to tools/python/perf-scale-workload/query_executer.py diff --git a/tools/perf-scale-workload/query_execution_utils.py b/tools/python/perf-scale-workload/query_execution_utils.py similarity index 100% rename from tools/perf-scale-workload/query_execution_utils.py rename to tools/python/perf-scale-workload/query_execution_utils.py diff --git a/tools/perf-scale-workload/requirements.txt b/tools/python/perf-scale-workload/requirements.txt similarity index 100% rename from tools/perf-scale-workload/requirements.txt rename to tools/python/perf-scale-workload/requirements.txt diff --git a/tools/perf-scale-workload/summarize_results.py b/tools/python/perf-scale-workload/summarize_results.py similarity index 100% rename from tools/perf-scale-workload/summarize_results.py rename to tools/python/perf-scale-workload/summarize_results.py diff --git a/tools/perf-scale-workload/timestreamquery.py b/tools/python/perf-scale-workload/timestreamquery.py similarity index 100% rename from tools/perf-scale-workload/timestreamquery.py rename to tools/python/perf-scale-workload/timestreamquery.py diff --git a/tools/perf-scale-workload/timestreamwrite.py b/tools/python/perf-scale-workload/timestreamwrite.py similarity index 100% rename from tools/perf-scale-workload/timestreamwrite.py rename to tools/python/perf-scale-workload/timestreamwrite.py From 62d44a705b4248ac0b6fd522c8f6537fc5ca1fc1 Mon Sep 17 00:00:00 2001 From: Norbert Funke Date: Fri, 29 Sep 2023 14:52:31 -0400 Subject: [PATCH 2/4] Updated links to new structure of python and java --- tools/README.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/tools/README.md b/tools/README.md index f5234ad2..e2faec2d 100644 --- a/tools/README.md +++ b/tools/README.md @@ -1,11 +1,14 @@ ## Amazon Timestream data ingestion and query tools To understand the performance and scale capabilities of Amazon Timestream, you can run the following workload: -* [Running large scale workloads with Amazon Timestream](perf-scale-workload) +* [Running large scale workloads with Amazon Timestream](python/perf-scale-workload) The following tools can be used to continuously send data into Amazon Timestream: -* [Publishing data with Amazon Kinesis](kinesis_ingestor) -* [Writing data using a multi-thread Python DevOps data generator](continuous-ingestor) +* [Publishing data with Amazon Kinesis](python/kinesis_ingestor) +* [Writing data using a multi-thread Python DevOps data generator](python/continuous-ingestor) + +The following tools show example to write common file formats: +* [Processing Apache Parquet files](python/parquet-writer) The following tool shows how to use multiple threads to write to Amazon Timestream with Java, while collecting important operational metrics. It includes samples which shows: -* [Local CSV file ingestion to Amazon Timestream](multithreaded-writer#Local-CSV-file-ingestion-to-Timestream) -* [Lambda function ingesting S3 CSV file to Amazon Timestream](multithreaded-writer#Lambda-function-ingesting-S3-CSV-file-to-Timestream) \ No newline at end of file +* [Local CSV file ingestion to Amazon Timestream](java/multithreaded-writer#Local-CSV-file-ingestion-to-Timestream) +* [Lambda function ingesting S3 CSV file to Amazon Timestream](java/multithreaded-writer#Lambda-function-ingesting-S3-CSV-file-to-Timestream) \ No newline at end of file From c5e097ca4df81de740c5f776b0d2a35b7acea0aa Mon Sep 17 00:00:00 2001 From: Norbert Funke Date: Fri, 29 Sep 2023 15:24:28 -0400 Subject: [PATCH 3/4] correct defect in multi-threading Added buffer split --- .../parquet_multi_process_lambda_function.py | 49 +++++++++---------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/tools/python/parquet-writer/parquet_multi_process_lambda_function.py b/tools/python/parquet-writer/parquet_multi_process_lambda_function.py index 94b2352b..fe016c1a 100644 --- a/tools/python/parquet-writer/parquet_multi_process_lambda_function.py +++ b/tools/python/parquet-writer/parquet_multi_process_lambda_function.py @@ -20,16 +20,23 @@ def unix_time_millis(dt): # epoch = datetime.datetime.utcfromtimestamp(0) return int((dt - pd.Timestamp("1970-01-01")).total_seconds() * 1000.0) -def load_parquet(folder_name): - rows = [] +def load_parquet(max_threads, folder_name): - for file_name in glob.glob(folder_name + '/value.parquet'): + # create buffer for each thread + buffer = [] + + for i in range(0, max_threads): + buffer.append([]) + record_count = 0 + + for file_name in glob.glob(folder_name + '/value.parquet'): df = pd.read_parquet(file_name) print(df) df_records = df.to_records() for df_record in df_records: + buffer_index = record_count % max_threads time = unix_time_millis(df_record['time']) signal = df_record['signal'] value = df_record['value'] @@ -41,9 +48,10 @@ def load_parquet(folder_name): 'value': value, 'source': source } - rows.append(row) + buffer[buffer_index].append(row) + record_count += 1 - return rows + return buffer class Generator: INTERVAL = 0.001 # Seconds @@ -110,19 +118,6 @@ def unix_time_millis(self, dt): epoch = datetime.datetime.utcfromtimestamp(0) return (dt - epoch).total_seconds() * 1000.0 - def write_buffer(self, buffer, common_attributes): - start_time = time.time() - total_records = 0 - for records in buffer: - elapsed_time = time.time() - start_time - self.write_records(records, common_attributes) - total_records += len(records) - if elapsed_time == 0.0: - elapsed_time = 0.00001 - rps = total_records/elapsed_time - print(f'{total_records} written rps = {rps}') - - # User can change this based on there record dimension/measure value def create_record(self, item): current_time = str(item['time']) @@ -141,8 +136,8 @@ def create_record(self, item): return record - def generate_data(self, pid, region, database_name, table_name, data): - self.data = data + def generate_data(self, pid, region, database_name, table_name, buffer): + self.data = buffer[pid] self.database_name = database_name self.table_name = table_name @@ -161,8 +156,8 @@ def generate_data(self, pid, region, database_name, table_name, data): launch_time = time.time() - for item in data: - print(item) + for item in self.data: + # print(item) record = self.create_record(item) records.append(record) @@ -194,14 +189,14 @@ def generate_data(self, pid, region, database_name, table_name, data): def lambda_handler(event, context): + max_threads = event['threads'] folder_name = event['folder'] - records = load_parquet(folder_name) + records = load_parquet(max_threads, folder_name) lambda_time = time.time() pid = 1 - max_threads = event['threads'] processes = [] record_counts = [] @@ -239,10 +234,10 @@ def thread_handler(pid, event, context, records): if __name__ == '__main__': event = { - 'threads': 1, + 'threads': 4, 'region': 'us-east-1', - 'database': 'sandbox-w-642', - 'table': 'ingestion-parquet2', + 'database': 'tools-sandbox', + 'table': 'ingestion-parquet', 'folder': './' } context = {} From 905d79eaaba7781eed7cfea5cf635d2573615751 Mon Sep 17 00:00:00 2001 From: Norbert Funke Date: Fri, 29 Sep 2023 16:12:47 -0400 Subject: [PATCH 4/4] Added usage and other comments --- tools/python/parquet-writer/README.md | 160 ++++++++++++++------------ 1 file changed, 84 insertions(+), 76 deletions(-) diff --git a/tools/python/parquet-writer/README.md b/tools/python/parquet-writer/README.md index fd178b7f..bb412138 100644 --- a/tools/python/parquet-writer/README.md +++ b/tools/python/parquet-writer/README.md @@ -1,92 +1,100 @@ -# multi-processing-timestream +# Loading Apache Parquet files into Amazon Timestream +This example illustrates how to load Apache Parquet files and write the data to Amazon Timestream. Some of the characteristics are: +* Loading multiple files in a folder +* For higher ingestion speed multiple threads can be configured. The parameters are preconfigured for 4 threads ## Getting started -To make it easy for you to get started with GitLab, here's a list of recommended next steps. - -Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)! - -## Add your files - -- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files -- [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command: - -``` -cd existing_repo -git remote add origin https://gitlab.aws.dev/wwso-timestream-ssa/multi-processing-timestream.git -git branch -M main -git push -uf origin main +This example contains a sample parquet file with the following data structure: + +| Field | example content | mapping to Timestream attribute | +|---------|-----------------|---------------------------------| +| signal | data channel | Dimension | +| source | device indentifier | Dimension | +| time | Timestamp | time | +| value | example measure value | Multi Measure column | + +The python code can be modified and is able to process more than one measure in multi-measure format. +For modifying the code to your data, please change the following functions: + +## Parquet data extraction: + +### Function `load_parquet` + +This function extracts the data needed for a record and simple transformation can be done here: + +```python +def load_parquet(max_threads, folder_name): + +... + for df_record in df_records: + buffer_index = record_count % max_threads + time = unix_time_millis(df_record['time']) + signal = df_record['signal'] + value = df_record['value'] + source = df_record['source'] + # print(df_record) + row = { + 'time': time, + 'signal': signal, + 'value': value, + 'source': source + } + buffer[buffer_index].append(row) + record_count += 1 + + return buffer ``` -## Integrate with your tools - -- [ ] [Set up project integrations](https://gitlab.aws.dev/wwso-timestream-ssa/multi-processing-timestream/-/settings/integrations) - -## Collaborate with your team - -- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/) -- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html) -- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically) -- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/) -- [ ] [Automatically merge when pipeline succeeds](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html) - -## Test and Deploy - -Use the built-in continuous integration in GitLab. - -- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html) -- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing(SAST)](https://docs.gitlab.com/ee/user/application_security/sast/) -- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html) -- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/) -- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html) +### Function `create_record:` -*** +## Parquet data to Timestream record mapping: -# Editing this README -When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thank you to [makeareadme.com](https://www.makeareadme.com/) for this template. +### Function `create_record:` -## Suggestions for a good README -Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information. +This function takes the record above and maps to Amazon Timestream attributes -## Name -Choose a self-explaining name for your project. +```python + def create_record(self, item): + current_time = str(item['time']) + source = item['source'] + value = item['value'] + signal = item['signal'] -## Description -Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors. + record = self.prepare_record(current_time) -## Badges -On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge. + record['Dimensions'].append(self.prepare_dimension('source', source)) + record['Dimensions'].append(self.prepare_dimension('signal', signal)) + # add more Dimensions from item as needed -## Visuals -Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method. + record['MeasureValues'].append(self.prepare_measure('value', value)) + # append more MeasureValues as measure columns as needed -## Installation -Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection. - -## Usage -Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README. - -## Support -Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc. - -## Roadmap -If you have ideas for releases in the future, it is a good idea to list them in the README. - -## Contributing -State if you are open to contributions and what your requirements are for accepting them. - -For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self. - -You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser. - -## Authors and acknowledgment -Show your appreciation to those who have contributed to the project. - -## License -For open source projects, say how it is licensed. - -## Project status -If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers. + return record +``` +Please append more dimensions or more measure values as needed + +## Parameters to run: + +The main function allows the following parameters: + +| Parameter | Usage| +|-----------|------| +| threads | Number of threads to run, should be at least 1 | +| region | AWS Region of Timestream database | +| database | Database containing the target table | +| table | Target table | +| folder | folder that contains parquet files. A sample file is included in this example | + +```json + { + 'threads': 4, + 'region': 'us-east-1', + 'database': 'tools-sandbox', + 'table': 'ingestion-parquet', + 'folder': './' + } +``` \ No newline at end of file