From afeab6a550065e3b95faaf463154503ec3720e67 Mon Sep 17 00:00:00 2001 From: Eric Pugh Date: Fri, 15 Aug 2025 06:57:08 -0400 Subject: [PATCH 1/8] Outline of new tutorial Signed-off-by: Eric Pugh --- .../ubi/ubi-aws-managed-services-tutorial.md | 150 ++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 _search-plugins/ubi/ubi-aws-managed-services-tutorial.md diff --git a/_search-plugins/ubi/ubi-aws-managed-services-tutorial.md b/_search-plugins/ubi/ubi-aws-managed-services-tutorial.md new file mode 100644 index 0000000000..b528b9d3e7 --- /dev/null +++ b/_search-plugins/ubi/ubi-aws-managed-services-tutorial.md @@ -0,0 +1,150 @@ +--- +layout: default +title: UBI in AWS Managed Services tutorial +parent: User Behavior Insights +has_children: false +nav_order: 24 +--- + + +# UBI in AWS Managed Services Tutorial + +This tutorial walks you through the steps for collecting queries and events when you are using AWS's Managed Service for OpenSearch. At the end of this tutorial you will be able to send authenticated events to both S3 for long term storage and OpenSearch using the Curl command line tool. This sets you up for integrating UBI event collection into your applications. + +The tutorial makes the following assumptions: + +1. You are using AWS Managed Service OpenSearch version 2.19. +1. You are not using the UBI Plugin for OpenSearch, which isn't available until OpenSearch 3.1 in Managed Service. +1. You are writing UBI data to OpenSearch via [OpenSearch Ingestion](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/ingestion.html) (managed version of Data Prepper). + + +## 1. Set Up UBI OpenSearch Indexes + +Log into Managed Service OpenSearch Dashboard. We will use the DevTools console to create two indexes for storing data: `ubi_queries` and `ubi_events`. + +Navigate to **Management > Dev Tools** + +Create the overall index creation command: + +```json +PUT ubi_events +{ + "mappings": +} +``` + +You will see a syntax warning after typing this in, that's okay. + +Then, go to https://github.com/opensearch-project/user-behavior-insights/blob/main/src/main/resources/events-mapping.json and copy the entire JSON text and paste it in after the `"mappings":` line in the Dev Tools console. You will have something similar to: + +```json +PUT ubi_events +{ + "mappings": { + "properties": { + "application": { + "type": "keyword", + "ignore_above": 256 + }, + "action_name": { + "type": "keyword", + "ignore_above": 100 + }, + CUT FOR LENGTH +``` + +Go ahead and run that command and make sure it runs successfully. + +You will do the same thing for `ubi_queries`. + +```json +PUT ubi_queries +{ + "mappings": +} +``` + +This time go to https://github.com/opensearch-project/user-behavior-insights/blob/main/src/main/resources/queries-mapping.json and copy the entire JSON text and paste it in after the `"mappings":` line in the Dev Tools console. Run the command. + +> If you are using OpenSearch 3.1 or newer then the UBI Plugin is already enabled for you. Instead of manually creating the indexes you can instead use the UBI plugin to create them: +> +> ```json +> POST /_plugins/ubi/initialize +> ``` +{: .note} + +You now have the OpenSearch indexes that will recieve UBI data. + +## 2. Set up S3 Storage + +## 3. Set up OpenSearch Ingestion Pipeline + + +## 4. Test with sample events + +## Where Next? + +In OpenSearch Management, navigate to **Dashboards Management > Index patterns** or navigate using a URL, such as `http://{server}:5601/app/management/OpenSearch-dashboards/indexPatterns`. + +OpenSearch Dashboards accesses your indexes using index patterns. To visualize your users' online search behavior, you must create an index pattern in order to access the indexes that UBI creates. For more information, see [Index patterns]({{site.url}}{{site.baseurl}}/dashboards/management/index-patterns/). + +After you select **Create index pattern**, a list of indexes in your OpenSearch instance is displayed. The UBI stores may be hidden by default, so make sure to select **Include system and hidden indexes**, as shown in the following image. +![Index Patterns]({{site.url}}{{site.baseurl}}/images/ubi/index_pattern2.png) + +You can group indexes into the same data source for your dashboard using wildcards. For this tutorial you'll combine the query and event stores into the `ubi_*` pattern. + +OpenSearch Dashboards prompts you to filter on any `date` field in your schema so that you can look at things like trending queries over the last 15 minutes. However, for your first dashboard, select **I don't want to use the time filter**, as shown in the following image. +Index Patterns + + +After selecting **Create index pattern**, you're ready to start building a dashboard that displays the UBI store data. + +## 3. Create a new dashboard + +To create a new dashboard, on the top menu, select **OpenSearch Dashboards > Dashboards** and then **Create > Dashboard** > **Create new**. +If you haven't previously created a dashboard, you are presented with the option to create a new dashboard. Otherwise, previously created dashboards are displayed. + + +In the **New Visualization** window, select **Pie** to create a new pie chart. Then select the index pattern you created in step 2. + +Most visualizations require some sort of aggregate function on a bucket/facet/aggregatable field (numeric or keyword). You'll add a `Terms` aggregation to the `action_name` field so that you can view the distribution of event names. Change the **Size** to the number of slices you want to display, as shown in the following image. +![Pie Chart]({{site.url}}{{site.baseurl}}/images/ubi/pie.png) + +Save the visualization so that it's added to your new dashboard. Now that you have a visualization displayed on your dashboard, you can save the dashboard. + +## 4. Add a tag cloud visualization + +Now you'll add a word cloud for trending searches by creating a new visualization, similarly to the previous step. + +In the **New Visualization** window, select **Tag Cloud**, and then select the index pattern you created in step 2. Choose the tag cloud visualization of the terms in the `message` field where the JavaScript client logs the raw search text. Note: The true query, as processed by OpenSearch with filters, boosting, and so on, resides in the `ubi_queries` index. However, you'll view the `message` field of the `ubi_events` index, where the JavaScript client captures the text that the user actually typed. + +The following image shows the tag cloud visualization on the `message` field. +![Word Cloud]({{site.url}}{{site.baseurl}}/images/ubi/tag_cloud1.png) + +The underlying queries can be found at [SQL trending queries]({{site.url}}{{site.baseurl}}/search-plugins/ubi/sql-queries/#trending-queries). +{: .note} + + +The resulting visualization may contain different information than you're looking for. The `message` field is updated with every event, and as a result, it can contain error messages, debug messages, click information, and other unwanted data. +To view only search terms for query events, you need to add a filter to your visualization. Because during setup you provided a `message_type` of `QUERY` for each search event, you can filter by that message type to isolate the specific users' searches. To do this, select **Add filter** and then select **QUERY** in the **Edit filter** panel, as shown in the following image. +![Word Cloud]({{site.url}}{{site.baseurl}}/images/ubi/tag_cloud2.png) + +There should now be two visualizations (the pie chart and the tag cloud) displayed on your dashboard, as shown in the following image. +![UBI Dashboard]({{site.url}}{{site.baseurl}}/images/ubi/dashboard2.png) + +## 5. Add a histogram of item clicks + +Now you'll add a histogram visualization to your dashboard, similarly to the previous step. In the **New Visualization** window, select **Vertical Bar**. Then select the index pattern you created in step 2. + +Examine the `event_attributes.position.ordinal` data field. This field contains the position of the item in a list selected by the user. For the histogram visualization, the x-axis represents the ordinal number of the selected item (n). The y-axis represents the number of times that the nth item was clicked, as shown in the following image. + +![Vertical Bar Chart]({{site.url}}{{site.baseurl}}/images/ubi/histogram.png) + +## 6. Filter the displayed data + +Now you can further filter the displayed data. For example, you can see how the click position changes when a purchase occurs. Select **Add filter** and then select the `action_name:product_purchase` field, as shown in the following image. +![Product Purchase]({{site.url}}{{site.baseurl}}/images/ubi/product_purchase.png) + + +You can filter event messages containing the word `*laptop*` by adding wildcards, as shown in the following image. +![Laptop]({{site.url}}{{site.baseurl}}/images/ubi/laptop.png). From 8231aa130994b5b04eec0f1f1a4dcadde48a5404 Mon Sep 17 00:00:00 2001 From: Eric Pugh Date: Fri, 15 Aug 2025 14:07:45 -0400 Subject: [PATCH 2/8] Respond to vale Signed-off-by: Eric Pugh --- .../ubi/ubi-aws-managed-services-tutorial.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/_search-plugins/ubi/ubi-aws-managed-services-tutorial.md b/_search-plugins/ubi/ubi-aws-managed-services-tutorial.md index b528b9d3e7..707d9929cf 100644 --- a/_search-plugins/ubi/ubi-aws-managed-services-tutorial.md +++ b/_search-plugins/ubi/ubi-aws-managed-services-tutorial.md @@ -7,20 +7,20 @@ nav_order: 24 --- -# UBI in AWS Managed Services Tutorial +# UBI in AWS Managed Services tutorial -This tutorial walks you through the steps for collecting queries and events when you are using AWS's Managed Service for OpenSearch. At the end of this tutorial you will be able to send authenticated events to both S3 for long term storage and OpenSearch using the Curl command line tool. This sets you up for integrating UBI event collection into your applications. +This tutorial walks you through the steps for collecting queries and events in the UBI (User Behavior Insights) format when you are using AWS's Managed Service for OpenSearch. At the end of this tutorial you will be able to send authenticated queries and events to both S3 for long term storage and OpenSearch for immediate processing using the Curl command line tool. At the end of the tutorial you will be ready to start collecting UBI data for your applications. The tutorial makes the following assumptions: 1. You are using AWS Managed Service OpenSearch version 2.19. 1. You are not using the UBI Plugin for OpenSearch, which isn't available until OpenSearch 3.1 in Managed Service. -1. You are writing UBI data to OpenSearch via [OpenSearch Ingestion](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/ingestion.html) (managed version of Data Prepper). +1. You are writing UBI data to OpenSearch using [OpenSearch Ingestion](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/ingestion.html), the managed version of Data Prepper. -## 1. Set Up UBI OpenSearch Indexes +## 1. Set up OpenSearch indexes for UBI -Log into Managed Service OpenSearch Dashboard. We will use the DevTools console to create two indexes for storing data: `ubi_queries` and `ubi_events`. +Log into Managed Service OpenSearch Dashboard. We will use the DevTools console to create two indexes for storing data: `ubi_queries` and `ubi_events`. Navigate to **Management > Dev Tools** @@ -35,7 +35,7 @@ PUT ubi_events You will see a syntax warning after typing this in, that's okay. -Then, go to https://github.com/opensearch-project/user-behavior-insights/blob/main/src/main/resources/events-mapping.json and copy the entire JSON text and paste it in after the `"mappings":` line in the Dev Tools console. You will have something similar to: +Then, go to (https://github.com/opensearch-project/user-behavior-insights/blob/main/src/main/resources/events-mapping.json)[https://github.com/opensearch-project/user-behavior-insights/blob/main/src/main/resources/events-mapping.json] and copy the entire JSON formatted contents of the file and paste it in after the `"mappings":` line in the Dev Tools console. This will produce a complete command similar to: ```json PUT ubi_events @@ -64,16 +64,16 @@ PUT ubi_queries } ``` -This time go to https://github.com/opensearch-project/user-behavior-insights/blob/main/src/main/resources/queries-mapping.json and copy the entire JSON text and paste it in after the `"mappings":` line in the Dev Tools console. Run the command. +This time go to https://github.com/opensearch-project/user-behavior-insights/blob/main/src/main/resources/queries-mapping.json and copy the entire JSON text and paste it in after the `"mappings":` line in the Dev Tools console. Run the command. -> If you are using OpenSearch 3.1 or newer then the UBI Plugin is already enabled for you. Instead of manually creating the indexes you can instead use the UBI plugin to create them: +> If you are using OpenSearch 3.1 or newer then the UBI Plugin is already included. Instead of manually creating the indexes you can instead use the UBI plugin to create them: > > ```json > POST /_plugins/ubi/initialize > ``` {: .note} -You now have the OpenSearch indexes that will recieve UBI data. +You now have the required OpenSearch indexes to recieve UBI data from applications. ## 2. Set up S3 Storage From 092b264a384fb8d1488f125b8ab2f1cdc264d4bf Mon Sep 17 00:00:00 2001 From: Eric Pugh Date: Fri, 15 Aug 2025 17:58:50 -0400 Subject: [PATCH 3/8] record progress Signed-off-by: Eric Pugh --- .../ubi/ubi-aws-managed-services-tutorial.md | 96 +++++++------------ 1 file changed, 35 insertions(+), 61 deletions(-) diff --git a/_search-plugins/ubi/ubi-aws-managed-services-tutorial.md b/_search-plugins/ubi/ubi-aws-managed-services-tutorial.md index 707d9929cf..39d937ba0f 100644 --- a/_search-plugins/ubi/ubi-aws-managed-services-tutorial.md +++ b/_search-plugins/ubi/ubi-aws-managed-services-tutorial.md @@ -66,7 +66,7 @@ PUT ubi_queries This time go to https://github.com/opensearch-project/user-behavior-insights/blob/main/src/main/resources/queries-mapping.json and copy the entire JSON text and paste it in after the `"mappings":` line in the Dev Tools console. Run the command. -> If you are using OpenSearch 3.1 or newer then the UBI Plugin is already included. Instead of manually creating the indexes you can instead use the UBI plugin to create them: +> If you are using OpenSearch 3.0 or newer then the UBI plugin is already included. Instead of manually creating the indexes you can instead use the UBI plugin to create them: > > ```json > POST /_plugins/ubi/initialize @@ -82,69 +82,43 @@ You now have the required OpenSearch indexes to recieve UBI data from applicatio ## 4. Test with sample events -## Where Next? - -In OpenSearch Management, navigate to **Dashboards Management > Index patterns** or navigate using a URL, such as `http://{server}:5601/app/management/OpenSearch-dashboards/indexPatterns`. - -OpenSearch Dashboards accesses your indexes using index patterns. To visualize your users' online search behavior, you must create an index pattern in order to access the indexes that UBI creates. For more information, see [Index patterns]({{site.url}}{{site.baseurl}}/dashboards/management/index-patterns/). - -After you select **Create index pattern**, a list of indexes in your OpenSearch instance is displayed. The UBI stores may be hidden by default, so make sure to select **Include system and hidden indexes**, as shown in the following image. -![Index Patterns]({{site.url}}{{site.baseurl}}/images/ubi/index_pattern2.png) - -You can group indexes into the same data source for your dashboard using wildcards. For this tutorial you'll combine the query and event stores into the `ubi_*` pattern. - -OpenSearch Dashboards prompts you to filter on any `date` field in your schema so that you can look at things like trending queries over the last 15 minutes. However, for your first dashboard, select **I don't want to use the time filter**, as shown in the following image. -Index Patterns - - -After selecting **Create index pattern**, you're ready to start building a dashboard that displays the UBI store data. - -## 3. Create a new dashboard - -To create a new dashboard, on the top menu, select **OpenSearch Dashboards > Dashboards** and then **Create > Dashboard** > **Create new**. -If you haven't previously created a dashboard, you are presented with the option to create a new dashboard. Otherwise, previously created dashboards are displayed. - - -In the **New Visualization** window, select **Pie** to create a new pie chart. Then select the index pattern you created in step 2. - -Most visualizations require some sort of aggregate function on a bucket/facet/aggregatable field (numeric or keyword). You'll add a `Terms` aggregation to the `action_name` field so that you can view the distribution of event names. Change the **Size** to the number of slices you want to display, as shown in the following image. -![Pie Chart]({{site.url}}{{site.baseurl}}/images/ubi/pie.png) - -Save the visualization so that it's added to your new dashboard. Now that you have a visualization displayed on your dashboard, you can save the dashboard. - -## 4. Add a tag cloud visualization - -Now you'll add a word cloud for trending searches by creating a new visualization, similarly to the previous step. - -In the **New Visualization** window, select **Tag Cloud**, and then select the index pattern you created in step 2. Choose the tag cloud visualization of the terms in the `message` field where the JavaScript client logs the raw search text. Note: The true query, as processed by OpenSearch with filters, boosting, and so on, resides in the `ubi_queries` index. However, you'll view the `message` field of the `ubi_events` index, where the JavaScript client captures the text that the user actually typed. - -The following image shows the tag cloud visualization on the `message` field. -![Word Cloud]({{site.url}}{{site.baseurl}}/images/ubi/tag_cloud1.png) - -The underlying queries can be found at [SQL trending queries]({{site.url}}{{site.baseurl}}/search-plugins/ubi/sql-queries/#trending-queries). -{: .note} - - -The resulting visualization may contain different information than you're looking for. The `message` field is updated with every event, and as a result, it can contain error messages, debug messages, click information, and other unwanted data. -To view only search terms for query events, you need to add a filter to your visualization. Because during setup you provided a `message_type` of `QUERY` for each search event, you can filter by that message type to isolate the specific users' searches. To do this, select **Add filter** and then select **QUERY** in the **Edit filter** panel, as shown in the following image. -![Word Cloud]({{site.url}}{{site.baseurl}}/images/ubi/tag_cloud2.png) - -There should now be two visualizations (the pie chart and the tag cloud) displayed on your dashboard, as shown in the following image. -![UBI Dashboard]({{site.url}}{{site.baseurl}}/images/ubi/dashboard2.png) - -## 5. Add a histogram of item clicks - -Now you'll add a histogram visualization to your dashboard, similarly to the previous step. In the **New Visualization** window, select **Vertical Bar**. Then select the index pattern you created in step 2. +Here is an example of posting an event. +``` +awscurl --service osis --region us-east-1 \ + -X POST \ + -H "Content-Type: application/json" \ + -d '[{ + "action_name": "page_exit", + "user_id": "1821196507152684", + "query_id": "00112233-4455-6677-8899-aabbccddeeff", + "session_id": "c3d22be7-6bdc-4250-91e1-fc8a92a9b1f9", + "page_id": "/docs/latest/", + "timestamp": "2024-05-16T12:34:56.789Z", + "message_type": "INFO", + "message": "On page /docs/latest/ for 3.35 seconds" + }]' \ + https://erictry2-e2tkd7xuvkswcreho56cuylooq.us-east-1.osis.amazonaws.com/eric-ubi-queries -Examine the `event_attributes.position.ordinal` data field. This field contains the position of the item in a list selected by the user. For the histogram visualization, the x-axis represents the ordinal number of the selected item (n). The y-axis represents the number of times that the nth item was clicked, as shown in the following image. +``` -![Vertical Bar Chart]({{site.url}}{{site.baseurl}}/images/ubi/histogram.png) +Now you can query for the event data that you posted in the Dev Tools console. It may take a minute for the data to flow through OpenSearch Ingestion to the `ubi_queries` index. -## 6. Filter the displayed data +``` +GET ubi_queries/_search +{ + "query": { + "match_all": {} + }, + "sort": [ + { "timestamp": { "order": "desc" } } + ] +} +``` -Now you can further filter the displayed data. For example, you can see how the click position changes when a purchase occurs. Select **Add filter** and then select the `action_name:product_purchase` field, as shown in the following image. -![Product Purchase]({{site.url}}{{site.baseurl}}/images/ubi/product_purchase.png) +If you are feeling impatient you can force the newly written data to be visible with: +``` +POST ubi_queries/_refresh +``` -You can filter event messages containing the word `*laptop*` by adding wildcards, as shown in the following image. -![Laptop]({{site.url}}{{site.baseurl}}/images/ubi/laptop.png). +## Where Next? From 458f0fe743fbe193490eedcced53eab520f5ac51 Mon Sep 17 00:00:00 2001 From: Eric Pugh Date: Mon, 18 Aug 2025 15:06:18 -0400 Subject: [PATCH 4/8] placeholder text --- .../ubi/ubi-aws-managed-services-tutorial.md | 57 +++++++++++++++++-- 1 file changed, 52 insertions(+), 5 deletions(-) diff --git a/_search-plugins/ubi/ubi-aws-managed-services-tutorial.md b/_search-plugins/ubi/ubi-aws-managed-services-tutorial.md index 39d937ba0f..71b6c4d0a2 100644 --- a/_search-plugins/ubi/ubi-aws-managed-services-tutorial.md +++ b/_search-plugins/ubi/ubi-aws-managed-services-tutorial.md @@ -9,7 +9,7 @@ nav_order: 24 # UBI in AWS Managed Services tutorial -This tutorial walks you through the steps for collecting queries and events in the UBI (User Behavior Insights) format when you are using AWS's Managed Service for OpenSearch. At the end of this tutorial you will be able to send authenticated queries and events to both S3 for long term storage and OpenSearch for immediate processing using the Curl command line tool. At the end of the tutorial you will be ready to start collecting UBI data for your applications. +This tutorial walks you through the steps for collecting queries and events in the UBI (User Behavior Insights) format when you are using AWS's OpenSearch Service. At the end of this tutorial you will be able to send authenticated queries and events to both S3 for long term storage and OpenSearch for immediate processing using the Curl command line tool. At the end of the tutorial you will be ready to start collecting UBI data for your applications. The tutorial makes the following assumptions: @@ -79,10 +79,56 @@ You now have the required OpenSearch indexes to recieve UBI data from applicatio ## 3. Set up OpenSearch Ingestion Pipeline +### Required Permissions + +To complete this tutorial, your user or role must have an attached identity-based policy with the following minimum permissions. These permissions allow you to create a pipeline role and attach a policy (iam:Create* and iam:Attach*), create or modify a domain (es:*), and work with pipelines (osis:*). + +```json +``` + +### BLAH + +### Create a Pipeline + +Now you can create a pipeline. This is inspired by https://docs.aws.amazon.com/opensearch-service/latest/developerguide/osis-get-started.html + +1. Within the Amazon OpenSearch Service console, choose Pipelines from the left navigation pane. + +1. Choose Create pipeline. + +1. Select the Blank pipeline, then choose Select blueprint. + +1. In this tutorial, we'll create a simple pipeline that uses the HTTP source plugin. The plugin accepts log data in a JSON array format. We'll specify a single OpenSearch Service domain as the sink, and ingest all data into the application_logs index. + +In the Source menu, choose HTTP. For the Path, enter /logs. + +1. For simplicity in this tutorial, we'll configure public access for the pipeline. For Source network options, choose Public access. For information about configuring VPC access, see Configuring VPC access for Amazon OpenSearch Ingestion pipelines. + +1. Choose Next. + +1. We have no intermediate Processor steps, so on the Processor screen, choose Next. + +1. Configure sink details. For OpenSearch resource type, choose Managed cluster. Then choose the OpenSearch Service domain that you created in the previous section. + +For Index name, enter ubi_queries. OpenSearch Ingestion automatically creates this index in the domain if it doesn't already exist, so make sure you have already created it using the required schema. + +1. Choose Next. + +1. Name the pipeline ubi-queries-ingestion-pipeline. Leave the capacity settings as their defaults. + +1. Do we want the next few steps? + ## 4. Test with sample events -Here is an example of posting an event. +When the pipeline status is `Active`, you can start ingesting data into it. You must sign all HTTP requests to the pipeline using [Signature Version 4](https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html). Use an HTTP tool such as [Postman](https://www.getpostman.com/) or [awscurl](https://github.com/okigan/awscurl) to send some data to the pipeline. As with indexing data directly to a domain, ingesting data into a pipeline always requires either an IAM role or an [IAM access key and secret key](https://docs.aws.amazon.com/powershell/latest/userguide/pstools-appendix-sign-up.html). + +First, get the ingestion URL from the Pipeline settings page: + +** IMGAGE HERE** + +Here is an example of posting an event using [awscurl](https://github.com/okigan/awscurl): + ``` awscurl --service osis --region us-east-1 \ -X POST \ @@ -97,11 +143,12 @@ awscurl --service osis --region us-east-1 \ "message_type": "INFO", "message": "On page /docs/latest/ for 3.35 seconds" }]' \ - https://erictry2-e2tkd7xuvkswcreho56cuylooq.us-east-1.osis.amazonaws.com/eric-ubi-queries - + https://YOUR-PIPELINE-ENDPOINT.osis.amazonaws.com/eric-ubi-queries ``` -Now you can query for the event data that you posted in the Dev Tools console. It may take a minute for the data to flow through OpenSearch Ingestion to the `ubi_queries` index. +You should see a `200 OK` response. + +Now you can query for the event data that you posted via the Dev Tools console. It may take a minute for the data to flow through OpenSearch Ingestion to the `ubi_queries` index. ``` GET ubi_queries/_search From 0af91673882b52ad0e4b9aac54f1a596b05b9b65 Mon Sep 17 00:00:00 2001 From: Eric Pugh Date: Mon, 18 Aug 2025 17:37:38 -0400 Subject: [PATCH 5/8] Add descriptive image and S3 sink Signed-off-by: Eric Pugh --- .../ubi/ubi-aws-managed-services-tutorial.md | 110 +++++++++++++----- images/ubi/opensearch-ingestion-pipeline.png | Bin 0 -> 90271 bytes 2 files changed, 84 insertions(+), 26 deletions(-) create mode 100644 images/ubi/opensearch-ingestion-pipeline.png diff --git a/_search-plugins/ubi/ubi-aws-managed-services-tutorial.md b/_search-plugins/ubi/ubi-aws-managed-services-tutorial.md index 71b6c4d0a2..9275ecd90a 100644 --- a/_search-plugins/ubi/ubi-aws-managed-services-tutorial.md +++ b/_search-plugins/ubi/ubi-aws-managed-services-tutorial.md @@ -16,6 +16,8 @@ The tutorial makes the following assumptions: 1. You are using AWS Managed Service OpenSearch version 2.19. 1. You are not using the UBI Plugin for OpenSearch, which isn't available until OpenSearch 3.1 in Managed Service. 1. You are writing UBI data to OpenSearch using [OpenSearch Ingestion](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/ingestion.html), the managed version of Data Prepper. +1. You have already established permissions between OpenSearch Ingestion and your Managed Clusters by following the steps in the tutorial [Tutorial: Ingesting data into a domain using Amazon OpenSearch Ingestion +](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/osis-get-started.html), specifically the *Required Permissions* step. ## 1. Set up OpenSearch indexes for UBI @@ -77,6 +79,8 @@ You now have the required OpenSearch indexes to recieve UBI data from applicatio ## 2. Set up S3 Storage +You need to have a bucket alredy created that you can write the queries and events data to. Use the AWS Console to create the S3 bucket. + ## 3. Set up OpenSearch Ingestion Pipeline ### Required Permissions @@ -86,37 +90,70 @@ To complete this tutorial, your user or role must have an attached identity-base ```json ``` -### BLAH +We expect your *DataPrepperOpenSearchRole* to have permissions similar to: + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "es:ESHttpPost", + "es:ESHttpPut", + "es:ESHttpGet", + "es:ESHttpHead" + ], + "Resource": "arn:aws:es:*::*" + }, + { + "Effect": "Allow", + "Action": [ + "s3:PutObject" + ], + "Resource": "arn:aws:s3:::/*" + } + ] +} +``` ### Create a Pipeline -Now you can create a pipeline. This is inspired by https://docs.aws.amazon.com/opensearch-service/latest/developerguide/osis-get-started.html +Now you can create a pipeline. __This is inspired by https://docs.aws.amazon.com/opensearch-service/latest/developerguide/osis-get-started.html__ -1. Within the Amazon OpenSearch Service console, choose Pipelines from the left navigation pane. +1. Within the Amazon OpenSearch Service console, choose **Pipelines** from the left navigation pane. -1. Choose Create pipeline. +1. Choose **Create pipeline**. -1. Select the Blank pipeline, then choose Select blueprint. +1. Select the **Blank** pipeline, then choose **Select blueprint**. -1. In this tutorial, we'll create a simple pipeline that uses the HTTP source plugin. The plugin accepts log data in a JSON array format. We'll specify a single OpenSearch Service domain as the sink, and ingest all data into the application_logs index. +1. In this tutorial, we'll create a simple pipeline that uses the HTTP source plugin. The plugin accepts UBI query data in a JSON array format. We'll specify a OpenSearch Service domain as the sink, and ingest all data into the `ubi_queries` index. We will also log all events to an S3 bucket in `.ndjson` format. -In the Source menu, choose HTTP. For the Path, enter /logs. +In the **Source**e menu, choose **HTTP**. For the **Path**, enter `/ubi/queries`. -1. For simplicity in this tutorial, we'll configure public access for the pipeline. For Source network options, choose Public access. For information about configuring VPC access, see Configuring VPC access for Amazon OpenSearch Ingestion pipelines. +1. We will configure public access for the pipeline to faciliate posting data from our notional application. For **Source network options**, choose **Public access**. 1. Choose Next. -1. We have no intermediate Processor steps, so on the Processor screen, choose Next. +1. We do not require any intermediate Processor steps, so on the Processor screen, choose Next. -1. Configure sink details. For OpenSearch resource type, choose Managed cluster. Then choose the OpenSearch Service domain that you created in the previous section. +1. Configure the first sink. For **OpenSearch resource type**, choose **Managed cluster**. Then choose the OpenSearch Service domain that you created in the previous section. -For Index name, enter ubi_queries. OpenSearch Ingestion automatically creates this index in the domain if it doesn't already exist, so make sure you have already created it using the required schema. +For **Index name**, enter `ubi_queries`. OpenSearch Ingestion automatically creates this index in the domain if it doesn't already exist, so make sure you have already created it using the specific schema required by UBI. -1. Choose Next. +1. Now configure the second sink. Start by clicking **Add Sink**. + +1. Choose **Amazon S3**. + +1. For **S3 bucket**, enter the bucket name that you created previosly and the corresponding **S3 Region**. Then choose the OpenSearch Service domain that you created in the previous section. For **Event Collection Timeout** use `60s` so you can see the data fairly quickly. There are a number of formats you can save the data as, **NDJSON** is a perfectly good one. + +1. Choose **Next**. + +1. Name the pipeline `ubi-queries-pipeline`. Leave the capacity settings as their defaults. -1. Name the pipeline ubi-queries-ingestion-pipeline. Leave the capacity settings as their defaults. +1. Choose **Next**. -1. Do we want the next few steps? +1. Choose **Create Pipeline**. ## 4. Test with sample events @@ -125,25 +162,46 @@ When the pipeline status is `Active`, you can start ingesting data into it. You First, get the ingestion URL from the Pipeline settings page: -** IMGAGE HERE** +![Pipeline Settings]({{site.url}}{{site.baseurl}}/images/ubi/opensearch-ingestion-pipeline.png "Pipeline Settings") -Here is an example of posting an event using [awscurl](https://github.com/okigan/awscurl): +Here is an example of posting a query using [awscurl](https://github.com/okigan/awscurl): ``` awscurl --service osis --region us-east-1 \ -X POST \ -H "Content-Type: application/json" \ -d '[{ - "action_name": "page_exit", - "user_id": "1821196507152684", - "query_id": "00112233-4455-6677-8899-aabbccddeeff", - "session_id": "c3d22be7-6bdc-4250-91e1-fc8a92a9b1f9", - "page_id": "/docs/latest/", - "timestamp": "2024-05-16T12:34:56.789Z", - "message_type": "INFO", - "message": "On page /docs/latest/ for 3.35 seconds" - }]' \ - https://YOUR-PIPELINE-ENDPOINT.osis.amazonaws.com/eric-ubi-queries + "query_response_id": "117d75fb-ea76-41dc-9d1d-1d7bba548bd8", + "user_query": "laptop", + "query_id": "d194b734-70a4-41dc-b103-b26a56a277b5", + "application": "Chorus", + "query_response_hit_ids": [ + "B076YX2LML", + "B07S3T59VP", + "B075ZGJSL1", + "B07FMGGRGG", + "B07KN5JP3H", + "B07FM8BNBC", + "B007OYLNGA", + "B07P75NDMB", + "B004HJ1ZB8", + "B01M69KU15", + "B072ZW6NBL", + "B07R7NL612", + "B083GH3L2N", + "B06XNQDR8J", + "B07ZQJQ4HV", + "B07YZHH5WY", + "B07F822FND", + "B004XAVT8K", + "B07F5JN761", + "B087RNZT41" + ], + "query_attributes": {}, + "client_id": "CLIENT-9a9968ac-664b-42d7-9a9e-96f412b5ab49", + "timestamp": "2025-01-23T13:18:22.274+0000" + }]' \ +https://ubi-queries-pipeline-il3g3pwe4ve4nov4bwhnzlrm4q.us-east-1.osis.amazonaws.com/ubi/queries ``` You should see a `200 OK` response. diff --git a/images/ubi/opensearch-ingestion-pipeline.png b/images/ubi/opensearch-ingestion-pipeline.png new file mode 100644 index 0000000000000000000000000000000000000000..65b1dc3b3a8050c7e4c2fafa5ff2083ed2642e7c GIT binary patch literal 90271 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 literal 0 HcmV?d00001 From 498aa3a4efec2051ddf9b951070dec2fecf1ba16 Mon Sep 17 00:00:00 2001 From: Eric Pugh Date: Mon, 18 Aug 2025 17:40:18 -0400 Subject: [PATCH 6/8] More details on permissions Signed-off-by: Eric Pugh --- .../ubi/ubi-aws-managed-services-tutorial.md | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/_search-plugins/ubi/ubi-aws-managed-services-tutorial.md b/_search-plugins/ubi/ubi-aws-managed-services-tutorial.md index 9275ecd90a..7984b92098 100644 --- a/_search-plugins/ubi/ubi-aws-managed-services-tutorial.md +++ b/_search-plugins/ubi/ubi-aws-managed-services-tutorial.md @@ -85,9 +85,35 @@ You need to have a bucket alredy created that you can write the queries and even ### Required Permissions -To complete this tutorial, your user or role must have an attached identity-based policy with the following minimum permissions. These permissions allow you to create a pipeline role and attach a policy (iam:Create* and iam:Attach*), create or modify a domain (es:*), and work with pipelines (osis:*). +To complete this tutorial, your user or role must have an attached identity-based policy with the following minimum permissions. These permissions allow you to create a pipeline role and attach a policy (`iam:Create*` and `iam:Attach*`), create or modify a domain (`es:*`), and work with pipelines (`osis:*`). ```json +{ + "Version":"2012-10-17", + "Statement":[ + { + "Effect":"Allow", + "Resource":"*", + "Action":[ + "osis:*", + "iam:Create*", + "iam:Attach*", + "es:*" + ] + }, + { + "Resource":[ + "arn:aws:iam::111122223333:role/OpenSearchIngestion-PipelineRole" + ], + "Effect":"Allow", + "Action":[ + "iam:CreateRole", + "iam:AttachRolePolicy", + "iam:PassRole" + ] + } + ] +} ``` We expect your *DataPrepperOpenSearchRole* to have permissions similar to: From 14db5a63d8ae082718133a1505c3f7e6fae7a11f Mon Sep 17 00:00:00 2001 From: Eric Pugh Date: Mon, 18 Aug 2025 17:49:46 -0400 Subject: [PATCH 7/8] Add Event pipeline Signed-off-by: Eric Pugh --- .../ubi/ubi-aws-managed-services-tutorial.md | 46 ++++++++++++++++++- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/_search-plugins/ubi/ubi-aws-managed-services-tutorial.md b/_search-plugins/ubi/ubi-aws-managed-services-tutorial.md index 7984b92098..511d02b50b 100644 --- a/_search-plugins/ubi/ubi-aws-managed-services-tutorial.md +++ b/_search-plugins/ubi/ubi-aws-managed-services-tutorial.md @@ -143,9 +143,9 @@ We expect your *DataPrepperOpenSearchRole* to have permissions similar to: } ``` -### Create a Pipeline +### Create a Pipeline for Query data -Now you can create a pipeline. __This is inspired by https://docs.aws.amazon.com/opensearch-service/latest/developerguide/osis-get-started.html__ +Now you can create a pipeline for the UBI Query data. 1. Within the Amazon OpenSearch Service console, choose **Pipelines** from the left navigation pane. @@ -252,4 +252,46 @@ If you are feeling impatient you can force the newly written data to be visible POST ubi_queries/_refresh ``` +### Create a Pipeline for Event data + +Repeat the steps above, but this time for UBI Event data. Use the following table to replace query-specific values with their event equivalents: + +| Query Pipeline Setting | Event Pipeline Setting | +|------------------------|------------------------| +| Path: `/ubi/queries` | Path: `/ubi/events` | +| Index name: `ubi_queries` | Index name: `ubi_events` | +| Pipeline name: `ubi-queries-pipeline` | Pipeline name: `ubi-events-pipeline` | +| S3 path prefix pattern: `ubi_queries/` | S3 path prefix pattern: `ubi_events/` | +| Dev Tools search: `GET ubi_queries/_search` | Dev Tools search: `GET ubi_events/_search` | +| Refresh command: `POST ubi_queries/_refresh` | Refresh command: `POST ubi_events/_refresh` | + +Here is an example of posting a query using [awscurl](https://github.com/okigan/awscurl): + +``` +awscurl --service osis --region us-east-1 \ + -X POST \ + -H "Content-Type: application/json" \ + -d '[ + { + "action_name": "product_hover", + "client_id": "CLIENT-9a9968ac-664b-42d7-9a9e-96f412b5ab49", + "query_id": "d194b734-70a4-41dc-b103-b26a56a277b5", + "page_id": "/", + "message_type": "INFO", + "message": "Integral 2GB SD Card memory card (undefined)", + "timestamp": 1724944081669, + "event_attributes": { + "object": { + "object_id_field": "product", + "object_id": "1625640", + "description": "Integral 2GB SD Card memory card", + "object_detail": null + } + } + } +] +' \ +https://ubi-queries-pipeline-il3g3pwe4ve4nov4bwhnzlrm4q.us-east-1.osis.amazonaws.com/ubi/events +``` + ## Where Next? From 44b3a4473e0ad04ceb9e0964fc74b7926c08f9d6 Mon Sep 17 00:00:00 2001 From: Eric Pugh Date: Wed, 3 Sep 2025 14:51:50 -0400 Subject: [PATCH 8/8] Updates after feedback --- .../ubi/ubi-aws-managed-services-tutorial.md | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/_search-plugins/ubi/ubi-aws-managed-services-tutorial.md b/_search-plugins/ubi/ubi-aws-managed-services-tutorial.md index 511d02b50b..66f502eff8 100644 --- a/_search-plugins/ubi/ubi-aws-managed-services-tutorial.md +++ b/_search-plugins/ubi/ubi-aws-managed-services-tutorial.md @@ -9,24 +9,24 @@ nav_order: 24 # UBI in AWS Managed Services tutorial -This tutorial walks you through the steps for collecting queries and events in the UBI (User Behavior Insights) format when you are using AWS's OpenSearch Service. At the end of this tutorial you will be able to send authenticated queries and events to both S3 for long term storage and OpenSearch for immediate processing using the Curl command line tool. At the end of the tutorial you will be ready to start collecting UBI data for your applications. +This tutorial walks you through the steps for collecting queries and events in the UBI (User Behavior Insights) format when you are using AWS's OpenSearch Service. At the end of this tutorial you will be able to send authenticated queries and events to both S3 for long term storage and OpenSearch for immediate processing using the Curl command line tool. At the end of the tutorial you will be ready to start collecting UBI data for your applications. The tutorial makes the following assumptions: 1. You are using AWS Managed Service OpenSearch version 2.19. 1. You are not using the UBI Plugin for OpenSearch, which isn't available until OpenSearch 3.1 in Managed Service. 1. You are writing UBI data to OpenSearch using [OpenSearch Ingestion](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/ingestion.html), the managed version of Data Prepper. -1. You have already established permissions between OpenSearch Ingestion and your Managed Clusters by following the steps in the tutorial [Tutorial: Ingesting data into a domain using Amazon OpenSearch Ingestion +1. You have already established permissions between OpenSearch Ingestion and your Managed Clusters by completeing the steps in the tutorial [Tutorial: Ingesting data into a domain using Amazon OpenSearch Ingestion ](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/osis-get-started.html), specifically the *Required Permissions* step. ## 1. Set up OpenSearch indexes for UBI -Log into Managed Service OpenSearch Dashboard. We will use the DevTools console to create two indexes for storing data: `ubi_queries` and `ubi_events`. +Log into Managed Service OpenSearch Dashboard. We will use the DevTools console to create two new indexes for storing UBI specific data: `ubi_queries` and `ubi_events`. Navigate to **Management > Dev Tools** -Create the overall index creation command: +Create the overall index creation command in the console: ```json PUT ubi_events @@ -35,9 +35,9 @@ PUT ubi_events } ``` -You will see a syntax warning after typing this in, that's okay. +You will see a syntax warning after typing this in, that's okay, we're going to modify it some more. -Then, go to (https://github.com/opensearch-project/user-behavior-insights/blob/main/src/main/resources/events-mapping.json)[https://github.com/opensearch-project/user-behavior-insights/blob/main/src/main/resources/events-mapping.json] and copy the entire JSON formatted contents of the file and paste it in after the `"mappings":` line in the Dev Tools console. This will produce a complete command similar to: +Then, open the [events-mapping.json](https://github.com/opensearch-project/user-behavior-insights/blob/main/src/main/resources/events-mapping.json) file in Github and copy the entire JSON formatted contents of the file and paste it in after the `"mappings":` line in the Dev Tools console. This will produce a complete command similar to: ```json PUT ubi_events @@ -66,7 +66,7 @@ PUT ubi_queries } ``` -This time go to https://github.com/opensearch-project/user-behavior-insights/blob/main/src/main/resources/queries-mapping.json and copy the entire JSON text and paste it in after the `"mappings":` line in the Dev Tools console. Run the command. +This time open the [queries-mapping.json](https://github.com/opensearch-project/user-behavior-insights/blob/main/src/main/resources/queries-mapping.json) file in Github and copy the entire JSON text and paste it in after the `"mappings":` line in the Dev Tools console. Run the command and make sure it completes successfully. > If you are using OpenSearch 3.0 or newer then the UBI plugin is already included. Instead of manually creating the indexes you can instead use the UBI plugin to create them: > @@ -75,13 +75,15 @@ This time go to https://github.com/opensearch-project/user-behavior-insights/blo > ``` {: .note} -You now have the required OpenSearch indexes to recieve UBI data from applications. +You now have the required OpenSearch indexes to receive UBI data from your applications. ## 2. Set up S3 Storage -You need to have a bucket alredy created that you can write the queries and events data to. Use the AWS Console to create the S3 bucket. +Assuming you want to store UBI data long term, then S3 is a good place for this. -## 3. Set up OpenSearch Ingestion Pipeline +You need to have a bucket created ahead of time that you can write the queries and events data to. Use the AWS Console to create the S3 bucket. Remember the name and the region it is in. + +## 3. Set up OpenSearch ingest pipeline ### Required Permissions @@ -153,9 +155,9 @@ Now you can create a pipeline for the UBI Query data. 1. Select the **Blank** pipeline, then choose **Select blueprint**. -1. In this tutorial, we'll create a simple pipeline that uses the HTTP source plugin. The plugin accepts UBI query data in a JSON array format. We'll specify a OpenSearch Service domain as the sink, and ingest all data into the `ubi_queries` index. We will also log all events to an S3 bucket in `.ndjson` format. +1. In this tutorial, we'll create a simple pipeline that uses the HTTP source plugin. The plugin accepts UBI query data in a JSON array format. We'll specify a OpenSearch Service domain as the sink, and ingest all data into the `ubi_queries` index. We will also log all events to an S3 bucket in `.ndjson` format. -In the **Source**e menu, choose **HTTP**. For the **Path**, enter `/ubi/queries`. +In the **Source** menu, choose **HTTP**. For the **Path**, enter `/ubi/queries`. 1. We will configure public access for the pipeline to faciliate posting data from our notional application. For **Source network options**, choose **Public access**. @@ -167,11 +169,11 @@ In the **Source**e menu, choose **HTTP**. For the **Path**, enter `/ubi/queries` For **Index name**, enter `ubi_queries`. OpenSearch Ingestion automatically creates this index in the domain if it doesn't already exist, so make sure you have already created it using the specific schema required by UBI. -1. Now configure the second sink. Start by clicking **Add Sink**. +1. Now configure the second sink. Start by clicking **Add Sink**. 1. Choose **Amazon S3**. -1. For **S3 bucket**, enter the bucket name that you created previosly and the corresponding **S3 Region**. Then choose the OpenSearch Service domain that you created in the previous section. For **Event Collection Timeout** use `60s` so you can see the data fairly quickly. There are a number of formats you can save the data as, **NDJSON** is a perfectly good one. +1. For **S3 bucket**, enter the bucket name that you created previosly and the corresponding **S3 Region**. Then choose the OpenSearch Service domain that you created in the previous section. For **Event Collection Timeout** field, enter `60s` so you can see the data process through the pipeline quickly. There are a number of different formats you can save the data in, **NDJSON** is a perfectly good one. 1. Choose **Next**. @@ -232,7 +234,7 @@ https://ubi-queries-pipeline-il3g3pwe4ve4nov4bwhnzlrm4q.us-east-1.osis.amazonaws You should see a `200 OK` response. -Now you can query for the event data that you posted via the Dev Tools console. It may take a minute for the data to flow through OpenSearch Ingestion to the `ubi_queries` index. +Now you can query for the event data that you posted using the Dev Tools console. It may take a minute for the data to flow through OpenSearch Ingestion to the `ubi_queries` index. ``` GET ubi_queries/_search @@ -254,7 +256,7 @@ POST ubi_queries/_refresh ### Create a Pipeline for Event data -Repeat the steps above, but this time for UBI Event data. Use the following table to replace query-specific values with their event equivalents: +Repeat the previous steps, but this time setting up a pipline for the UBI event data. Use the following table to replace query-specific values with their event equivalents: | Query Pipeline Setting | Event Pipeline Setting | |------------------------|------------------------| @@ -293,5 +295,3 @@ awscurl --service osis --region us-east-1 \ ' \ https://ubi-queries-pipeline-il3g3pwe4ve4nov4bwhnzlrm4q.us-east-1.osis.amazonaws.com/ubi/events ``` - -## Where Next?