{"id":29639,"date":"2024-05-30T06:25:59","date_gmt":"2024-05-30T01:25:59","guid":{"rendered":"https:\/\/kmwllc.com\/?p=29639"},"modified":"2025-06-02T20:13:40","modified_gmt":"2025-06-02T15:13:40","slug":"duplicate-terms-aggregation-plug-in-for-opensearch","status":"publish","type":"post","link":"https:\/\/kmwllc.com\/index.php\/2024\/05\/30\/duplicate-terms-aggregation-plug-in-for-opensearch\/","title":{"rendered":"Duplicate Terms Aggregation Plug-in for OpenSearch"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-post\" data-elementor-id=\"29639\" class=\"elementor elementor-29639\" data-elementor-post-type=\"post\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-b9d2795 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"b9d2795\" data-element_type=\"section\" data-e-type=\"section\">\r\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-thegem\"><div class=\"elementor-row\">\r\n\t\t\t\t\t<div class=\"elementor-column elementor-col-33 elementor-top-column elementor-element elementor-element-849c1d1\" data-id=\"849c1d1\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-1298f9a flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-post-info\" data-id=\"1298f9a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"post-info.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<ul class=\"elementor-inline-items elementor-icon-list-items elementor-post-info\">\n\t\t\t\t\t\t\t\t<li class=\"elementor-icon-list-item elementor-repeater-item-91a0f52 elementor-inline-item\" itemprop=\"datePublished\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-icon-list-text elementor-post-info__item elementor-post-info__item--type-date\">\n\t\t\t\t\t\t\t\t\t\t<time>May 30, 2024<\/time>\t\t\t\t\t<\/span>\n\t\t\t\t\t\t\t\t<\/li>\n\t\t\t\t<\/ul>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-cb40088 flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-heading\" data-id=\"cb40088\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div class=\"styled-subtitle elementor-heading-title elementor-size-default\">In Lucene-based search engines like OpenSearch and Solr, keyword aggregations ignore duplicate values that occur within a multi-valued field. We built an OpenSearch plugin to overcome this limitation.<\/div>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-984b5d3 elementor-author-box--image-valign-top flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-author-box\" data-id=\"984b5d3\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"author-box.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-author-box\">\n\t\t\t\t\t\t\t<div  class=\"elementor-author-box__avatar\">\n\t\t\t\t\t<img src=\"https:\/\/kmwllc.com\/wp-content\/uploads\/2024\/01\/Abijit2023.png\" alt=\"Picture of Abijit Rangesh\" loading=\"lazy\">\n\t\t\t\t<\/div>\n\t\t\t\n\t\t\t<div class=\"elementor-author-box__text\">\n\t\t\t\t\t\t\t\t\t<div >\n\t\t\t\t\t\t<div class=\"elementor-author-box__name\">\n\t\t\t\t\t\t\tAbijit Rangesh\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t\n\t\t\t\t\t\t\t\t\t<div class=\"elementor-author-box__bio\">\n\t\t\t\t\t\t<p>Search Engineer at KMW Technology<\/p>\n\t\t\t\t\t<\/div>\n\t\t\t\t\n\t\t\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-57774d5 elementor-widget-divider--view-line flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-divider\" data-id=\"57774d5\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"divider.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-divider\">\n\t\t\t<span class=\"elementor-divider-separator\">\n\t\t\t\t\t\t<\/span>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-2f6bf75 flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-spacer\" data-id=\"2f6bf75\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"spacer.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-spacer\">\n\t\t\t<div class=\"elementor-spacer-inner\"><\/div>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-6d550b8 flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-heading\" data-id=\"6d550b8\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-large\">What We\u2019ve Accomplished<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-c3fec1d flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-text-editor\" data-id=\"c3fec1d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t<div class=\"elementor-text-editor elementor-clearfix\">\r\n\t\t\t\t\t\t<p><span style=\"font-weight: 400;\">In Lucene-based search engines like OpenSearch and Solr, keyword aggregations ignore duplicate values that occur within a multi-valued field. If a document has a multi-valued field containing the values [&#8220;foo&#8221;, &#8220;foo&#8221;, &#8220;bar&#8221;] then an aggregation would increment the count for the &#8220;foo&#8221; and \u201cbar\u201d bucket once, even though \u201cfoo\u201d occurs twice. We built an OpenSearch plugin to overcome this limitation.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">In this blog post, we detail the investigation process into duplicate terms aggregation solutions and the subsequent development process by which a plug-in was built for OpenSearch. Previously, only the nested field type and scripted aggregation methods seemed to be viable solutions. Our plug-in aims to be a third option to solve this problem. This plug-in serves to be the fastest solution for a duplicate terms aggregation on a multivalued keyword field in OpenSearch without compromising index size.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">The link to the plug-in repository can be found <\/span><a href=\"https:\/\/github.com\/kmwtechnology\/opensearch-duplicate-terms-agg\"><span style=\"font-weight: 400;\">here<\/span><\/a><span style=\"font-weight: 400;\">. Please follow the steps in the README.md to install this plug-in into an OpenSearch distribution and interact with the custom aggregation.\u00a0<\/span><\/p>\t\t\t\t\t\t\t<\/div>\r\n\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-0ef200a flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-spacer\" data-id=\"0ef200a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"spacer.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-spacer\">\n\t\t\t<div class=\"elementor-spacer-inner\"><\/div>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-26d3771 flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-heading\" data-id=\"26d3771\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-large\">The Problem  <\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-c0b7446 flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-text-editor\" data-id=\"c0b7446\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t<div class=\"elementor-text-editor elementor-clearfix\">\r\n\t\t\t\t\t\t<p><span style=\"font-weight: 400;\">Imagine you\u2019re rummaging through your attic at your family home and you\u2019ve found a large recipe book. It seems to be something your great-grandmother cherished. As both a devoted great-grandchild and a fan of search solutions, you\u2019d like to catalogue the data found in this recipe book in a search engine, specifically OpenSearch.\u00a0<\/span><\/p><p><span style=\"font-weight: 400;\">You wish to represent each recipe as a document and each document would store fields for different aspects of the recipe: cook_time, steps, technique, ingredients, etc. Ingredients could have duplicate values, designating how many of them to include i.e. [carrot, carrot, apple, cucumber] would represent 2 carrots, 1 apple, and 1 cucumber for our recipe.\u00a0<\/span><\/p><p><span style=\"font-weight: 400;\">Upon completion of your index, you wish to aggregate upon all the ingredients and find out how many of each ingredient to purchase in order to make all of your great grandmother\u2019s recipes. You notice a problem quite quickly: OpenSearch aggregations do not take into account duplicate values on multi-valued fields. While the recipes may have called for a total of three carrots (two for one recipe and one for a different recipe), the aggregation result only tells you to buy two (one for each recipe).<\/span><\/p>\t\t\t\t\t\t\t<\/div>\r\n\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-199285c flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-code-highlight\" data-id=\"199285c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-tomorrow copy-to-clipboard word-wrap\">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-javascript \">\n\t\t\t\t<code readonly=\"true\" class=\"language-javascript\">\n\t\t\t\t\t<xmp>Documents & Aggregation: \r\n\r\ncurl -XPUT \"http:\/\/localhost:9200\/recipe-book\/_doc\/1\" -H 'Content-Type: application\/json' -d'\r\n{\r\n  \"favorite_foods\": [\"carrot\", \"carrot\", \"apple\", \"cucumber\"]\r\n}'\r\n\r\ncurl -XPUT \"http:\/\/localhost:9200\/recipe-book\/_doc\/2\" -H 'Content-Type: application\/json' -d'\r\n{\r\n  \"favorite_foods\": [\"carrot\", \"apple\", \"cucumber\"]\r\n}'\r\n\r\ncurl -XPUT \"http:\/\/localhost:9200\/recipe-book\/_doc\/3\" -H 'Content-Type: application\/json' -d'\r\n{\r\n  \"favorite_foods\": [\"cucumber\", \"cucumber\", \"cucumber\"]\r\n}'\r\n\r\ncurl -XGET \"http:\/\/localhost:9200\/recipe-book\/_search\" -H 'Content-Type: application\/json' -d'\r\n{\r\n  \"size\": 0,\r\n  \"aggregations\": {\r\n    \"ingredient_frequency\": {\r\n      \"terms\": {\r\n   \t   \"field\": \"favorite_foods\"\r\n      }\r\n    }\r\n  }\r\n}'\r\n\r\nResult: \r\n\"aggregations\":{\r\n  \t\"ingredient_frequency\":{\r\n     \t  \"doc_count_error_upper_bound\":0,\r\n     \t  \"sum_other_doc_count\":0,\r\n     \t  \"buckets\":[\r\n        \t{\r\n           \t\"key\":\"cucumber\",\r\n           \t\"doc_count\":3\r\n        \t},\r\n        \t{\r\n           \t\"key\":\"apple\",\r\n           \t\"doc_count\":2\r\n        \t},\r\n        \t{\r\n           \t\"key\":\"carrot\",\r\n           \t\"doc_count\":2\r\n        \t}\r\n     \t  ]\r\n  \t}\r\n}\r\n\r\n<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-aecaba2 flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-heading\" data-id=\"aecaba2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h3 class=\"elementor-heading-title elementor-size-large\">Delving Deeper Into the Problem<\/h3>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-9759dbb flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-text-editor\" data-id=\"9759dbb\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t<div class=\"elementor-text-editor elementor-clearfix\">\r\n\t\t\t\t\t\t<p><span style=\"font-weight: 400;\">Why is it that OpenSearch is unable to perform aggregations on duplicate values in keyword fields? Behind the scenes, OpenSearch is using a doc_values data structure for operations like aggregations, as they perform far better than the traditional inverted-index data structure. The specific type of doc_values supported by Lucene for keyword fields do not store duplicate values. Conversely, a match_all query would return us duplicate values as it would be using a segment lookup unlike aggregations which would be using the aforementioned doc_values data structure.\u00a0<\/span><\/p><p><span style=\"font-weight: 400;\">The following <\/span><a href=\"https:\/\/solr.apache.org\/guide\/8_7\/docvalues.html\"><span style=\"font-weight: 400;\">link<\/span><\/a><span style=\"font-weight: 400;\"> provides more information about specific field types and whether they support duplicates or not. Note that while this links to Solr documentation and presents Solr specific information, the section on docValues types is a Lucene specific implementation detail that applies to OpenSearch as well.\u00a0<\/span><\/p>\t\t\t\t\t\t\t<\/div>\r\n\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-495477a flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-heading\" data-id=\"495477a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h3 class=\"elementor-heading-title elementor-size-medium\">Scripting<\/h3>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-ecffa21 flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-text-editor\" data-id=\"ecffa21\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t<div class=\"elementor-text-editor elementor-clearfix\">\r\n\t\t\t\t\t\t<p><span style=\"font-weight: 400;\">OpenSearch offers users the ability to include scripts with aggregations via the \u201cscripted_metric\u201d aggregation type. This leverages the painless scripting language, built specifically for Elasticsearch (and subsequently OpenSearch). Painless has Java-like syntax and compiles directly into JVM bytecode, leveraging any optimizations that the JVM has.\u00a0<\/span><\/p><p><span style=\"font-weight: 400;\">With painless, we have access to the \u201c_source\u201d variable that offers us the ability to view the segment data on specific fields. With this approach, we should be able to access duplicates on our keyword field type and aggregate them together via a hashmap defined by our script.\u00a0<\/span><\/p><p><span style=\"font-weight: 400;\">Here\u2019s what the script looked like inside of an aggregation query:<\/span><\/p>\t\t\t\t\t\t\t<\/div>\r\n\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-e071421 flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-code-highlight\" data-id=\"e071421\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-tomorrow copy-to-clipboard word-wrap\">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-javascript \">\n\t\t\t\t<code readonly=\"true\" class=\"language-javascript\">\n\t\t\t\t\t<xmp>{\r\n\t\"size\": 0,\r\n\t\"aggs\": {\r\n    \t\"ingredient_frequency\": {\r\n      \t\"scripted_metric\": {\r\n        \t\"init_script\": \"state.foodFreq = new HashMap();\",\r\n        \t\"map_script\": \"for (f in params._source.favorite_foods) { if (state.foodFreq.get(f) == null) { state.foodFreq.put(f, 1); } else { state.foodFreq.put(f, state.foodFreq.get(f) + 1); }}\",\r\n        \t\"combine_script\": \"return state.foodFreq;\",\r\n        \t\"reduce_script\": \"\"\"\r\nMap finalMap = new HashMap(); \r\nfor (map in states) { \r\n for (key in map.keySet()) { \r\n  if (finalMap.get(key) == null) { \r\n   def val = map[key]; \r\n   finalMap.put(key, map[key]); \r\n  } \r\n  else {\r\n   def prevVal = finalMap[key]; \r\n   finalMap.put(key, prevVal + map[key]); \r\n  }\r\n  }\r\n} \r\nreturn finalMap;\r\n\"\"\"\r\n      \t}\r\n    \t}\r\n  \t    }\r\n  }\r\n<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-9529a53 flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-text-editor\" data-id=\"9529a53\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t<div class=\"elementor-text-editor elementor-clearfix\">\r\n\t\t\t\t\t\t<p><span style=\"font-weight: 400;\">Notice that this is quite brute-force. We have to account for each and every value, place them in a hashmap, and then combine these hashmaps across shards via the \u201creduce_script\u201d. Also, we don\u2019t leverage the highly performant doc_values data structure, built for aggregations. We know this, as we are accessing \u201c_source\u201d which takes information directly from Lucene segments, rather than from doc_values. In the benchmarking section, these observations will be substantiated by our gathered performance statistics.\u00a0<\/span><\/p><p><span style=\"font-weight: 400;\">For more information on the scripted_metric aggregation, here\u2019s a link to <\/span><a href=\"https:\/\/www.elastic.co\/guide\/en\/elasticsearch\/reference\/current\/modules-scripting-painless.html\"><span style=\"font-weight: 400;\">official documentation<\/span><\/a><span style=\"font-weight: 400;\">.<\/span><\/p>\t\t\t\t\t\t\t<\/div>\r\n\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-8a8978f flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-heading\" data-id=\"8a8978f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h3 class=\"elementor-heading-title elementor-size-medium\">Nested Fields<\/h3>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-f6f6630 flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-text-editor\" data-id=\"f6f6630\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t<div class=\"elementor-text-editor elementor-clearfix\">\r\n\t\t\t\t\t\t<p><span style=\"font-weight: 400;\">Scripting worked within the confines of our original organisation of the recipe book. We wanted our ingredients to be represented in a multi-valued field. However, if we can\u2019t see duplicate values across multi-valued fields due to the doc_value limitation, why not try to change how the documents themselves are indexed?<\/span><\/p><p><span style=\"font-weight: 400;\">\u00a0<\/span><span style=\"font-weight: 400;\">OpenSearch offers users the ability to create inner or \u201cnested\u201d documents within other documents. Each nested document is underlyingly treated as a \u201chidden\u201d Lucene document, allowing for a nested aggregation that would guarantee that we would be able to see duplicate documents.\u00a0<\/span><\/p><p><span style=\"font-weight: 400;\">We can implement this, simply, with the following:<\/span><\/p>\t\t\t\t\t\t\t<\/div>\r\n\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-71c1c92 flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-code-highlight\" data-id=\"71c1c92\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-tomorrow copy-to-clipboard word-wrap\">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-javascript \">\n\t\t\t\t<code readonly=\"true\" class=\"language-javascript\">\n\t\t\t\t\t<xmp>PUT \/recipe-book\r\n{\r\n  \"mappings\": {\r\n    \"properties\": {\r\n      \"favorite_foods\": {\r\n   \t \"type\": \"nested\",\r\n   \t \"properties\": {\r\n \t\t \"food\": {\r\n \t\t \"type\": \"keyword\"\r\n \t\t }\r\n   \t  }\r\n     }\r\n    }\r\n  }\r\n}   \r\n\r\nPUT \/recipe-book\/_doc\/1\r\n{\r\n  \"favorite_foods\": [\r\n    {\r\n      \"food\": \"carrot\"\r\n    },\r\n    {\r\n      \"food\": \"carrot\"\r\n    },\r\n    {\r\n      \"food\": \"apple\"\r\n    },\r\n    {\r\n      \"food\": \"cucumber\"\r\n    }\r\n  ]\r\n}\r\n\r\nPUT \/recipe-book\/_doc\/2\r\n{\r\n  \"favorite_foods\": [\r\n    {\r\n      \"food\": \"carrot\"\r\n    },\r\n    {\r\n      \"food\": \"apple\"\r\n    },\r\n    {\r\n      \"food\": \"cucumber\"\r\n    }\r\n  ]\r\n}\r\n\r\nPUT \/recipe-book\/_doc\/3\r\n{\r\n  \"favorite_foods\": [\r\n    {\r\n      \"food\": \"cucumber\"\r\n    },\r\n    {\r\n      \"food\": \"cucumber\"\r\n    },\r\n    {\r\n      \"food\": \"cucumber\"\r\n    }\r\n  ]\r\n}\r\n\r\n{\r\n  \"size\": 0,\r\n  \"aggs\": {\r\n\t\"favorite_foods\": {\r\n  \t\"nested\": {\r\n    \t\"path\": \"favorite_foods\"\r\n  \t},\r\n  \t\"aggs\": {\r\n    \t\"food_freq\": {\r\n      \t\"terms\": {\r\n        \t\"size\": 10000,\r\n        \t\"field\": \"favorite_foods.data\"\r\n      \t}\r\n    \t}\r\n    \t}\r\n    \t}\r\n  }\r\n}\r\n\r\n\"aggregations\": {\r\n\t\"favorite_foods\": {\r\n  \t\"doc_count\": 10,\r\n  \t\"food_freq\": {\r\n    \t\"doc_count_error_upper_bound\": 0,\r\n    \t\"sum_other_doc_count\": 0,\r\n    \t\"buckets\": [\r\n      \t{\r\n        \t\"key\": \"cucumber\",\r\n        \t\"doc_count\": 5\r\n      \t},\r\n      \t{\r\n        \t\"key\": \"carrot\",\r\n        \t\"doc_count\": 3\r\n      \t},\r\n      \t{\r\n        \t\"key\": \"apple\",\r\n        \t\"doc_count\": 2\r\n      \t}\r\n    \t]\r\n  \t    }\r\n\t    }\r\n}<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-ba484a2 flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-text-editor\" data-id=\"ba484a2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t<div class=\"elementor-text-editor elementor-clearfix\">\r\n\t\t\t\t\t\t<p><span style=\"font-weight: 400;\">This implementation is simple at first glance, but this approach can quickly cause problems at scale. Nested documents are inherently documents, therefore they take up their own space in the index. 200 recipes with 20 average ingredients in each would lead to over 4000 documents. Again, we\u2019ll see how this implementation fares in our benchmarks.\u00a0<\/span><\/p><p><span style=\"font-weight: 400;\">For more information on the nested field aggregations, here\u2019s a link to <\/span><a href=\"https:\/\/www.elastic.co\/guide\/en\/elasticsearch\/reference\/current\/search-aggregations-bucket-nested-aggregation.html\"><span style=\"font-weight: 400;\">official documentation<\/span><\/a><span style=\"font-weight: 400;\">.<\/span><\/p>\t\t\t\t\t\t\t<\/div>\r\n\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-93e1cde flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-heading\" data-id=\"93e1cde\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h3 class=\"elementor-heading-title elementor-size-medium\">Underscore Representation<\/h3>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-b562b5b flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-text-editor\" data-id=\"b562b5b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t<div class=\"elementor-text-editor elementor-clearfix\">\r\n\t\t\t\t\t\t<p><span style=\"font-weight: 400;\">Let\u2019s try something different. Let\u2019s go back to using multi-valued fields, but this time, let\u2019s look at how the ingredients themselves are represented. What if we changed the representation from [carrots, carrots, apple, cucumber] to [carrots_2, apple_1, cucumber_1]? By appending our counts, we retain information about duplicates, without exposing duplicates to the underlying doc_values data structure. We can perform this conversion at index time well in advance. The question now remains as to how we can aggregate upon those \u201csuffixes\u201d or numbers after our underscore delimiter.\u00a0<\/span><\/p><p><span style=\"font-weight: 400;\">We can try to write code directly within a cloned repository of the OpenSearch codebase\u00a0 and test to see if we can create a performant solution with regards to this representation of our ingredients. If this solution proves to be a winner in our benchmarks, we can move this code over to a plug-in architecture that\u2019s easily packageable and can be installed via a single command by other users.\u00a0<\/span><\/p><p><span style=\"font-weight: 400;\">Here\u2019s how the example from before might look like with our new representation:<\/span><\/p>\t\t\t\t\t\t\t<\/div>\r\n\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-8a11f9b flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-code-highlight\" data-id=\"8a11f9b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-tomorrow copy-to-clipboard word-wrap\">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-javascript \">\n\t\t\t\t<code readonly=\"true\" class=\"language-javascript\">\n\t\t\t\t\t<xmp>curl -XPUT \"http:\/\/localhost:9200\/recipe-book\" -H 'Content-Type: application\/json' -d' \t \r\n{\r\n  \"mappings\": {\r\n    \"properties\": {\r\n    \t \"favorite_foods\": {\r\n   \t\t\t \"type\": \"keyword\"\r\n     \t }\r\n     }\r\n   }\r\n}'\r\n\r\ncurl -XPUT \"http:\/\/localhost:9200\/recipe-book\/_doc\/1\" -H 'Content-Type: application\/json' -d'\r\n{\r\n  \"favorite_foods\": [\"apple_1\", \"carrot_2\", \"cucumber_1\"]\r\n}'\r\n\r\ncurl -XPUT \"http:\/\/localhost:9200\/recipe-book\/_doc\/2\" -H 'Content-Type: application\/json' -d'\r\n{\r\n  \"favorite_foods\": [\"apple_1\", \"carrot_1\", \"cucumber_1\"]\r\n}'\r\n\r\ncurl -XPUT \"http:\/\/localhost:9200\/recipe-book\/_doc\/3\" -H 'Content-Type: application\/json' -d'\r\n{\r\n  \"favorite_foods\": [\"cucumber_3\"]\r\n}'\r\n<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-9a83613 flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-text-editor\" data-id=\"9a83613\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t<div class=\"elementor-text-editor elementor-clearfix\">\r\n\t\t\t\t\t\t<p><span style=\"font-weight: 400;\">We took a look at the OpenSearch codebase, finding the code path by which traditional terms aggregations were performed. There were two \u201caggregator\u201d classes that OpenSearch uses in a terms aggregation, either the GlobalOrdinalsStringTermsAggregator or the MapStringTermsAggregator. The Global Ordinals aggregation takes advantage of global ordinals, mappings of segment ordinals to their original locations at a \u201cglobal\u201d level. While this is the traditional aggregator used for terms aggregations, seeing that aggregations occur across shards and segments, we opted to base our custom implementation in the MapStringTermsAggregator.\u00a0<\/span><\/p><p><span style=\"font-weight: 400;\">The GlobalOrdinalsStringTermsAggregator deals in globalOrds represented as longs, which are not easily convertible into Strings. We need to deal with Strings in order to separate the suffix count from the delimiter. The MapStringTermsAggregator uses a representation of doc values that enables for ordinal representations to be converted to BytesRefs and subsequently to Strings.\u00a0<\/span><\/p><p><span style=\"font-weight: 400;\">Following further down the code path, we then modified the doc values typing used by the MapStringTermsAggregator, specifically the SortedBinaryDocValues type, and created a custom implementation that separated the suffix from our term (apple_3 \u2192 apple, 3) and created new buckets with these new terms as keys and suffixes as counts. We then sent \u201cfake\u201d values to the LeafCollector method that would mimic the bucket counts that we required. For example, the value apple_3 would be seen by the collector as apple, apple(fake), apple(fake).\u00a0<\/span><\/p><p><span style=\"font-weight: 400;\">On further iteration, caching via Hashmap was supported to prevent multiple ordinal lookups and multiple conversions from BytesRef to Strings, improving performance in the process.\u00a0<\/span><\/p>\t\t\t\t\t\t\t<\/div>\r\n\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-c6abd2e flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-spacer\" data-id=\"c6abd2e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"spacer.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-spacer\">\n\t\t\t<div class=\"elementor-spacer-inner\"><\/div>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-8ca4920 flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-heading\" data-id=\"8ca4920\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h3 class=\"elementor-heading-title elementor-size-large\">Benchmarks &amp; Takeaways<\/h3>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-8cdf81a flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-text-editor\" data-id=\"8cdf81a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t<div class=\"elementor-text-editor elementor-clearfix\">\r\n\t\t\t\t\t\t<p><span style=\"font-weight: 400;\">We now have three implementations that each net us the expected result. It now remains to see which implementation will offer us the best solution in accordance with our guidelines.\u00a0<\/span><\/p><p><span style=\"font-weight: 400;\">We used JMeter to test the query performance. Here are important points regarding how the implementations were benchmarked:<\/span><\/p><ul><li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Documents were indexed via <a href=\"https:\/\/github.com\/kmwtechnology\/lucille\">Lucille<\/a>, an open-source Java framework for ETL pipelines created by KMW Technology; Lucille supports a benchmarking workflow with randomised document creation<\/span><\/li><li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">1 index was created per implementation, each within their own instance of OS<\/span><\/li><li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">100k documents were indexed into each index<\/span><\/li><li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Each document averaged at 1000 values in its field, with the range spanning from 750 to 1250<\/span><\/li><li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">All queries had random boolean match filters alongside the aggregations so as to prevent the impact of caches<\/span><ul><li style=\"font-weight: 400;\" aria-level=\"2\"><span style=\"font-weight: 400;\">The underscore representation queries used a \u201cprefix\u201d match seeing that their values had an additional delimiter and count attached<\/span><\/li><li style=\"font-weight: 400;\" aria-level=\"2\"><span style=\"font-weight: 400;\">This \u201cprefix\u201d analysis may potentially have had ramifications for query performance for the underscore implementation<\/span><\/li><\/ul><\/li><li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">50 users sent queries simultaneously with a 1 second ramp-up time<\/span><\/li><\/ul>\t\t\t\t\t\t\t<\/div>\r\n\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-c26131c flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-text-editor\" data-id=\"c26131c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t<div class=\"elementor-text-editor elementor-clearfix\">\r\n\t\t\t\t\t\t<p><\/p><figure class=\"wp-block-table is-style-regular\"><table class=\"has-fixed-layout\"><tbody><tr><td>\u00a0<\/td><td><strong>Scripted Imp.<\/strong><\/td><td><strong>Underscore Imp.<\/strong><\/td><td><strong>Nested Imp.<\/strong><\/td><\/tr><tr><td># of samples<\/td><td>50<\/td><td>50<\/td><td>50<\/td><\/tr><tr><td>Average Latency (ms)<\/td><td>103907 ms<\/td><td>34505 ms<\/td><td>11877 ms<\/td><\/tr><tr><td>Min Latency (ms)<\/td><td>0 ms<\/td><td>0 ms<\/td><td>0 ms<\/td><\/tr><tr><td>Max Latency (ms)<\/td><td>147451 ms<\/td><td>41623 ms<\/td><td>16203 ms<\/td><\/tr><tr><td>Std. Dev<\/td><td>39522.05<\/td><td>7823.51<\/td><td>2761.71<\/td><\/tr><tr><td>Error %<\/td><td>0%<\/td><td>0%<\/td><td>0%<\/td><\/tr><tr><td>Throughput (requests per second)<\/td><td>0%<\/td><td>0%<\/td><td>0%<\/td><\/tr><\/tbody><\/table><\/figure>\t\t\t\t\t\t\t<\/div>\r\n\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-fcf9fc2 flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-text-editor\" data-id=\"fcf9fc2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t<div class=\"elementor-text-editor elementor-clearfix\">\r\n\t\t\t\t\t\t<p><span style=\"font-weight: 400;\">The scripted implementation saw the longest average query time at around 104 seconds. The underscore implementation sat in the middle with an average query time of around 35 seconds.<\/span><span style=\"font-weight: 400;\">The nested implementation was the fastest with an average query time of around 12 seconds.<\/span><\/p><p><span style=\"font-weight: 400;\">With this information, it may seem clear that the nested approach is the best approach for handling duplicate terms aggregations in OpenSearch. However, taking a closer look at our proposed guidelines, we notice that we\u2019ve yet to evaluate index size. Looking at index size benchmarks for both the nested and underscore implementations, we see a potentially new conclusion. The nested document index holds a large 1.4 GB index size. Meanwhile, the underscore index boasts a significantly smaller 187 MB index size. This translates to a <em>7.5x smaller index<\/em> size for the underscore implementation, with a 2.9x slower average query time.\u00a0<\/span><\/p><p><span style=\"font-weight: 400;\">While we didn\u2019t explicitly weigh each guideline\u2019s importance, it was clear to us that a significantly larger index would present more problems than the query time performance hit, especially with the magnitudes mentioned before. This led us to believe that the underscore implementation was the best fit for our needs and the guidelines that we set forth. If index size is not a consideration for users, then the nested approach would be the best, seeing that it offers extremely fast lookup \/ query times.<\/span><\/p>\t\t\t\t\t\t\t<\/div>\r\n\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-7dc0602 flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-spacer\" data-id=\"7dc0602\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"spacer.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-spacer\">\n\t\t\t<div class=\"elementor-spacer-inner\"><\/div>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-0070c1d flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-heading\" data-id=\"0070c1d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-large\">The Plug-in<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-8aa794a flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-text-editor\" data-id=\"8aa794a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t<div class=\"elementor-text-editor elementor-clearfix\">\r\n\t\t\t\t\t\t<p><span style=\"font-weight: 400;\">It now makes sense to package this solution into a plug-in. While OpenSearch does offer an easy-to-use <\/span><a href=\"https:\/\/github.com\/opensearch-project\/opensearch-plugin-template-java\"><span style=\"font-weight: 400;\">template<\/span><\/a><span style=\"font-weight: 400;\"> for developers to get started with plug-in development, the convenience stops shortly thereafter. We encountered some problems while developing the plug-in.<\/span><\/p>\t\t\t\t\t\t\t<\/div>\r\n\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-eae5bdc flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-heading\" data-id=\"eae5bdc\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h3 class=\"elementor-heading-title elementor-size-medium\">Difficulties in Plug-in Creation <\/h3>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-1796c20 flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-text-editor\" data-id=\"1796c20\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t<div class=\"elementor-text-editor elementor-clearfix\">\r\n\t\t\t\t\t\t<p><span style=\"font-weight: 400;\">The most challenging issue in plug-in development with OpenSearch has to do with Java class loaders. When installing a plug-in into an OpenSearch distribution, OpenSearch uses a parent class loader to load in OpenSearch related files and a child class loader to load in our plug-in files. OpenSearch files are largely package-private, preventing the child class loader from having access to their methods, constructors, etc. This causes large amounts of code duplication and requires a deep understanding of the inner workings of OpenSearch aggregations. Here is a link to a code example that illustrates the issues we encountered with class loaders: <\/span><a href=\"https:\/\/gist.github.com\/rseitz\/59bff56936756ff29b2e151e2857aa37\"><span style=\"font-weight: 400;\">link<\/span><\/a><span style=\"font-weight: 400;\">.<\/span><\/p><p><span style=\"font-weight: 400;\">Another issue faced was a lack of clear testing protocol for plug-ins. Tests situated within the OpenSearch core codebase, specifically aggregation tests, relied heavily on helper classes and methods found within the core codebase. Our plug-in code, due to the aforementioned class loader issue, did not have access to these assisting classes. This made it extremely difficult to write unit tests, leaving us only with integration tests.<\/span><\/p>\t\t\t\t\t\t\t<\/div>\r\n\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-f49451e flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-heading\" data-id=\"f49451e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h3 class=\"elementor-heading-title elementor-size-medium\">Future Points of Interest<\/h3>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-20673c2 flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-text-editor\" data-id=\"20673c2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t<div class=\"elementor-text-editor elementor-clearfix\">\r\n\t\t\t\t\t\t<p><span style=\"font-weight: 400;\">To say that our investigation exhausted all avenues for how to perform a duplicate terms aggregation would be naive. A few ideas were brainstormed (and even tested), but didn\u2019t seem promising or did not fit our original guidelines. Here are a few:<\/span><span style=\"font-weight: 400;\"><br \/><\/span><\/p><p><span style=\"font-weight: 400;\">Our plug-in implementation leveraged the SortedBinaryDocValues, the primary doc values data type for keyword field types. If we were open to changing the field type of our data, we could have experimented with the SortedOrderedNumericDocValues which stores duplicates for the numeric field type. This type is the only doc values field type in Lucene that retains duplicates. However, the issue would arise for a need to convert from numeric type to string at query time, leading to definite performance loss.\u00a0<\/span><\/p><p><span style=\"font-weight: 400;\">Another potential solution would be to utilise Lucene payloads. Payloads are metadata that can be stored with terms and accessed via Lucene. The concern regarding this solution was that payloads would likely not be accessible via doc_values, leaving them as a likely slower alternative.<\/span><\/p><p><span style=\"font-weight: 400;\">One solution that was explored thoroughly was term vectors. Term vectors work by offering statistics for all the terms in the fields of a specific document, provided by the user. This already raised a few concerns, especially since we would require an artificial \u201cmaster\u201d document that contained all possible terms and fields so that its \u2018id\u2019 could be provided. If using this artificial document approach, term vectors would gather statistics from a randomly selected shard. The user must then choose to use only a single-shard instance or total the counts across all shards and create \u201cmaster\u201d documents within each shard. Despite this, we created code against Lucene itself comparing doc values to term vectors. For 10 million documents, term vectors seemed to be averaging 50 seconds slower than doc values.\u00a0<\/span><\/p>\t\t\t\t\t\t\t<\/div>\r\n\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-c9a6ce9 flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-heading\" data-id=\"c9a6ce9\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-large\">Conclusion<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-e94bbab flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-text-editor\" data-id=\"e94bbab\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t<div class=\"elementor-text-editor elementor-clearfix\">\r\n\t\t\t\t\t\t<p><span style=\"font-weight: 400;\">Overall, we believe our investigation to be a thorough analysis of the existing possible tools to perform a duplicate terms aggregation. The plug-in we\u2019ve created seems likely to be the best solution for duplicate terms aggregation depending on the individual context and use-case.\u00a0<\/span><\/p><p><span style=\"font-weight: 400;\">With this solution under our belt, we can now make our shopping list and make our great-grandmother proud!\u00a0<\/span><\/p>\t\t\t\t\t\t\t<\/div>\r\n\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t<div class=\"elementor-column elementor-col-33 elementor-top-column elementor-element elementor-element-7295c69\" data-id=\"7295c69\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap\">\n\t\t\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t<div class=\"elementor-column elementor-col-33 elementor-top-column elementor-element elementor-element-1f8e61f\" data-id=\"1f8e61f\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-b2890c3 flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-heading\" data-id=\"b2890c3\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div class=\"title-h6 elementor-heading-title elementor-size-small\">Share Post<\/div>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-5fe7d43 flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-thegem-social-sharing\" data-id=\"5fe7d43\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"thegem-social-sharing.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\n        <div id=\"thegem-custom-69da47cfd5fea7456\" class=\"thegem-te-socials-sharing socials-sharing--left socials-sharing--simple socials-sharing--tiny\">\n            <div class=\"socials-sharing\">\n                <ul>\n\t\t\t\t\t                        <li><a class=\"socials-item facebook\" target=\"_blank\" href=\"https:\/\/www.facebook.com\/sharer\/sharer.php?u=https%3A%2F%2Fkmwllc.com%2Findex.php%2Fwp-json%2Fwp%2Fv2%2Fposts%2F29639\" title=\"Facebook\"><i class=\"socials-item-icon facebook\"><\/i><\/a><\/li>\n\t\t\t\t\t\n\t\t\t\t\t                        <li><a class=\"socials-item twitter\" target=\"_blank\" href=\"https:\/\/twitter.com\/intent\/tweet?text=&#038;url=https%3A%2F%2Fkmwllc.com%2Findex.php%2Fwp-json%2Fwp%2Fv2%2Fposts%2F29639\" title=\"Twitter\"><i class=\"socials-item-icon twitter\"><\/i><\/a><\/li>\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t                        <li><a class=\"socials-item linkedin\" target=\"_blank\" href=\"https:\/\/www.linkedin.com\/shareArticle?mini=true&#038;url=https%3A%2F%2Fkmwllc.com%2Findex.php%2Fwp-json%2Fwp%2Fv2%2Fposts%2F29639&#038;title=&amp;summary=\" title=\"LinkedIn\"><i class=\"socials-item-icon linkedin\"><\/i><\/a><\/li>\n\t\t\t\t\t\n\t\t\t\t\t                        <li><a class=\"socials-item reddit\" target=\"_blank\" href=\"https:\/\/www.reddit.com\/submit?url=https%3A%2F%2Fkmwllc.com%2Findex.php%2Fwp-json%2Fwp%2Fv2%2Fposts%2F29639&#038;title=\" title=\"Reddit\"><i class=\"socials-item-icon reddit\"><\/i><\/a><\/li>\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t                        <li><a class=\"socials-item threads\" target=\"_blank\" href=\"https:\/\/www.threads.net\/intent\/post?text=https%3A%2F%2Fkmwllc.com%2Findex.php%2Fwp-json%2Fwp%2Fv2%2Fposts%2F29639\" title=\"Threads\"><i class=\"socials-item-icon threads\"><\/i><\/a><\/li>\n\t\t\t\t\t                <\/ul>\n            <\/div>\n        <\/div>\n\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-0a5e46b flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-heading\" data-id=\"0a5e46b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div class=\"title-h6 elementor-heading-title elementor-size-small\">More From the KMW Blog<\/div>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-a1cba74 flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-thegem-bloglist\" data-id=\"a1cba74\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;thegem_elementor_preset&quot;:&quot;compact-tiny-2&quot;,&quot;source&quot;:[&quot;posts&quot;],&quot;exclude_blog_posts_type&quot;:&quot;current&quot;,&quot;query_type&quot;:&quot;post&quot;,&quot;order_by&quot;:&quot;default&quot;,&quot;order&quot;:&quot;default&quot;,&quot;items_per_page&quot;:8}\" data-widget_type=\"thegem-bloglist.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t<div class=\"bloglist blog clearfix  blog-style-compact-tiny-2   \" data-page=\"1\" data-paged=\"1\" data-next-page=\"2\" data-pages-count=\"3\" data-load-more-action=\"thegem_bloglist_load_more\">\n\t\t\t\r\n<article id=\"post-30279\" class=\"post-item clearfix post-30279 post type-post status-publish format-standard has-post-thumbnail category-elasticsearch category-lucene category-performance\">\r\n\t\t\t<div class=\"gem-compact-tiny-left\">\r\n\t\t\t<div class=\"gem-news-item-image\">\r\n\t\t\t\t<a href=\"https:\/\/kmwllc.com\/index.php\/2026\/01\/10\/the-mystery-of-elasticsearch-8-17-query-performance-degradation\/\"><img width=\"144\" height=\"144\" src=\"https:\/\/kmwllc.com\/wp-content\/uploads\/2026\/01\/blog_elasticperftest_900x1200-thegem-news-carousel.png\" class=\"img-responsive wp-post-image\" alt=\"blog_elasticperftest_900x1200\" \/><\/a>\r\n\t\t\t<\/div>\r\n\t\t<\/div>\r\n\t\r\n\t<div class=\"gem-compact-tiny-right\">\r\n\t\t<div class=\"gem-compact-item-content\">\r\n\t\t\t<div class=\"tiny-post-title gem-news-item-title text-body-tiny\"><a class=\"reverse-link-color \" href=\"https:\/\/kmwllc.com\/index.php\/2026\/01\/10\/the-mystery-of-elasticsearch-8-17-query-performance-degradation\/\" rel=\"bookmark\">The Mystery of Elasticsearch 8.17 Query Performance Degradation<\/a><\/div>\t\t<\/div>\r\n\t\t<div class=\"post-meta\">\r\n\t\t\t<div class=\"entry-meta clearfix text-body-tiny\">\r\n\t\t\t\t<div class=\"post-meta-left gem-news-item-date\">\r\n\t\t\t\t\t<span\r\n\t\t\t\t\t\t\tclass=\"post-meta-author tiny-post-author\">By Henry Caldwell<\/span><br>\t\t\t\t\t<span\r\n\t\t\t\t\t\t\tclass=\"post-meta-date tiny-post-date\">January 10, 2026<\/span>\t\t\t\t<\/div>\r\n\t\t\t\t<div class=\"post-meta-right\">\r\n\t\t\t\t\t\t\t\t\t<\/div>\r\n\t\t\t<\/div><!-- .entry-meta -->\r\n\t\t<\/div>\r\n\r\n\t<\/div>\r\n<\/article><!-- #post-30279 -->\r\n\r\n<article id=\"post-30125\" class=\"post-item clearfix post-30125 post type-post status-publish format-standard has-post-thumbnail category-ai category-performance category-relevancy category-search category-uncategorized\">\r\n\t\t\t<div class=\"gem-compact-tiny-left\">\r\n\t\t\t<div class=\"gem-news-item-image\">\r\n\t\t\t\t<a href=\"https:\/\/kmwllc.com\/index.php\/2025\/10\/04\/whats-the-best-way-to-do-entity-extraction-for-search\/\"><img width=\"144\" height=\"144\" src=\"https:\/\/kmwllc.com\/wp-content\/uploads\/2025\/10\/blogpost_entityex-thegem-news-carousel.png\" class=\"img-responsive wp-post-image\" alt=\"blogpost_entityex\" \/><\/a>\r\n\t\t\t<\/div>\r\n\t\t<\/div>\r\n\t\r\n\t<div class=\"gem-compact-tiny-right\">\r\n\t\t<div class=\"gem-compact-item-content\">\r\n\t\t\t<div class=\"tiny-post-title gem-news-item-title text-body-tiny\"><a class=\"reverse-link-color \" href=\"https:\/\/kmwllc.com\/index.php\/2025\/10\/04\/whats-the-best-way-to-do-entity-extraction-for-search\/\" rel=\"bookmark\">What&#8217;s the best way to do entity extraction for search?<\/a><\/div>\t\t<\/div>\r\n\t\t<div class=\"post-meta\">\r\n\t\t\t<div class=\"entry-meta clearfix text-body-tiny\">\r\n\t\t\t\t<div class=\"post-meta-left gem-news-item-date\">\r\n\t\t\t\t\t<span\r\n\t\t\t\t\t\t\tclass=\"post-meta-author tiny-post-author\">By Jacob Squatrito<\/span><br>\t\t\t\t\t<span\r\n\t\t\t\t\t\t\tclass=\"post-meta-date tiny-post-date\">October 4, 2025<\/span>\t\t\t\t<\/div>\r\n\t\t\t\t<div class=\"post-meta-right\">\r\n\t\t\t\t\t\t\t\t\t<\/div>\r\n\t\t\t<\/div><!-- .entry-meta -->\r\n\t\t<\/div>\r\n\r\n\t<\/div>\r\n<\/article><!-- #post-30125 -->\r\n\r\n<article id=\"post-30155\" class=\"post-item clearfix post-30155 post type-post status-publish format-standard has-post-thumbnail category-ai\">\r\n\t\t\t<div class=\"gem-compact-tiny-left\">\r\n\t\t\t<div class=\"gem-news-item-image\">\r\n\t\t\t\t<a href=\"https:\/\/kmwllc.com\/index.php\/2025\/05\/20\/mcp-in-llm-apps-overkill-or-integral\/\"><img width=\"144\" height=\"144\" src=\"https:\/\/kmwllc.com\/wp-content\/uploads\/2025\/05\/blog_mcp_1200x900_min-thegem-news-carousel.png\" class=\"img-responsive wp-post-image\" alt=\"blog_mcp_1200x900_min\" \/><\/a>\r\n\t\t\t<\/div>\r\n\t\t<\/div>\r\n\t\r\n\t<div class=\"gem-compact-tiny-right\">\r\n\t\t<div class=\"gem-compact-item-content\">\r\n\t\t\t<div class=\"tiny-post-title gem-news-item-title text-body-tiny\"><a class=\"reverse-link-color \" href=\"https:\/\/kmwllc.com\/index.php\/2025\/05\/20\/mcp-in-llm-apps-overkill-or-integral\/\" rel=\"bookmark\">MCP in LLM Apps: Overkill or Integral?<\/a><\/div>\t\t<\/div>\r\n\t\t<div class=\"post-meta\">\r\n\t\t\t<div class=\"entry-meta clearfix text-body-tiny\">\r\n\t\t\t\t<div class=\"post-meta-left gem-news-item-date\">\r\n\t\t\t\t\t<span\r\n\t\t\t\t\t\t\tclass=\"post-meta-author tiny-post-author\">By Kevin Butler<\/span><br>\t\t\t\t\t<span\r\n\t\t\t\t\t\t\tclass=\"post-meta-date tiny-post-date\">May 20, 2025<\/span>\t\t\t\t<\/div>\r\n\t\t\t\t<div class=\"post-meta-right\">\r\n\t\t\t\t\t\t\t\t\t<\/div>\r\n\t\t\t<\/div><!-- .entry-meta -->\r\n\t\t<\/div>\r\n\r\n\t<\/div>\r\n<\/article><!-- #post-30155 -->\r\n\r\n<article id=\"post-29895\" class=\"post-item clearfix post-29895 post type-post status-publish format-standard has-post-thumbnail category-ai category-opensearch category-relevancy category-search category-solr category-vector-search\">\r\n\t\t\t<div class=\"gem-compact-tiny-left\">\r\n\t\t\t<div class=\"gem-news-item-image\">\r\n\t\t\t\t<a href=\"https:\/\/kmwllc.com\/index.php\/2024\/06\/23\/rag-question-answering-system-for-solr-and-opensearch\/\"><img loading=\"lazy\" width=\"144\" height=\"144\" src=\"https:\/\/kmwllc.com\/wp-content\/uploads\/2024\/06\/blog_rag-thegem-news-carousel.png\" class=\"img-responsive wp-post-image\" alt=\"blog_rag\" \/><\/a>\r\n\t\t\t<\/div>\r\n\t\t<\/div>\r\n\t\r\n\t<div class=\"gem-compact-tiny-right\">\r\n\t\t<div class=\"gem-compact-item-content\">\r\n\t\t\t<div class=\"tiny-post-title gem-news-item-title text-body-tiny\"><a class=\"reverse-link-color \" href=\"https:\/\/kmwllc.com\/index.php\/2024\/06\/23\/rag-question-answering-system-for-solr-and-opensearch\/\" rel=\"bookmark\">RAG Question Answering System for Solr and OpenSearch\u00a0<\/a><\/div>\t\t<\/div>\r\n\t\t<div class=\"post-meta\">\r\n\t\t\t<div class=\"entry-meta clearfix text-body-tiny\">\r\n\t\t\t\t<div class=\"post-meta-left gem-news-item-date\">\r\n\t\t\t\t\t<span\r\n\t\t\t\t\t\t\tclass=\"post-meta-author tiny-post-author\">By Akul Sethi<\/span><br>\t\t\t\t\t<span\r\n\t\t\t\t\t\t\tclass=\"post-meta-date tiny-post-date\">June 23, 2024<\/span>\t\t\t\t<\/div>\r\n\t\t\t\t<div class=\"post-meta-right\">\r\n\t\t\t\t\t\t\t\t\t<\/div>\r\n\t\t\t<\/div><!-- .entry-meta -->\r\n\t\t<\/div>\r\n\r\n\t<\/div>\r\n<\/article><!-- #post-29895 -->\r\n\r\n<article id=\"post-28464\" class=\"post-item clearfix post-28464 post type-post status-publish format-standard has-post-thumbnail category-ai category-opensearch category-search category-vector-search\">\r\n\t\t\t<div class=\"gem-compact-tiny-left\">\r\n\t\t\t<div class=\"gem-news-item-image\">\r\n\t\t\t\t<a href=\"https:\/\/kmwllc.com\/index.php\/2023\/03\/29\/building-vector-search-on-opensearch\/\"><img loading=\"lazy\" width=\"144\" height=\"144\" src=\"https:\/\/kmwllc.com\/wp-content\/uploads\/2024\/05\/blog_vectorSearch_1200x900-min-thegem-news-carousel.png\" class=\"img-responsive wp-post-image\" alt=\"blog_vectorSearch_1200x900-min\" \/><\/a>\r\n\t\t\t<\/div>\r\n\t\t<\/div>\r\n\t\r\n\t<div class=\"gem-compact-tiny-right\">\r\n\t\t<div class=\"gem-compact-item-content\">\r\n\t\t\t<div class=\"tiny-post-title gem-news-item-title text-body-tiny\"><a class=\"reverse-link-color \" href=\"https:\/\/kmwllc.com\/index.php\/2023\/03\/29\/building-vector-search-on-opensearch\/\" rel=\"bookmark\">Building A Vector Search Application on OpenSearch<\/a><\/div>\t\t<\/div>\r\n\t\t<div class=\"post-meta\">\r\n\t\t\t<div class=\"entry-meta clearfix text-body-tiny\">\r\n\t\t\t\t<div class=\"post-meta-left gem-news-item-date\">\r\n\t\t\t\t\t<span\r\n\t\t\t\t\t\t\tclass=\"post-meta-author tiny-post-author\">By Jake Horban<\/span><br>\t\t\t\t\t<span\r\n\t\t\t\t\t\t\tclass=\"post-meta-date tiny-post-date\">March 29, 2023<\/span>\t\t\t\t<\/div>\r\n\t\t\t\t<div class=\"post-meta-right\">\r\n\t\t\t\t\t\t\t\t\t<\/div>\r\n\t\t\t<\/div><!-- .entry-meta -->\r\n\t\t<\/div>\r\n\r\n\t<\/div>\r\n<\/article><!-- #post-28464 -->\r\n\r\n<article id=\"post-28075\" class=\"post-item clearfix post-28075 post type-post status-publish format-standard has-post-thumbnail category-elasticsearch category-search category-solr\">\r\n\t\t\t<div class=\"gem-compact-tiny-left\">\r\n\t\t\t<div class=\"gem-news-item-image\">\r\n\t\t\t\t<a href=\"https:\/\/kmwllc.com\/index.php\/2022\/12\/17\/ingesting-solr-logs-with-the-elk-stack\/\"><img loading=\"lazy\" width=\"144\" height=\"144\" src=\"https:\/\/kmwllc.com\/wp-content\/uploads\/2022\/12\/blog_LogAnalysisElk_min-thegem-news-carousel.png\" class=\"img-responsive wp-post-image\" alt=\"blog_LogAnalysisElk_min\" \/><\/a>\r\n\t\t\t<\/div>\r\n\t\t<\/div>\r\n\t\r\n\t<div class=\"gem-compact-tiny-right\">\r\n\t\t<div class=\"gem-compact-item-content\">\r\n\t\t\t<div class=\"tiny-post-title gem-news-item-title text-body-tiny\"><a class=\"reverse-link-color \" href=\"https:\/\/kmwllc.com\/index.php\/2022\/12\/17\/ingesting-solr-logs-with-the-elk-stack\/\" rel=\"bookmark\">Ingesting Solr Logs with the ELK Stack<\/a><\/div>\t\t<\/div>\r\n\t\t<div class=\"post-meta\">\r\n\t\t\t<div class=\"entry-meta clearfix text-body-tiny\">\r\n\t\t\t\t<div class=\"post-meta-left gem-news-item-date\">\r\n\t\t\t\t\t<span\r\n\t\t\t\t\t\t\tclass=\"post-meta-author tiny-post-author\">By Kira Traynor<\/span><br>\t\t\t\t\t<span\r\n\t\t\t\t\t\t\tclass=\"post-meta-date tiny-post-date\">December 17, 2022<\/span>\t\t\t\t<\/div>\r\n\t\t\t\t<div class=\"post-meta-right\">\r\n\t\t\t\t\t\t\t\t\t<\/div>\r\n\t\t\t<\/div><!-- .entry-meta -->\r\n\t\t<\/div>\r\n\r\n\t<\/div>\r\n<\/article><!-- #post-28075 -->\r\n\r\n<article id=\"post-27467\" class=\"post-item clearfix post-27467 post type-post status-publish format-standard has-post-thumbnail category-search category-solr\">\r\n\t\t\t<div class=\"gem-compact-tiny-left\">\r\n\t\t\t<div class=\"gem-news-item-image\">\r\n\t\t\t\t<a href=\"https:\/\/kmwllc.com\/index.php\/2022\/11\/17\/solrs-query-elevation-component-now-supports-filter-exclusions\/\"><img loading=\"lazy\" width=\"144\" height=\"144\" src=\"https:\/\/kmwllc.com\/wp-content\/uploads\/2022\/11\/blog_QEC1200x900-thegem-news-carousel.png\" class=\"img-responsive wp-post-image\" alt=\"blog_QEC1200x900\" \/><\/a>\r\n\t\t\t<\/div>\r\n\t\t<\/div>\r\n\t\r\n\t<div class=\"gem-compact-tiny-right\">\r\n\t\t<div class=\"gem-compact-item-content\">\r\n\t\t\t<div class=\"tiny-post-title gem-news-item-title text-body-tiny\"><a class=\"reverse-link-color \" href=\"https:\/\/kmwllc.com\/index.php\/2022\/11\/17\/solrs-query-elevation-component-now-supports-filter-exclusions\/\" rel=\"bookmark\">Solr&#8217;s query elevation component now supports filter exclusions<\/a><\/div>\t\t<\/div>\r\n\t\t<div class=\"post-meta\">\r\n\t\t\t<div class=\"entry-meta clearfix text-body-tiny\">\r\n\t\t\t\t<div class=\"post-meta-left gem-news-item-date\">\r\n\t\t\t\t\t<span\r\n\t\t\t\t\t\t\tclass=\"post-meta-author tiny-post-author\">By Rudi Seitz<\/span><br>\t\t\t\t\t<span\r\n\t\t\t\t\t\t\tclass=\"post-meta-date tiny-post-date\">November 17, 2022<\/span>\t\t\t\t<\/div>\r\n\t\t\t\t<div class=\"post-meta-right\">\r\n\t\t\t\t\t\t\t\t\t<\/div>\r\n\t\t\t<\/div><!-- .entry-meta -->\r\n\t\t<\/div>\r\n\r\n\t<\/div>\r\n<\/article><!-- #post-27467 -->\r\n\r\n<article id=\"post-26659\" class=\"post-item clearfix post-26659 post type-post status-publish format-standard has-post-thumbnail category-search\">\r\n\t\t\t<div class=\"gem-compact-tiny-left\">\r\n\t\t\t<div class=\"gem-news-item-image\">\r\n\t\t\t\t<a href=\"https:\/\/kmwllc.com\/index.php\/2022\/09\/30\/the-kmw-search-audit\/\"><img loading=\"lazy\" width=\"144\" height=\"144\" src=\"https:\/\/kmwllc.com\/wp-content\/uploads\/2022\/09\/blog_KMWSearchAudit1200x900-thegem-news-carousel.png\" class=\"img-responsive wp-post-image\" alt=\"blog_KMWSearchAudit1200x900\" \/><\/a>\r\n\t\t\t<\/div>\r\n\t\t<\/div>\r\n\t\r\n\t<div class=\"gem-compact-tiny-right\">\r\n\t\t<div class=\"gem-compact-item-content\">\r\n\t\t\t<div class=\"tiny-post-title gem-news-item-title text-body-tiny\"><a class=\"reverse-link-color \" href=\"https:\/\/kmwllc.com\/index.php\/2022\/09\/30\/the-kmw-search-audit\/\" rel=\"bookmark\">The KMW Search Audit<\/a><\/div>\t\t<\/div>\r\n\t\t<div class=\"post-meta\">\r\n\t\t\t<div class=\"entry-meta clearfix text-body-tiny\">\r\n\t\t\t\t<div class=\"post-meta-left gem-news-item-date\">\r\n\t\t\t\t\t<span\r\n\t\t\t\t\t\t\tclass=\"post-meta-author tiny-post-author\">By Brian Nauheimer<\/span><br>\t\t\t\t\t<span\r\n\t\t\t\t\t\t\tclass=\"post-meta-date tiny-post-date\">September 30, 2022<\/span>\t\t\t\t<\/div>\r\n\t\t\t\t<div class=\"post-meta-right\">\r\n\t\t\t\t\t\t\t\t\t<\/div>\r\n\t\t\t<\/div><!-- .entry-meta -->\r\n\t\t<\/div>\r\n\r\n\t<\/div>\r\n<\/article><!-- #post-26659 -->\r\n\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div><\/div>\r\n\t\t<\/section>\r\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-87fbea3 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"87fbea3\" data-element_type=\"section\" data-e-type=\"section\">\r\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-thegem\"><div class=\"elementor-row\">\r\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-c32d4f1\" data-id=\"c32d4f1\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-aecd2e9 flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-spacer\" data-id=\"aecd2e9\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"spacer.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-spacer\">\n\t\t\t<div class=\"elementor-spacer-inner\"><\/div>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-a1d11f5 flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-post-navigation\" data-id=\"a1d11f5\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"post-navigation.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-post-navigation\" role=\"navigation\" aria-label=\"Post Navigation\">\n\t\t\t<div class=\"elementor-post-navigation__prev elementor-post-navigation__link\">\n\t\t\t\t<a href=\"https:\/\/kmwllc.com\/index.php\/2022\/07\/02\/search-engine-upgrade\/\" rel=\"prev\"><span class=\"elementor-post-navigation__link__prev\"><span class=\"post-navigation__prev--label\">Previous Post<\/span><span class=\"post-navigation__prev--title\">Search Engine Upgrade<\/span><\/span><\/a>\t\t\t<\/div>\n\t\t\t\t\t\t<div class=\"elementor-post-navigation__next elementor-post-navigation__link\">\n\t\t\t\t<a href=\"https:\/\/kmwllc.com\/index.php\/2022\/11\/17\/solrs-query-elevation-component-now-supports-filter-exclusions\/\" rel=\"next\"><span class=\"elementor-post-navigation__link__next\"><span class=\"post-navigation__next--label\">Next Post<\/span><span class=\"post-navigation__next--title\">Solr&#8217;s query elevation component now supports filter exclusions<\/span><\/span><\/a>\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div><\/div>\r\n\t\t<\/section>\r\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>In Lucene-based search engines like OpenSearch and Solr, keyword aggregations ignore duplicate values that occur within a multi-valued field. We built an OpenSearch plugin to overcome this limitation.<\/p>\n","protected":false},"author":11,"featured_media":29759,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[46,43,5,36],"tags":[],"class_list":{"0":"post-29639","1":"post","2":"type-post","3":"status-publish","4":"format-standard","5":"has-post-thumbnail","7":"category-lucene","8":"category-opensearch","9":"category-performance","10":"category-search"},"aioseo_notices":[],"post_meta_fields":{"_wp_page_template":["default"],"_edit_lock":["1748877252:7"],"_edit_last":["7"],"thegem_post_item_gallery_images":[""],"_customize_sidebars":["yes"],"thegem_post_general_item_data":["a:26:{s:20:\"post_layout_settings\";s:6:\"custom\";s:18:\"post_layout_source\";s:7:\"default\";s:21:\"post_builder_template\";s:1:\"0\";s:26:\"show_featured_posts_slider\";i:0;s:21:\"show_featured_content\";s:7:\"default\";s:10:\"video_type\";s:7:\"youtube\";s:5:\"video\";s:0:\"\";s:18:\"video_aspect_ratio\";s:0:\"\";s:20:\"video_play_on_mobile\";s:0:\"\";s:13:\"video_overlay\";s:0:\"\";s:12:\"video_poster\";s:0:\"\";s:11:\"video_start\";s:16:\"open_in_lightbox\";s:10:\"quote_text\";s:0:\"\";s:12:\"quote_author\";s:0:\"\";s:16:\"quote_background\";s:0:\"\";s:18:\"quote_author_color\";s:0:\"\";s:5:\"audio\";s:0:\"\";s:7:\"gallery\";i:0;s:18:\"gallery_autoscroll\";i:0;s:9:\"highlight\";i:0;s:14:\"highlight_type\";s:7:\"squared\";s:15:\"highlight_style\";s:7:\"default\";s:31:\"highlight_title_left_background\";s:9:\"#00BCD4FF\";s:26:\"highlight_title_left_color\";s:9:\"#FFFFFFFF\";s:32:\"highlight_title_right_background\";s:9:\"#00BCD4FF\";s:27:\"highlight_title_right_color\";s:9:\"#FFFFFFFF\";}"],"thegem_show_featured_posts_slider":["0"],"thegem_post_page_elements_data":["a:12:{s:13:\"post_elements\";s:6:\"custom\";s:11:\"show_author\";i:0;s:16:\"blog_hide_author\";i:1;s:14:\"blog_hide_date\";i:1;s:26:\"blog_hide_date_in_blog_cat\";i:1;s:20:\"blog_hide_categories\";i:1;s:14:\"blog_hide_tags\";i:1;s:18:\"blog_hide_comments\";i:1;s:15:\"blog_hide_likes\";i:1;s:20:\"blog_hide_navigation\";i:1;s:17:\"blog_hide_socials\";i:1;s:17:\"blog_hide_realted\";i:0;}"],"thegem_popups_data":["a:2:{s:20:\"popups_layout_source\";s:7:\"default\";s:12:\"thegemPopups\";a:1:{i:0;a:14:{s:6:\"active\";s:0:\"\";s:8:\"template\";s:0:\"\";s:8:\"triggers\";a:0:{}s:23:\"show_after_x_page_views\";s:0:\"\";s:15:\"show_page_views\";s:1:\"2\";s:18:\"show_up_to_x_times\";s:0:\"\";s:16:\"show_popup_count\";s:1:\"1\";s:11:\"cookie_time\";s:2:\"30\";s:24:\"hide_for_logged_in_users\";s:0:\"\";s:14:\"show_on_mobile\";s:0:\"\";s:14:\"show_on_tablet\";s:0:\"\";s:17:\"images_preloading\";s:0:\"\";s:2:\"id\";s:25:\"thegem-popup-221414794411\";s:3:\"key\";i:0;}}}"],"thegem_page_data":["a:200:{s:10:\"title_show\";s:7:\"default\";s:11:\"title_style\";s:1:\"2\";s:14:\"title_template\";s:5:\"27835\";s:23:\"title_use_page_settings\";i:1;s:12:\"title_xlarge\";i:0;s:18:\"title_rich_content\";i:0;s:13:\"title_content\";s:0:\"\";s:21:\"title_background_type\";s:5:\"color\";s:22:\"title_background_image\";s:0:\"\";s:29:\"title_background_image_repeat\";i:0;s:27:\"title_background_position_x\";s:6:\"center\";s:27:\"title_background_position_y\";s:3:\"top\";s:21:\"title_background_size\";s:5:\"cover\";s:28:\"title_background_image_color\";s:0:\"\";s:30:\"title_background_image_overlay\";s:0:\"\";s:30:\"title_background_gradient_type\";s:6:\"linear\";s:31:\"title_background_gradient_angle\";i:90;s:34:\"title_background_gradient_position\";s:13:\"center center\";s:38:\"title_background_gradient_point1_color\";s:9:\"#00BCD4BF\";s:41:\"title_background_gradient_point1_position\";i:0;s:38:\"title_background_gradient_point2_color\";s:9:\"#354093BF\";s:41:\"title_background_gradient_point2_position\";i:100;s:23:\"title_background_effect\";s:6:\"normal\";s:36:\"title_background_ken_burns_direction\";s:7:\"zoom_in\";s:43:\"title_background_ken_burns_transition_speed\";i:15000;s:37:\"title_background_video_play_on_mobile\";i:0;s:22:\"title_background_color\";s:7:\"#333144\";s:27:\"title_background_video_type\";s:0:\"\";s:22:\"title_background_video\";s:0:\"\";s:35:\"title_background_video_aspect_ratio\";s:0:\"\";s:36:\"title_background_video_overlay_color\";s:0:\"\";s:38:\"title_background_video_overlay_opacity\";s:0:\"\";s:29:\"title_background_video_poster\";s:0:\"\";s:19:\"title_menu_on_video\";s:0:\"\";s:16:\"title_text_color\";s:7:\"#ffffff\";s:24:\"title_excerpt_text_color\";s:7:\"#ffffff\";s:13:\"title_excerpt\";s:0:\"\";s:18:\"title_hide_excerpt\";i:0;s:17:\"title_title_width\";i:0;s:19:\"title_excerpt_width\";i:0;s:22:\"title_font_preset_html\";s:0:\"\";s:23:\"title_font_preset_style\";s:0:\"\";s:24:\"title_font_preset_weight\";s:0:\"\";s:27:\"title_font_preset_transform\";s:0:\"\";s:30:\"title_excerpt_font_preset_html\";s:0:\"\";s:31:\"title_excerpt_font_preset_style\";s:0:\"\";s:32:\"title_excerpt_font_preset_weight\";s:0:\"\";s:35:\"title_excerpt_font_preset_transform\";s:0:\"\";s:17:\"title_padding_top\";i:80;s:24:\"title_padding_top_tablet\";i:80;s:24:\"title_padding_top_mobile\";i:80;s:20:\"title_padding_bottom\";i:80;s:27:\"title_padding_bottom_tablet\";i:80;s:27:\"title_padding_bottom_mobile\";i:80;s:18:\"title_padding_left\";i:0;s:25:\"title_padding_left_tablet\";i:0;s:25:\"title_padding_left_mobile\";i:0;s:19:\"title_padding_right\";i:0;s:26:\"title_padding_right_tablet\";i:0;s:26:\"title_padding_right_mobile\";i:0;s:16:\"title_top_margin\";s:0:\"\";s:23:\"title_top_margin_tablet\";i:0;s:23:\"title_top_margin_mobile\";i:0;s:24:\"title_excerpt_top_margin\";i:18;s:31:\"title_excerpt_top_margin_tablet\";i:18;s:31:\"title_excerpt_top_margin_mobile\";i:18;s:17:\"title_breadcrumbs\";i:1;s:15:\"title_alignment\";s:0:\"\";s:15:\"title_icon_pack\";s:7:\"elegant\";s:10:\"title_icon\";s:0:\"\";s:16:\"title_icon_color\";s:0:\"\";s:18:\"title_icon_color_2\";s:0:\"\";s:27:\"title_icon_background_color\";s:0:\"\";s:16:\"title_icon_shape\";s:6:\"circle\";s:23:\"title_icon_border_color\";s:0:\"\";s:15:\"title_icon_size\";s:5:\"large\";s:16:\"title_icon_style\";s:0:\"\";s:18:\"title_icon_opacity\";d:0;s:25:\"breadcrumbs_default_color\";s:0:\"\";s:24:\"breadcrumbs_active_color\";s:0:\"\";s:23:\"breadcrumbs_hover_color\";s:0:\"\";s:27:\"title_breadcrumbs_alignment\";s:6:\"center\";s:18:\"header_transparent\";i:0;s:25:\"header_transparent_mobile\";i:0;s:14:\"header_opacity\";i:50;s:22:\"header_menu_logo_light\";i:0;s:20:\"disable_fixed_header\";i:0;s:23:\"sticky_header_on_mobile\";s:0:\"\";s:20:\"header_hide_top_area\";s:7:\"default\";s:27:\"header_hide_top_area_tablet\";s:7:\"default\";s:27:\"header_hide_top_area_mobile\";s:7:\"default\";s:9:\"menu_show\";s:7:\"default\";s:12:\"menu_options\";s:7:\"default\";s:18:\"header_custom_menu\";i:0;s:27:\"header_top_area_transparent\";i:0;s:23:\"header_top_area_opacity\";i:50;s:16:\"top_area_options\";s:7:\"default\";s:13:\"header_source\";s:7:\"default\";s:14:\"header_builder\";s:1:\"0\";s:29:\"header_builder_sticky_desktop\";i:0;s:28:\"header_builder_sticky_mobile\";i:0;s:34:\"header_builder_sticky_hide_desktop\";i:0;s:33:\"header_builder_sticky_hide_mobile\";i:1;s:21:\"header_builder_sticky\";s:1:\"0\";s:29:\"header_builder_sticky_opacity\";i:80;s:26:\"header_builder_light_color\";s:7:\"#FFFFFF\";s:32:\"header_builder_light_color_hover\";s:7:\"#00bcd4\";s:20:\"main_background_type\";s:5:\"color\";s:21:\"main_background_color\";s:7:\"#ffffff\";s:21:\"main_background_image\";s:60:\"https:\/\/kmwllc.com\/wp-content\/uploads\/2022\/11\/Artboard-3.png\";s:28:\"main_background_image_repeat\";s:1:\"1\";s:26:\"main_background_position_x\";s:4:\"left\";s:26:\"main_background_position_y\";s:3:\"top\";s:20:\"main_background_size\";s:4:\"auto\";s:27:\"main_background_image_color\";s:0:\"\";s:29:\"main_background_image_overlay\";s:0:\"\";s:29:\"main_background_gradient_type\";s:6:\"linear\";s:30:\"main_background_gradient_angle\";s:2:\"90\";s:33:\"main_background_gradient_position\";s:0:\"\";s:37:\"main_background_gradient_point1_color\";s:9:\"#E9ECDAFF\";s:40:\"main_background_gradient_point1_position\";s:1:\"0\";s:37:\"main_background_gradient_point2_color\";s:9:\"#D5F6FAFF\";s:40:\"main_background_gradient_point2_position\";s:3:\"100\";s:23:\"main_background_pattern\";s:0:\"\";s:19:\"content_padding_top\";i:50;s:26:\"content_padding_top_tablet\";i:30;s:26:\"content_padding_top_mobile\";i:20;s:22:\"content_padding_bottom\";i:50;s:29:\"content_padding_bottom_tablet\";i:30;s:29:\"content_padding_bottom_mobile\";i:20;s:20:\"content_area_options\";s:6:\"custom\";s:18:\"footer_custom_show\";s:7:\"default\";s:13:\"footer_custom\";s:5:\"28054\";s:19:\"footer_hide_default\";s:7:\"default\";s:23:\"footer_hide_widget_area\";s:7:\"default\";s:16:\"effects_disabled\";i:0;s:17:\"effects_one_pager\";i:0;s:23:\"effects_parallax_footer\";i:0;s:24:\"effects_no_bottom_margin\";i:0;s:21:\"effects_no_top_margin\";i:0;s:19:\"redirect_to_subpage\";i:0;s:19:\"effects_hide_header\";s:7:\"default\";s:19:\"effects_hide_footer\";s:7:\"default\";s:21:\"effects_page_scroller\";i:0;s:28:\"effects_page_scroller_mobile\";i:0;s:26:\"effects_page_scroller_type\";s:8:\"advanced\";s:22:\"fullpage_disabled_dots\";i:0;s:19:\"fullpage_style_dots\";s:7:\"outline\";s:31:\"fullpage_disabled_tooltips_dots\";i:0;s:25:\"fullpage_fixed_background\";b:0;s:26:\"fullpage_enable_continuous\";i:0;s:24:\"fullpage_disabled_mobile\";i:0;s:22:\"fullpage_scroll_effect\";s:6:\"normal\";s:21:\"enable_page_preloader\";s:7:\"default\";s:14:\"slideshow_type\";s:0:\"\";s:19:\"slideshow_slideshow\";s:0:\"\";s:21:\"slideshow_layerslider\";s:0:\"\";s:19:\"slideshow_revslider\";s:0:\"\";s:19:\"slideshow_preloader\";i:0;s:12:\"sidebar_show\";s:7:\"default\";s:16:\"sidebar_position\";s:5:\"right\";s:14:\"sidebar_sticky\";i:0;s:24:\"product_header_separator\";i:0;s:23:\"page_layout_breadcrumbs\";s:7:\"default\";s:37:\"page_layout_breadcrumbs_default_color\";s:9:\"#99A9B5FF\";s:36:\"page_layout_breadcrumbs_active_color\";s:9:\"#3C3950FF\";s:35:\"page_layout_breadcrumbs_hover_color\";s:9:\"#3C3950FF\";s:33:\"page_layout_breadcrumbs_alignment\";s:4:\"left\";s:38:\"page_layout_breadcrumbs_bottom_spacing\";s:1:\"0\";s:37:\"page_layout_breadcrumbs_shop_category\";i:0;s:26:\"delay_js_execution_desktop\";i:0;s:13:\"disable_cache\";i:0;s:23:\"custom_fields_item_data\";N;s:31:\"title_breadcrumbs_shop_category\";s:1:\"0\";s:20:\"title_padding_locked\";s:0:\"\";s:27:\"title_padding_tablet_locked\";s:0:\"\";s:27:\"title_padding_mobile_locked\";s:0:\"\";s:24:\"title_background_pattern\";s:0:\"\";s:30:\"title_background_video_overlay\";s:0:\"\";s:16:\"title_icon__pack\";s:0:\"\";s:21:\"title_icon_shape_show\";s:0:\"\";s:25:\"footer_widget_woocommerce\";s:1:\"1\";s:25:\"delay_js_execution_mobile\";s:1:\"0\";s:18:\"custom_fields_data\";s:0:\"\";s:14:\"page_item_data\";a:3:{s:20:\"page_layout_settings\";s:7:\"default\";s:18:\"page_layout_source\";s:7:\"default\";s:21:\"page_builder_template\";s:0:\"\";}s:19:\"portfolio_item_data\";a:35:{s:25:\"portfolio_layout_settings\";s:7:\"default\";s:23:\"portfolio_layout_source\";s:7:\"default\";s:26:\"portfolio_builder_template\";s:0:\"\";s:8:\"back_url\";s:0:\"\";s:9:\"highlight\";s:0:\"\";s:14:\"highlight_type\";s:0:\"\";s:14:\"overview_title\";s:0:\"\";s:16:\"overview_summary\";s:0:\"\";s:12:\"project_link\";s:0:\"\";s:12:\"project_text\";s:0:\"\";s:9:\"fullwidth\";s:0:\"\";s:19:\"project_button_show\";s:0:\"\";s:20:\"grid_appearance_type\";s:14:\"featured_image\";s:30:\"grid_appearance_featured_image\";s:0:\"\";s:19:\"grid_appearance_gif\";s:0:\"\";s:25:\"grid_appearance_gif_start\";s:8:\"autoplay\";s:26:\"grid_appearance_gif_poster\";s:0:\"\";s:27:\"grid_appearance_gif_preload\";s:0:\"\";s:21:\"grid_appearance_video\";s:0:\"\";s:26:\"grid_appearance_video_type\";s:0:\"\";s:34:\"grid_appearance_video_aspect_ratio\";s:0:\"\";s:36:\"grid_appearance_video_play_on_mobile\";s:0:\"\";s:29:\"grid_appearance_video_overlay\";s:0:\"\";s:28:\"grid_appearance_video_poster\";s:0:\"\";s:27:\"grid_appearance_video_start\";s:8:\"autoplay\";s:34:\"grid_appearance_gallery_autoscroll\";s:1:\"1\";s:40:\"grid_appearance_gallery_autoscroll_speed\";s:4:\"3000\";s:30:\"grid_appearance_image_behavior\";s:12:\"link_to_page\";s:28:\"grid_appearance_gif_behavior\";s:12:\"link_to_page\";s:30:\"grid_appearance_video_behavior\";s:12:\"link_to_page\";s:32:\"grid_appearance_gallery_behavior\";s:12:\"link_to_page\";s:31:\"grid_appearance_behavior_target\";s:5:\"_self\";s:36:\"grid_appearance_behavior_custom_link\";s:0:\"\";s:43:\"grid_appearance_behavior_custom_link_target\";s:5:\"_self\";s:30:\"grid_appearance_lightbox_image\";s:0:\"\";}s:23:\"portfolio_elements_data\";a:7:{s:23:\"portfolio_page_elements\";s:7:\"default\";s:19:\"portfolio_hide_date\";s:0:\"\";s:19:\"portfolio_hide_sets\";s:0:\"\";s:20:\"portfolio_hide_likes\";s:0:\"\";s:22:\"portfolio_hide_socials\";s:0:\"\";s:29:\"portfolio_hide_top_navigation\";s:0:\"\";s:32:\"portfolio_hide_bottom_navigation\";s:0:\"\";}s:17:\"product_item_data\";a:117:{s:9:\"highlight\";s:0:\"\";s:14:\"highlight_type\";s:7:\"squared\";s:28:\"thegem_product_disable_hover\";s:1:\"0\";s:10:\"size_guide\";s:7:\"default\";s:16:\"size_guide_image\";s:0:\"\";s:15:\"size_guide_text\";s:10:\"Size guide\";s:23:\"product_layout_settings\";s:7:\"default\";s:21:\"product_layout_source\";s:7:\"default\";s:24:\"product_builder_template\";s:0:\"\";s:19:\"product_page_layout\";s:7:\"default\";s:25:\"product_page_layout_style\";s:15:\"horizontal_tabs\";s:28:\"product_page_layout_centered\";s:1:\"0\";s:39:\"product_page_layout_centered_top_margin\";s:2:\"42\";s:34:\"product_page_layout_centered_boxed\";s:1:\"0\";s:40:\"product_page_layout_centered_boxed_color\";s:0:\"\";s:29:\"product_page_layout_fullwidth\";s:1:\"0\";s:26:\"product_page_layout_sticky\";s:1:\"0\";s:33:\"product_page_layout_sticky_offset\";s:1:\"0\";s:28:\"product_page_skeleton_loader\";s:1:\"0\";s:30:\"product_page_layout_background\";s:0:\"\";s:30:\"product_page_layout_title_area\";s:8:\"disabled\";s:29:\"product_page_ajax_add_to_cart\";s:1:\"1\";s:31:\"product_page_desc_review_source\";s:17:\"extra_description\";s:31:\"product_page_desc_review_layout\";s:4:\"tabs\";s:42:\"product_page_desc_review_layout_tabs_style\";s:10:\"horizontal\";s:46:\"product_page_desc_review_layout_tabs_alignment\";s:4:\"left\";s:44:\"product_page_desc_review_layout_acc_position\";s:13:\"below_gallery\";s:65:\"product_page_desc_review_layout_one_by_one_description_background\";s:9:\"#F4F6F7FF\";s:69:\"product_page_desc_review_layout_one_by_one_additional_info_background\";s:9:\"#FFFFFFFF\";s:61:\"product_page_desc_review_layout_one_by_one_reviews_background\";s:9:\"#F4F6F7FF\";s:36:\"product_page_desc_review_description\";s:1:\"1\";s:42:\"product_page_desc_review_description_title\";s:11:\"Description\";s:40:\"product_page_desc_review_additional_info\";s:1:\"1\";s:46:\"product_page_desc_review_additional_info_title\";s:15:\"Additional Info\";s:32:\"product_page_desc_review_reviews\";s:1:\"1\";s:38:\"product_page_desc_review_reviews_title\";s:7:\"Reviews\";s:36:\"product_page_button_add_to_cart_text\";s:11:\"Add to Cart\";s:36:\"product_page_button_add_to_cart_icon\";s:4:\"f1e7\";s:41:\"product_page_button_add_to_cart_icon_pack\";s:8:\"material\";s:45:\"product_page_button_add_to_cart_icon_position\";s:4:\"left\";s:40:\"product_page_button_add_to_wishlist_icon\";s:4:\"f37b\";s:45:\"product_page_button_add_to_wishlist_icon_pack\";s:8:\"material\";s:42:\"product_page_button_added_to_wishlist_icon\";s:4:\"f377\";s:47:\"product_page_button_added_to_wishlist_icon_pack\";s:8:\"material\";s:41:\"product_page_button_clear_attributes_text\";s:15:\"Clear selection\";s:31:\"product_page_elements_prev_next\";s:1:\"1\";s:38:\"product_page_elements_preview_on_hover\";s:1:\"1\";s:34:\"product_page_elements_back_to_shop\";s:1:\"1\";s:39:\"product_page_elements_back_to_shop_link\";s:9:\"main_shop\";s:50:\"product_page_elements_back_to_shop_link_custom_url\";s:0:\"\";s:27:\"product_page_elements_title\";s:1:\"1\";s:32:\"product_page_elements_attributes\";s:1:\"0\";s:37:\"product_page_elements_attributes_data\";s:0:\"\";s:29:\"product_page_elements_reviews\";s:1:\"1\";s:34:\"product_page_elements_reviews_text\";s:16:\"customer reviews\";s:27:\"product_page_elements_price\";s:1:\"1\";s:41:\"product_page_elements_price_strikethrough\";s:1:\"1\";s:33:\"product_page_elements_description\";s:1:\"1\";s:34:\"product_page_elements_stock_amount\";s:1:\"1\";s:39:\"product_page_elements_stock_amount_text\";s:17:\"Products in stock\";s:32:\"product_page_elements_size_guide\";s:1:\"1\";s:25:\"product_page_elements_sku\";s:1:\"1\";s:31:\"product_page_elements_sku_title\";s:3:\"SKU\";s:32:\"product_page_elements_categories\";s:1:\"1\";s:38:\"product_page_elements_categories_title\";s:10:\"Categories\";s:26:\"product_page_elements_tags\";s:1:\"1\";s:32:\"product_page_elements_tags_title\";s:4:\"Tags\";s:27:\"product_page_elements_share\";s:1:\"1\";s:33:\"product_page_elements_share_title\";s:5:\"Share\";s:36:\"product_page_elements_share_facebook\";s:1:\"1\";s:35:\"product_page_elements_share_twitter\";s:1:\"1\";s:37:\"product_page_elements_share_pinterest\";s:1:\"1\";s:34:\"product_page_elements_share_tumblr\";s:1:\"1\";s:36:\"product_page_elements_share_linkedin\";s:1:\"1\";s:34:\"product_page_elements_share_reddit\";s:1:\"1\";s:28:\"product_page_elements_upsell\";s:1:\"1\";s:34:\"product_page_elements_upsell_title\";s:17:\"You may also like\";s:44:\"product_page_elements_upsell_title_alignment\";s:4:\"left\";s:34:\"product_page_elements_upsell_items\";s:2:\"-1\";s:44:\"product_page_elements_upsell_columns_desktop\";s:2:\"4x\";s:43:\"product_page_elements_upsell_columns_tablet\";s:2:\"3x\";s:43:\"product_page_elements_upsell_columns_mobile\";s:2:\"2x\";s:40:\"product_page_elements_upsell_columns_100\";s:1:\"5\";s:29:\"product_page_elements_related\";s:1:\"1\";s:35:\"product_page_elements_related_title\";s:16:\"Related Products\";s:45:\"product_page_elements_related_title_alignment\";s:4:\"left\";s:35:\"product_page_elements_related_items\";s:2:\"-1\";s:45:\"product_page_elements_related_columns_desktop\";s:2:\"4x\";s:44:\"product_page_elements_related_columns_tablet\";s:2:\"3x\";s:44:\"product_page_elements_related_columns_mobile\";s:2:\"2x\";s:41:\"product_page_elements_related_columns_100\";s:1:\"5\";s:28:\"product_page_additional_tabs\";s:7:\"default\";s:33:\"product_page_additional_tabs_data\";s:0:\"\";s:15:\"product_gallery\";s:7:\"enabled\";s:20:\"product_gallery_type\";s:10:\"horizontal\";s:31:\"product_gallery_thumb_on_mobile\";s:1:\"0\";s:31:\"product_gallery_column_position\";s:4:\"left\";s:30:\"product_gallery_thumb_position\";s:4:\"left\";s:28:\"product_gallery_column_width\";s:2:\"50\";s:26:\"product_gallery_show_image\";s:5:\"hover\";s:27:\"product_gallery_image_ratio\";s:0:\"\";s:31:\"product_gallery_grid_image_size\";s:7:\"default\";s:32:\"product_gallery_grid_image_ratio\";s:0:\"\";s:20:\"product_gallery_zoom\";s:1:\"1\";s:24:\"product_gallery_lightbox\";s:1:\"1\";s:22:\"product_gallery_labels\";s:1:\"1\";s:26:\"product_gallery_label_sale\";s:1:\"1\";s:25:\"product_gallery_label_new\";s:1:\"1\";s:31:\"product_gallery_label_out_stock\";s:1:\"1\";s:27:\"product_gallery_auto_height\";s:1:\"1\";s:30:\"product_gallery_elements_color\";s:0:\"\";s:28:\"product_gallery_grid_columns\";s:2:\"1x\";s:25:\"product_gallery_grid_gaps\";s:2:\"42\";s:30:\"product_gallery_grid_gaps_hide\";s:1:\"0\";s:31:\"product_gallery_grid_top_margin\";s:1:\"0\";s:30:\"product_gallery_video_autoplay\";s:1:\"0\";s:32:\"product_page_elements_title_html\";s:0:\"\";}s:25:\"product_archive_item_data\";a:5:{s:29:\"product_archive_layout_source\";s:7:\"default\";s:32:\"product_archive_builder_template\";s:0:\"\";s:24:\"products_layout_settings\";s:7:\"default\";s:22:\"products_layout_source\";s:7:\"default\";s:25:\"products_builder_template\";s:0:\"\";}s:22:\"blog_archive_item_data\";a:3:{s:28:\"blog_archive_layout_settings\";s:7:\"default\";s:26:\"blog_archive_layout_source\";s:7:\"default\";s:29:\"blog_archive_builder_template\";s:0:\"\";}s:24:\"custom_archive_item_data\";a:6:{s:15:\"layout_settings\";s:7:\"default\";s:13:\"layout_source\";s:7:\"default\";s:16:\"builder_template\";s:0:\"\";s:21:\"posts_layout_settings\";s:7:\"default\";s:19:\"posts_layout_source\";s:7:\"default\";s:22:\"posts_builder_template\";s:0:\"\";}s:21:\"custom_post_item_data\";a:26:{s:15:\"layout_settings\";s:7:\"default\";s:13:\"layout_source\";s:7:\"default\";s:16:\"builder_template\";s:0:\"\";s:10:\"video_type\";s:0:\"\";s:18:\"video_aspect_ratio\";s:0:\"\";s:5:\"video\";s:0:\"\";s:20:\"video_play_on_mobile\";s:0:\"\";s:13:\"video_overlay\";s:0:\"\";s:12:\"video_poster\";s:0:\"\";s:11:\"video_start\";s:16:\"open_in_lightbox\";s:5:\"audio\";s:0:\"\";s:10:\"quote_text\";s:0:\"\";s:12:\"quote_author\";s:0:\"\";s:16:\"quote_background\";s:0:\"\";s:18:\"quote_author_color\";s:0:\"\";s:7:\"gallery\";s:0:\"\";s:18:\"gallery_autoscroll\";s:4:\"1500\";s:26:\"show_featured_posts_slider\";s:0:\"\";s:21:\"show_featured_content\";s:0:\"\";s:9:\"highlight\";s:0:\"\";s:14:\"highlight_type\";s:0:\"\";s:15:\"highlight_style\";s:0:\"\";s:31:\"highlight_title_left_background\";s:9:\"#00BCD4FF\";s:32:\"highlight_title_right_background\";s:9:\"#00BCD4FF\";s:26:\"highlight_title_left_color\";s:9:\"#FFFFFFFF\";s:27:\"highlight_title_right_color\";s:9:\"#FFFFFFFF\";}s:24:\"options_current_contents\";N;s:16:\"options_modified\";N;s:34:\"options_outside_parameter_modified\";b:0;s:22:\"options_saved_contents\";N;s:8:\"settings\";a:3:{s:5:\"theme\";s:5:\"light\";s:24:\"background_image_gallery\";a:0:{}s:21:\"colorpicker_favorites\";a:1:{s:7:\"default\";a:0:{}}}s:19:\"fullpage_dots_color\";s:0:\"\";s:33:\"fullpage_dots_tolltips_text_color\";s:0:\"\";s:31:\"fullpage_dots_tolltips_bg_color\";s:0:\"\";}"],"_yoast_wpseo_primary_category":["46"],"_yoast_wpseo_estimated-reading-time-minutes":["13"],"_yoast_wpseo_wordproof_timestamp":[""],"_elementor_template_type":["wp-post"],"_elementor_version":["3.25.10"],"_elementor_pro_version":["3.22.1"],"_elementor_data":["[{\"id\":\"b9d2795\",\"elType\":\"section\",\"settings\":{\"structure\":\"30\"},\"elements\":[{\"id\":\"849c1d1\",\"elType\":\"column\",\"settings\":{\"_column_size\":33,\"_inline_size\":65,\"thegem_column_breakpoints_list\":[],\"_inline_size_tablet\":100},\"elements\":[{\"id\":\"1298f9a\",\"elType\":\"widget\",\"settings\":{\"icon_list\":[{\"selected_icon\":{\"value\":\"fas fa-calendar\",\"library\":\"fa-solid\"},\"_id\":\"91a0f52\",\"custom_date_format\":\"F j, Y\",\"custom_time_format\":\"g:i a\",\"link\":\"\",\"show_icon\":\"none\"}],\"icon_typography_typography\":\"custom\",\"__globals__\":{\"text_color\":\"globals\\\/colors?id=primary\"}},\"elements\":[],\"widgetType\":\"post-info\"},{\"id\":\"cb40088\",\"elType\":\"widget\",\"settings\":{\"title\":\"Add Your Heading Text Here\",\"header_size\":\"div\",\"thegem_heading_style\":\"styled-subtitle\",\"__dynamic__\":{\"title\":\"[elementor-tag id=\\\"7b6ad14\\\" name=\\\"thegem-post-excerpt\\\" settings=\\\"%7B%7D\\\"]\"}},\"elements\":[],\"widgetType\":\"heading\"},{\"id\":\"984b5d3\",\"elType\":\"widget\",\"settings\":{\"source\":\"custom\",\"author_avatar\":{\"url\":\"https:\\\/\\\/kmwllccom.stage.site\\\/wp-content\\\/uploads\\\/2024\\\/01\\\/Abijit2023.png\",\"id\":29652,\"alt\":\"\",\"source\":\"library\",\"size\":\"\"},\"author_name\":\"Abijit Rangesh\",\"author_name_tag\":\"div\",\"author_bio\":\"Search Engineer at KMW Technology\",\"link_text\":\"All Posts\",\"image_vertical_align\":\"top\",\"image_border\":\"yes\",\"image_border_width\":{\"unit\":\"px\",\"size\":3,\"sizes\":[]},\"image_border_radius\":{\"unit\":\"px\",\"size\":100,\"sizes\":[]},\"name_gap\":{\"unit\":\"px\",\"size\":0,\"sizes\":[]},\"__globals__\":{\"image_border_color\":\"globals\\\/colors?id=428f277\",\"bio_color\":\"globals\\\/colors?id=secondary\"},\"_padding\":{\"unit\":\"em\",\"top\":\"2\",\"right\":\"2\",\"bottom\":\"2\",\"left\":\"2\",\"isLinked\":true},\"_padding_tablet\":{\"unit\":\"em\",\"top\":\"\",\"right\":\"\",\"bottom\":\"\",\"left\":\"\",\"isLinked\":true},\"_padding_mobile\":{\"unit\":\"em\",\"top\":\"\",\"right\":\"\",\"bottom\":\"\",\"left\":\"\",\"isLinked\":true}},\"elements\":[],\"widgetType\":\"author-box\"},{\"id\":\"57774d5\",\"elType\":\"widget\",\"settings\":{\"text\":\"Divider\",\"weight\":{\"unit\":\"px\",\"size\":3,\"sizes\":[]},\"gap\":{\"unit\":\"px\",\"size\":0,\"sizes\":[]},\"__globals__\":{\"color\":\"globals\\\/colors?id=428f277\"}},\"elements\":[],\"widgetType\":\"divider\"},{\"id\":\"2f6bf75\",\"elType\":\"widget\",\"settings\":[],\"elements\":[],\"widgetType\":\"spacer\"},{\"id\":\"6d550b8\",\"elType\":\"widget\",\"settings\":{\"title\":\"What We\\u2019ve Accomplished\",\"size\":\"large\"},\"elements\":[],\"widgetType\":\"heading\"},{\"id\":\"c3fec1d\",\"elType\":\"widget\",\"settings\":{\"editor\":\"<p><span style=\\\"font-weight: 400;\\\">In Lucene-based search engines like OpenSearch and Solr, keyword aggregations ignore duplicate values that occur within a multi-valued field. If a document has a multi-valued field containing the values [\\\"foo\\\", \\\"foo\\\", \\\"bar\\\"] then an aggregation would increment the count for the \\\"foo\\\" and \\u201cbar\\u201d bucket once, even though \\u201cfoo\\u201d occurs twice. We built an OpenSearch plugin to overcome this limitation.<\\\/span><\\\/p>\\n<p><span style=\\\"font-weight: 400;\\\">In this blog post, we detail the investigation process into duplicate terms aggregation solutions and the subsequent development process by which a plug-in was built for OpenSearch. Previously, only the nested field type and scripted aggregation methods seemed to be viable solutions. Our plug-in aims to be a third option to solve this problem. This plug-in serves to be the fastest solution for a duplicate terms aggregation on a multivalued keyword field in OpenSearch without compromising index size.<\\\/span><\\\/p>\\n<p><span style=\\\"font-weight: 400;\\\">The link to the plug-in repository can be found <\\\/span><a href=\\\"https:\\\/\\\/github.com\\\/kmwtechnology\\\/opensearch-duplicate-terms-agg\\\"><span style=\\\"font-weight: 400;\\\">here<\\\/span><\\\/a><span style=\\\"font-weight: 400;\\\">. Please follow the steps in the README.md to install this plug-in into an OpenSearch distribution and interact with the custom aggregation.\\u00a0<\\\/span><\\\/p>\"},\"elements\":[],\"widgetType\":\"text-editor\"},{\"id\":\"0ef200a\",\"elType\":\"widget\",\"settings\":[],\"elements\":[],\"widgetType\":\"spacer\"},{\"id\":\"26d3771\",\"elType\":\"widget\",\"settings\":{\"title\":\"The Problem  \",\"size\":\"large\"},\"elements\":[],\"widgetType\":\"heading\"},{\"id\":\"c0b7446\",\"elType\":\"widget\",\"settings\":{\"editor\":\"<p><span style=\\\"font-weight: 400;\\\">Imagine you\\u2019re rummaging through your attic at your family home and you\\u2019ve found a large recipe book. It seems to be something your great-grandmother cherished. As both a devoted great-grandchild and a fan of search solutions, you\\u2019d like to catalogue the data found in this recipe book in a search engine, specifically OpenSearch.\\u00a0<\\\/span><\\\/p><p><span style=\\\"font-weight: 400;\\\">You wish to represent each recipe as a document and each document would store fields for different aspects of the recipe: cook_time, steps, technique, ingredients, etc. Ingredients could have duplicate values, designating how many of them to include i.e. [carrot, carrot, apple, cucumber] would represent 2 carrots, 1 apple, and 1 cucumber for our recipe.\\u00a0<\\\/span><\\\/p><p><span style=\\\"font-weight: 400;\\\">Upon completion of your index, you wish to aggregate upon all the ingredients and find out how many of each ingredient to purchase in order to make all of your great grandmother\\u2019s recipes. You notice a problem quite quickly: OpenSearch aggregations do not take into account duplicate values on multi-valued fields. While the recipes may have called for a total of three carrots (two for one recipe and one for a different recipe), the aggregation result only tells you to buy two (one for each recipe).<\\\/span><\\\/p>\"},\"elements\":[],\"widgetType\":\"text-editor\"},{\"id\":\"199285c\",\"elType\":\"widget\",\"settings\":{\"code\":\"Documents & Aggregation: \\r\\n\\r\\ncurl -XPUT \\\"http:\\\/\\\/localhost:9200\\\/recipe-book\\\/_doc\\\/1\\\" -H 'Content-Type: application\\\/json' -d'\\r\\n{\\r\\n  \\\"favorite_foods\\\": [\\\"carrot\\\", \\\"carrot\\\", \\\"apple\\\", \\\"cucumber\\\"]\\r\\n}'\\r\\n\\r\\ncurl -XPUT \\\"http:\\\/\\\/localhost:9200\\\/recipe-book\\\/_doc\\\/2\\\" -H 'Content-Type: application\\\/json' -d'\\r\\n{\\r\\n  \\\"favorite_foods\\\": [\\\"carrot\\\", \\\"apple\\\", \\\"cucumber\\\"]\\r\\n}'\\r\\n\\r\\ncurl -XPUT \\\"http:\\\/\\\/localhost:9200\\\/recipe-book\\\/_doc\\\/3\\\" -H 'Content-Type: application\\\/json' -d'\\r\\n{\\r\\n  \\\"favorite_foods\\\": [\\\"cucumber\\\", \\\"cucumber\\\", \\\"cucumber\\\"]\\r\\n}'\\r\\n\\r\\ncurl -XGET \\\"http:\\\/\\\/localhost:9200\\\/recipe-book\\\/_search\\\" -H 'Content-Type: application\\\/json' -d'\\r\\n{\\r\\n  \\\"size\\\": 0,\\r\\n  \\\"aggregations\\\": {\\r\\n    \\\"ingredient_frequency\\\": {\\r\\n      \\\"terms\\\": {\\r\\n   \\t   \\\"field\\\": \\\"favorite_foods\\\"\\r\\n      }\\r\\n    }\\r\\n  }\\r\\n}'\\r\\n\\r\\nResult: \\r\\n\\\"aggregations\\\":{\\r\\n  \\t\\\"ingredient_frequency\\\":{\\r\\n     \\t  \\\"doc_count_error_upper_bound\\\":0,\\r\\n     \\t  \\\"sum_other_doc_count\\\":0,\\r\\n     \\t  \\\"buckets\\\":[\\r\\n        \\t{\\r\\n           \\t\\\"key\\\":\\\"cucumber\\\",\\r\\n           \\t\\\"doc_count\\\":3\\r\\n        \\t},\\r\\n        \\t{\\r\\n           \\t\\\"key\\\":\\\"apple\\\",\\r\\n           \\t\\\"doc_count\\\":2\\r\\n        \\t},\\r\\n        \\t{\\r\\n           \\t\\\"key\\\":\\\"carrot\\\",\\r\\n           \\t\\\"doc_count\\\":2\\r\\n        \\t}\\r\\n     \\t  ]\\r\\n  \\t}\\r\\n}\\r\\n\\r\\n\",\"line_numbers\":\"\",\"word_wrap\":\"word-wrap\",\"theme\":\"tomorrow\"},\"elements\":[],\"widgetType\":\"code-highlight\"},{\"id\":\"aecaba2\",\"elType\":\"widget\",\"settings\":{\"title\":\"Delving Deeper Into the Problem\",\"size\":\"large\",\"header_size\":\"h3\"},\"elements\":[],\"widgetType\":\"heading\"},{\"id\":\"9759dbb\",\"elType\":\"widget\",\"settings\":{\"editor\":\"<p><span style=\\\"font-weight: 400;\\\">Why is it that OpenSearch is unable to perform aggregations on duplicate values in keyword fields? Behind the scenes, OpenSearch is using a doc_values data structure for operations like aggregations, as they perform far better than the traditional inverted-index data structure. The specific type of doc_values supported by Lucene for keyword fields do not store duplicate values. Conversely, a match_all query would return us duplicate values as it would be using a segment lookup unlike aggregations which would be using the aforementioned doc_values data structure.\\u00a0<\\\/span><\\\/p><p><span style=\\\"font-weight: 400;\\\">The following <\\\/span><a href=\\\"https:\\\/\\\/solr.apache.org\\\/guide\\\/8_7\\\/docvalues.html\\\"><span style=\\\"font-weight: 400;\\\">link<\\\/span><\\\/a><span style=\\\"font-weight: 400;\\\"> provides more information about specific field types and whether they support duplicates or not. Note that while this links to Solr documentation and presents Solr specific information, the section on docValues types is a Lucene specific implementation detail that applies to OpenSearch as well.\\u00a0<\\\/span><\\\/p>\"},\"elements\":[],\"widgetType\":\"text-editor\"},{\"id\":\"495477a\",\"elType\":\"widget\",\"settings\":{\"title\":\"Scripting\",\"size\":\"medium\",\"header_size\":\"h3\"},\"elements\":[],\"widgetType\":\"heading\"},{\"id\":\"ecffa21\",\"elType\":\"widget\",\"settings\":{\"editor\":\"<p><span style=\\\"font-weight: 400;\\\">OpenSearch offers users the ability to include scripts with aggregations via the \\u201cscripted_metric\\u201d aggregation type. This leverages the painless scripting language, built specifically for Elasticsearch (and subsequently OpenSearch). Painless has Java-like syntax and compiles directly into JVM bytecode, leveraging any optimizations that the JVM has.\\u00a0<\\\/span><\\\/p><p><span style=\\\"font-weight: 400;\\\">With painless, we have access to the \\u201c_source\\u201d variable that offers us the ability to view the segment data on specific fields. With this approach, we should be able to access duplicates on our keyword field type and aggregate them together via a hashmap defined by our script.\\u00a0<\\\/span><\\\/p><p><span style=\\\"font-weight: 400;\\\">Here\\u2019s what the script looked like inside of an aggregation query:<\\\/span><\\\/p>\"},\"elements\":[],\"widgetType\":\"text-editor\"},{\"id\":\"e071421\",\"elType\":\"widget\",\"settings\":{\"code\":\"{\\r\\n\\t\\\"size\\\": 0,\\r\\n\\t\\\"aggs\\\": {\\r\\n    \\t\\\"ingredient_frequency\\\": {\\r\\n      \\t\\\"scripted_metric\\\": {\\r\\n        \\t\\\"init_script\\\": \\\"state.foodFreq = new HashMap();\\\",\\r\\n        \\t\\\"map_script\\\": \\\"for (f in params._source.favorite_foods) { if (state.foodFreq.get(f) == null) { state.foodFreq.put(f, 1); } else { state.foodFreq.put(f, state.foodFreq.get(f) + 1); }}\\\",\\r\\n        \\t\\\"combine_script\\\": \\\"return state.foodFreq;\\\",\\r\\n        \\t\\\"reduce_script\\\": \\\"\\\"\\\"\\r\\nMap finalMap = new HashMap(); \\r\\nfor (map in states) { \\r\\n for (key in map.keySet()) { \\r\\n  if (finalMap.get(key) == null) { \\r\\n   def val = map[key]; \\r\\n   finalMap.put(key, map[key]); \\r\\n  } \\r\\n  else {\\r\\n   def prevVal = finalMap[key]; \\r\\n   finalMap.put(key, prevVal + map[key]); \\r\\n  }\\r\\n  }\\r\\n} \\r\\nreturn finalMap;\\r\\n\\\"\\\"\\\"\\r\\n      \\t}\\r\\n    \\t}\\r\\n  \\t    }\\r\\n  }\\r\\n\",\"line_numbers\":\"\",\"word_wrap\":\"word-wrap\",\"theme\":\"tomorrow\"},\"elements\":[],\"widgetType\":\"code-highlight\"},{\"id\":\"9529a53\",\"elType\":\"widget\",\"settings\":{\"editor\":\"<p><span style=\\\"font-weight: 400;\\\">Notice that this is quite brute-force. We have to account for each and every value, place them in a hashmap, and then combine these hashmaps across shards via the \\u201creduce_script\\u201d. Also, we don\\u2019t leverage the highly performant doc_values data structure, built for aggregations. We know this, as we are accessing \\u201c_source\\u201d which takes information directly from Lucene segments, rather than from doc_values. In the benchmarking section, these observations will be substantiated by our gathered performance statistics.\\u00a0<\\\/span><\\\/p><p><span style=\\\"font-weight: 400;\\\">For more information on the scripted_metric aggregation, here\\u2019s a link to <\\\/span><a href=\\\"https:\\\/\\\/www.elastic.co\\\/guide\\\/en\\\/elasticsearch\\\/reference\\\/current\\\/modules-scripting-painless.html\\\"><span style=\\\"font-weight: 400;\\\">official documentation<\\\/span><\\\/a><span style=\\\"font-weight: 400;\\\">.<\\\/span><\\\/p>\"},\"elements\":[],\"widgetType\":\"text-editor\"},{\"id\":\"8a8978f\",\"elType\":\"widget\",\"settings\":{\"title\":\"Nested Fields\",\"size\":\"medium\",\"header_size\":\"h3\"},\"elements\":[],\"widgetType\":\"heading\"},{\"id\":\"f6f6630\",\"elType\":\"widget\",\"settings\":{\"editor\":\"<p><span style=\\\"font-weight: 400;\\\">Scripting worked within the confines of our original organisation of the recipe book. We wanted our ingredients to be represented in a multi-valued field. However, if we can\\u2019t see duplicate values across multi-valued fields due to the doc_value limitation, why not try to change how the documents themselves are indexed?<\\\/span><\\\/p><p><span style=\\\"font-weight: 400;\\\">\\u00a0<\\\/span><span style=\\\"font-weight: 400;\\\">OpenSearch offers users the ability to create inner or \\u201cnested\\u201d documents within other documents. Each nested document is underlyingly treated as a \\u201chidden\\u201d Lucene document, allowing for a nested aggregation that would guarantee that we would be able to see duplicate documents.\\u00a0<\\\/span><\\\/p><p><span style=\\\"font-weight: 400;\\\">We can implement this, simply, with the following:<\\\/span><\\\/p>\"},\"elements\":[],\"widgetType\":\"text-editor\"},{\"id\":\"71c1c92\",\"elType\":\"widget\",\"settings\":{\"code\":\"PUT \\\/recipe-book\\r\\n{\\r\\n  \\\"mappings\\\": {\\r\\n    \\\"properties\\\": {\\r\\n      \\\"favorite_foods\\\": {\\r\\n   \\t \\\"type\\\": \\\"nested\\\",\\r\\n   \\t \\\"properties\\\": {\\r\\n \\t\\t \\\"food\\\": {\\r\\n \\t\\t \\\"type\\\": \\\"keyword\\\"\\r\\n \\t\\t }\\r\\n   \\t  }\\r\\n     }\\r\\n    }\\r\\n  }\\r\\n}   \\r\\n\\r\\nPUT \\\/recipe-book\\\/_doc\\\/1\\r\\n{\\r\\n  \\\"favorite_foods\\\": [\\r\\n    {\\r\\n      \\\"food\\\": \\\"carrot\\\"\\r\\n    },\\r\\n    {\\r\\n      \\\"food\\\": \\\"carrot\\\"\\r\\n    },\\r\\n    {\\r\\n      \\\"food\\\": \\\"apple\\\"\\r\\n    },\\r\\n    {\\r\\n      \\\"food\\\": \\\"cucumber\\\"\\r\\n    }\\r\\n  ]\\r\\n}\\r\\n\\r\\nPUT \\\/recipe-book\\\/_doc\\\/2\\r\\n{\\r\\n  \\\"favorite_foods\\\": [\\r\\n    {\\r\\n      \\\"food\\\": \\\"carrot\\\"\\r\\n    },\\r\\n    {\\r\\n      \\\"food\\\": \\\"apple\\\"\\r\\n    },\\r\\n    {\\r\\n      \\\"food\\\": \\\"cucumber\\\"\\r\\n    }\\r\\n  ]\\r\\n}\\r\\n\\r\\nPUT \\\/recipe-book\\\/_doc\\\/3\\r\\n{\\r\\n  \\\"favorite_foods\\\": [\\r\\n    {\\r\\n      \\\"food\\\": \\\"cucumber\\\"\\r\\n    },\\r\\n    {\\r\\n      \\\"food\\\": \\\"cucumber\\\"\\r\\n    },\\r\\n    {\\r\\n      \\\"food\\\": \\\"cucumber\\\"\\r\\n    }\\r\\n  ]\\r\\n}\\r\\n\\r\\n{\\r\\n  \\\"size\\\": 0,\\r\\n  \\\"aggs\\\": {\\r\\n\\t\\\"favorite_foods\\\": {\\r\\n  \\t\\\"nested\\\": {\\r\\n    \\t\\\"path\\\": \\\"favorite_foods\\\"\\r\\n  \\t},\\r\\n  \\t\\\"aggs\\\": {\\r\\n    \\t\\\"food_freq\\\": {\\r\\n      \\t\\\"terms\\\": {\\r\\n        \\t\\\"size\\\": 10000,\\r\\n        \\t\\\"field\\\": \\\"favorite_foods.data\\\"\\r\\n      \\t}\\r\\n    \\t}\\r\\n    \\t}\\r\\n    \\t}\\r\\n  }\\r\\n}\\r\\n\\r\\n\\\"aggregations\\\": {\\r\\n\\t\\\"favorite_foods\\\": {\\r\\n  \\t\\\"doc_count\\\": 10,\\r\\n  \\t\\\"food_freq\\\": {\\r\\n    \\t\\\"doc_count_error_upper_bound\\\": 0,\\r\\n    \\t\\\"sum_other_doc_count\\\": 0,\\r\\n    \\t\\\"buckets\\\": [\\r\\n      \\t{\\r\\n        \\t\\\"key\\\": \\\"cucumber\\\",\\r\\n        \\t\\\"doc_count\\\": 5\\r\\n      \\t},\\r\\n      \\t{\\r\\n        \\t\\\"key\\\": \\\"carrot\\\",\\r\\n        \\t\\\"doc_count\\\": 3\\r\\n      \\t},\\r\\n      \\t{\\r\\n        \\t\\\"key\\\": \\\"apple\\\",\\r\\n        \\t\\\"doc_count\\\": 2\\r\\n      \\t}\\r\\n    \\t]\\r\\n  \\t    }\\r\\n\\t    }\\r\\n}\",\"line_numbers\":\"\",\"word_wrap\":\"word-wrap\",\"theme\":\"tomorrow\"},\"elements\":[],\"widgetType\":\"code-highlight\"},{\"id\":\"ba484a2\",\"elType\":\"widget\",\"settings\":{\"editor\":\"<p><span style=\\\"font-weight: 400;\\\">This implementation is simple at first glance, but this approach can quickly cause problems at scale. Nested documents are inherently documents, therefore they take up their own space in the index. 200 recipes with 20 average ingredients in each would lead to over 4000 documents. Again, we\\u2019ll see how this implementation fares in our benchmarks.\\u00a0<\\\/span><\\\/p><p><span style=\\\"font-weight: 400;\\\">For more information on the nested field aggregations, here\\u2019s a link to <\\\/span><a href=\\\"https:\\\/\\\/www.elastic.co\\\/guide\\\/en\\\/elasticsearch\\\/reference\\\/current\\\/search-aggregations-bucket-nested-aggregation.html\\\"><span style=\\\"font-weight: 400;\\\">official documentation<\\\/span><\\\/a><span style=\\\"font-weight: 400;\\\">.<\\\/span><\\\/p>\"},\"elements\":[],\"widgetType\":\"text-editor\"},{\"id\":\"93e1cde\",\"elType\":\"widget\",\"settings\":{\"title\":\"Underscore Representation\",\"size\":\"medium\",\"header_size\":\"h3\"},\"elements\":[],\"widgetType\":\"heading\"},{\"id\":\"b562b5b\",\"elType\":\"widget\",\"settings\":{\"editor\":\"<p><span style=\\\"font-weight: 400;\\\">Let\\u2019s try something different. Let\\u2019s go back to using multi-valued fields, but this time, let\\u2019s look at how the ingredients themselves are represented. What if we changed the representation from [carrots, carrots, apple, cucumber] to [carrots_2, apple_1, cucumber_1]? By appending our counts, we retain information about duplicates, without exposing duplicates to the underlying doc_values data structure. We can perform this conversion at index time well in advance. The question now remains as to how we can aggregate upon those \\u201csuffixes\\u201d or numbers after our underscore delimiter.\\u00a0<\\\/span><\\\/p><p><span style=\\\"font-weight: 400;\\\">We can try to write code directly within a cloned repository of the OpenSearch codebase\\u00a0 and test to see if we can create a performant solution with regards to this representation of our ingredients. If this solution proves to be a winner in our benchmarks, we can move this code over to a plug-in architecture that\\u2019s easily packageable and can be installed via a single command by other users.\\u00a0<\\\/span><\\\/p><p><span style=\\\"font-weight: 400;\\\">Here\\u2019s how the example from before might look like with our new representation:<\\\/span><\\\/p>\"},\"elements\":[],\"widgetType\":\"text-editor\"},{\"id\":\"8a11f9b\",\"elType\":\"widget\",\"settings\":{\"code\":\"curl -XPUT \\\"http:\\\/\\\/localhost:9200\\\/recipe-book\\\" -H 'Content-Type: application\\\/json' -d' \\t \\r\\n{\\r\\n  \\\"mappings\\\": {\\r\\n    \\\"properties\\\": {\\r\\n    \\t \\\"favorite_foods\\\": {\\r\\n   \\t\\t\\t \\\"type\\\": \\\"keyword\\\"\\r\\n     \\t }\\r\\n     }\\r\\n   }\\r\\n}'\\r\\n\\r\\ncurl -XPUT \\\"http:\\\/\\\/localhost:9200\\\/recipe-book\\\/_doc\\\/1\\\" -H 'Content-Type: application\\\/json' -d'\\r\\n{\\r\\n  \\\"favorite_foods\\\": [\\\"apple_1\\\", \\\"carrot_2\\\", \\\"cucumber_1\\\"]\\r\\n}'\\r\\n\\r\\ncurl -XPUT \\\"http:\\\/\\\/localhost:9200\\\/recipe-book\\\/_doc\\\/2\\\" -H 'Content-Type: application\\\/json' -d'\\r\\n{\\r\\n  \\\"favorite_foods\\\": [\\\"apple_1\\\", \\\"carrot_1\\\", \\\"cucumber_1\\\"]\\r\\n}'\\r\\n\\r\\ncurl -XPUT \\\"http:\\\/\\\/localhost:9200\\\/recipe-book\\\/_doc\\\/3\\\" -H 'Content-Type: application\\\/json' -d'\\r\\n{\\r\\n  \\\"favorite_foods\\\": [\\\"cucumber_3\\\"]\\r\\n}'\\r\\n\",\"line_numbers\":\"\",\"word_wrap\":\"word-wrap\",\"theme\":\"tomorrow\"},\"elements\":[],\"widgetType\":\"code-highlight\"},{\"id\":\"9a83613\",\"elType\":\"widget\",\"settings\":{\"editor\":\"<p><span style=\\\"font-weight: 400;\\\">We took a look at the OpenSearch codebase, finding the code path by which traditional terms aggregations were performed. There were two \\u201caggregator\\u201d classes that OpenSearch uses in a terms aggregation, either the GlobalOrdinalsStringTermsAggregator or the MapStringTermsAggregator. The Global Ordinals aggregation takes advantage of global ordinals, mappings of segment ordinals to their original locations at a \\u201cglobal\\u201d level. While this is the traditional aggregator used for terms aggregations, seeing that aggregations occur across shards and segments, we opted to base our custom implementation in the MapStringTermsAggregator.\\u00a0<\\\/span><\\\/p><p><span style=\\\"font-weight: 400;\\\">The GlobalOrdinalsStringTermsAggregator deals in globalOrds represented as longs, which are not easily convertible into Strings. We need to deal with Strings in order to separate the suffix count from the delimiter. The MapStringTermsAggregator uses a representation of doc values that enables for ordinal representations to be converted to BytesRefs and subsequently to Strings.\\u00a0<\\\/span><\\\/p><p><span style=\\\"font-weight: 400;\\\">Following further down the code path, we then modified the doc values typing used by the MapStringTermsAggregator, specifically the SortedBinaryDocValues type, and created a custom implementation that separated the suffix from our term (apple_3 \\u2192 apple, 3) and created new buckets with these new terms as keys and suffixes as counts. We then sent \\u201cfake\\u201d values to the LeafCollector method that would mimic the bucket counts that we required. For example, the value apple_3 would be seen by the collector as apple, apple(fake), apple(fake).\\u00a0<\\\/span><\\\/p><p><span style=\\\"font-weight: 400;\\\">On further iteration, caching via Hashmap was supported to prevent multiple ordinal lookups and multiple conversions from BytesRef to Strings, improving performance in the process.\\u00a0<\\\/span><\\\/p>\"},\"elements\":[],\"widgetType\":\"text-editor\"},{\"id\":\"c6abd2e\",\"elType\":\"widget\",\"settings\":[],\"elements\":[],\"widgetType\":\"spacer\"},{\"id\":\"8ca4920\",\"elType\":\"widget\",\"settings\":{\"title\":\"Benchmarks &amp; Takeaways\",\"size\":\"large\",\"header_size\":\"h3\"},\"elements\":[],\"widgetType\":\"heading\"},{\"id\":\"8cdf81a\",\"elType\":\"widget\",\"settings\":{\"editor\":\"<p><span style=\\\"font-weight: 400;\\\">We now have three implementations that each net us the expected result. It now remains to see which implementation will offer us the best solution in accordance with our guidelines.\\u00a0<\\\/span><\\\/p><p><span style=\\\"font-weight: 400;\\\">We used JMeter to test the query performance. Here are important points regarding how the implementations were benchmarked:<\\\/span><\\\/p><ul><li style=\\\"font-weight: 400;\\\" aria-level=\\\"1\\\"><span style=\\\"font-weight: 400;\\\">Documents were indexed via <a href=\\\"https:\\\/\\\/github.com\\\/kmwtechnology\\\/lucille\\\">Lucille<\\\/a>, an open-source Java framework for ETL pipelines created by KMW Technology; Lucille supports a benchmarking workflow with randomised document creation<\\\/span><\\\/li><li style=\\\"font-weight: 400;\\\" aria-level=\\\"1\\\"><span style=\\\"font-weight: 400;\\\">1 index was created per implementation, each within their own instance of OS<\\\/span><\\\/li><li style=\\\"font-weight: 400;\\\" aria-level=\\\"1\\\"><span style=\\\"font-weight: 400;\\\">100k documents were indexed into each index<\\\/span><\\\/li><li style=\\\"font-weight: 400;\\\" aria-level=\\\"1\\\"><span style=\\\"font-weight: 400;\\\">Each document averaged at 1000 values in its field, with the range spanning from 750 to 1250<\\\/span><\\\/li><li style=\\\"font-weight: 400;\\\" aria-level=\\\"1\\\"><span style=\\\"font-weight: 400;\\\">All queries had random boolean match filters alongside the aggregations so as to prevent the impact of caches<\\\/span><ul><li style=\\\"font-weight: 400;\\\" aria-level=\\\"2\\\"><span style=\\\"font-weight: 400;\\\">The underscore representation queries used a \\u201cprefix\\u201d match seeing that their values had an additional delimiter and count attached<\\\/span><\\\/li><li style=\\\"font-weight: 400;\\\" aria-level=\\\"2\\\"><span style=\\\"font-weight: 400;\\\">This \\u201cprefix\\u201d analysis may potentially have had ramifications for query performance for the underscore implementation<\\\/span><\\\/li><\\\/ul><\\\/li><li style=\\\"font-weight: 400;\\\" aria-level=\\\"1\\\"><span style=\\\"font-weight: 400;\\\">50 users sent queries simultaneously with a 1 second ramp-up time<\\\/span><\\\/li><\\\/ul>\"},\"elements\":[],\"widgetType\":\"text-editor\"},{\"id\":\"c26131c\",\"elType\":\"widget\",\"settings\":{\"editor\":\"<p><!-- wp:table {\\\"hasFixedLayout\\\":true,\\\"className\\\":\\\"is-style-regular\\\"} --><\\\/p><figure class=\\\"wp-block-table is-style-regular\\\"><table class=\\\"has-fixed-layout\\\"><tbody><tr><td>\\u00a0<\\\/td><td><strong>Scripted Imp.<\\\/strong><\\\/td><td><strong>Underscore Imp.<\\\/strong><\\\/td><td><strong>Nested Imp.<\\\/strong><\\\/td><\\\/tr><tr><td># of samples<\\\/td><td>50<\\\/td><td>50<\\\/td><td>50<\\\/td><\\\/tr><tr><td>Average Latency (ms)<\\\/td><td>103907 ms<\\\/td><td>34505 ms<\\\/td><td>11877 ms<\\\/td><\\\/tr><tr><td>Min Latency (ms)<\\\/td><td>0 ms<\\\/td><td>0 ms<\\\/td><td>0 ms<\\\/td><\\\/tr><tr><td>Max Latency (ms)<\\\/td><td>147451 ms<\\\/td><td>41623 ms<\\\/td><td>16203 ms<\\\/td><\\\/tr><tr><td>Std. Dev<\\\/td><td>39522.05<\\\/td><td>7823.51<\\\/td><td>2761.71<\\\/td><\\\/tr><tr><td>Error %<\\\/td><td>0%<\\\/td><td>0%<\\\/td><td>0%<\\\/td><\\\/tr><tr><td>Throughput (requests per second)<\\\/td><td>0%<\\\/td><td>0%<\\\/td><td>0%<\\\/td><\\\/tr><\\\/tbody><\\\/table><\\\/figure>\"},\"elements\":[],\"widgetType\":\"text-editor\"},{\"id\":\"fcf9fc2\",\"elType\":\"widget\",\"settings\":{\"editor\":\"<p><span style=\\\"font-weight: 400;\\\">The scripted implementation saw the longest average query time at around 104 seconds. The underscore implementation sat in the middle with an average query time of around 35 seconds.<\\\/span><span style=\\\"font-weight: 400;\\\">The nested implementation was the fastest with an average query time of around 12 seconds.<\\\/span><\\\/p><p><span style=\\\"font-weight: 400;\\\">With this information, it may seem clear that the nested approach is the best approach for handling duplicate terms aggregations in OpenSearch. However, taking a closer look at our proposed guidelines, we notice that we\\u2019ve yet to evaluate index size. Looking at index size benchmarks for both the nested and underscore implementations, we see a potentially new conclusion. The nested document index holds a large 1.4 GB index size. Meanwhile, the underscore index boasts a significantly smaller 187 MB index size. This translates to a <em>7.5x smaller index<\\\/em> size for the underscore implementation, with a 2.9x slower average query time.\\u00a0<\\\/span><\\\/p><p><span style=\\\"font-weight: 400;\\\">While we didn\\u2019t explicitly weigh each guideline\\u2019s importance, it was clear to us that a significantly larger index would present more problems than the query time performance hit, especially with the magnitudes mentioned before. This led us to believe that the underscore implementation was the best fit for our needs and the guidelines that we set forth. If index size is not a consideration for users, then the nested approach would be the best, seeing that it offers extremely fast lookup \\\/ query times.<\\\/span><\\\/p>\"},\"elements\":[],\"widgetType\":\"text-editor\"},{\"id\":\"7dc0602\",\"elType\":\"widget\",\"settings\":[],\"elements\":[],\"widgetType\":\"spacer\"},{\"id\":\"0070c1d\",\"elType\":\"widget\",\"settings\":{\"title\":\"The Plug-in\",\"size\":\"large\"},\"elements\":[],\"widgetType\":\"heading\"},{\"id\":\"8aa794a\",\"elType\":\"widget\",\"settings\":{\"editor\":\"<p><span style=\\\"font-weight: 400;\\\">It now makes sense to package this solution into a plug-in. While OpenSearch does offer an easy-to-use <\\\/span><a href=\\\"https:\\\/\\\/github.com\\\/opensearch-project\\\/opensearch-plugin-template-java\\\"><span style=\\\"font-weight: 400;\\\">template<\\\/span><\\\/a><span style=\\\"font-weight: 400;\\\"> for developers to get started with plug-in development, the convenience stops shortly thereafter. We encountered some problems while developing the plug-in.<\\\/span><\\\/p>\"},\"elements\":[],\"widgetType\":\"text-editor\"},{\"id\":\"eae5bdc\",\"elType\":\"widget\",\"settings\":{\"title\":\"Difficulties in Plug-in Creation \",\"size\":\"medium\",\"header_size\":\"h3\"},\"elements\":[],\"widgetType\":\"heading\"},{\"id\":\"1796c20\",\"elType\":\"widget\",\"settings\":{\"editor\":\"<p><span style=\\\"font-weight: 400;\\\">The most challenging issue in plug-in development with OpenSearch has to do with Java class loaders. When installing a plug-in into an OpenSearch distribution, OpenSearch uses a parent class loader to load in OpenSearch related files and a child class loader to load in our plug-in files. OpenSearch files are largely package-private, preventing the child class loader from having access to their methods, constructors, etc. This causes large amounts of code duplication and requires a deep understanding of the inner workings of OpenSearch aggregations. Here is a link to a code example that illustrates the issues we encountered with class loaders: <\\\/span><a href=\\\"https:\\\/\\\/gist.github.com\\\/rseitz\\\/59bff56936756ff29b2e151e2857aa37\\\"><span style=\\\"font-weight: 400;\\\">link<\\\/span><\\\/a><span style=\\\"font-weight: 400;\\\">.<\\\/span><\\\/p><p><span style=\\\"font-weight: 400;\\\">Another issue faced was a lack of clear testing protocol for plug-ins. Tests situated within the OpenSearch core codebase, specifically aggregation tests, relied heavily on helper classes and methods found within the core codebase. Our plug-in code, due to the aforementioned class loader issue, did not have access to these assisting classes. This made it extremely difficult to write unit tests, leaving us only with integration tests.<\\\/span><\\\/p>\"},\"elements\":[],\"widgetType\":\"text-editor\"},{\"id\":\"f49451e\",\"elType\":\"widget\",\"settings\":{\"title\":\"Future Points of Interest\",\"size\":\"medium\",\"header_size\":\"h3\"},\"elements\":[],\"widgetType\":\"heading\"},{\"id\":\"20673c2\",\"elType\":\"widget\",\"settings\":{\"editor\":\"<p><span style=\\\"font-weight: 400;\\\">To say that our investigation exhausted all avenues for how to perform a duplicate terms aggregation would be naive. A few ideas were brainstormed (and even tested), but didn\\u2019t seem promising or did not fit our original guidelines. Here are a few:<\\\/span><span style=\\\"font-weight: 400;\\\"><br \\\/><\\\/span><\\\/p><p><span style=\\\"font-weight: 400;\\\">Our plug-in implementation leveraged the SortedBinaryDocValues, the primary doc values data type for keyword field types. If we were open to changing the field type of our data, we could have experimented with the SortedOrderedNumericDocValues which stores duplicates for the numeric field type. This type is the only doc values field type in Lucene that retains duplicates. However, the issue would arise for a need to convert from numeric type to string at query time, leading to definite performance loss.\\u00a0<\\\/span><\\\/p><p><span style=\\\"font-weight: 400;\\\">Another potential solution would be to utilise Lucene payloads. Payloads are metadata that can be stored with terms and accessed via Lucene. The concern regarding this solution was that payloads would likely not be accessible via doc_values, leaving them as a likely slower alternative.<\\\/span><\\\/p><p><span style=\\\"font-weight: 400;\\\">One solution that was explored thoroughly was term vectors. Term vectors work by offering statistics for all the terms in the fields of a specific document, provided by the user. This already raised a few concerns, especially since we would require an artificial \\u201cmaster\\u201d document that contained all possible terms and fields so that its \\u2018id\\u2019 could be provided. If using this artificial document approach, term vectors would gather statistics from a randomly selected shard. The user must then choose to use only a single-shard instance or total the counts across all shards and create \\u201cmaster\\u201d documents within each shard. Despite this, we created code against Lucene itself comparing doc values to term vectors. For 10 million documents, term vectors seemed to be averaging 50 seconds slower than doc values.\\u00a0<\\\/span><\\\/p>\"},\"elements\":[],\"widgetType\":\"text-editor\"},{\"id\":\"c9a6ce9\",\"elType\":\"widget\",\"settings\":{\"title\":\"Conclusion\",\"size\":\"large\"},\"elements\":[],\"widgetType\":\"heading\"},{\"id\":\"e94bbab\",\"elType\":\"widget\",\"settings\":{\"editor\":\"<p><span style=\\\"font-weight: 400;\\\">Overall, we believe our investigation to be a thorough analysis of the existing possible tools to perform a duplicate terms aggregation. The plug-in we\\u2019ve created seems likely to be the best solution for duplicate terms aggregation depending on the individual context and use-case.\\u00a0<\\\/span><\\\/p><p><span style=\\\"font-weight: 400;\\\">With this solution under our belt, we can now make our shopping list and make our great-grandmother proud!\\u00a0<\\\/span><\\\/p>\"},\"elements\":[],\"widgetType\":\"text-editor\"}],\"isInner\":false},{\"id\":\"7295c69\",\"elType\":\"column\",\"settings\":{\"_column_size\":33,\"_inline_size\":10,\"thegem_column_breakpoints_list\":[]},\"elements\":[],\"isInner\":false},{\"id\":\"1f8e61f\",\"elType\":\"column\",\"settings\":{\"_column_size\":33,\"_inline_size\":24.666,\"thegem_column_breakpoints_list\":[],\"_inline_size_tablet\":100},\"elements\":[{\"id\":\"b2890c3\",\"elType\":\"widget\",\"settings\":{\"title\":\"Share Post\",\"size\":\"small\",\"header_size\":\"div\",\"thegem_heading_style\":\"title-h6\"},\"elements\":[],\"widgetType\":\"heading\"},{\"id\":\"5fe7d43\",\"elType\":\"widget\",\"settings\":{\"pinterest\":\"\",\"tumblr\":\"\",\"telegram\":\"\",\"whatsapp\":\"\",\"viber\":\"\",\"xing\":\"\",\"icons_color\":\"#00DEFF\"},\"elements\":[],\"widgetType\":\"thegem-social-sharing\"},{\"id\":\"0a5e46b\",\"elType\":\"widget\",\"settings\":{\"title\":\"More From the KMW Blog\",\"size\":\"small\",\"header_size\":\"div\",\"thegem_heading_style\":\"title-h6\"},\"elements\":[],\"widgetType\":\"heading\"},{\"id\":\"a1cba74\",\"elType\":\"widget\",\"settings\":{\"thegem_elementor_preset\":\"compact-tiny-2\",\"source\":[\"posts\"],\"show_separator\":\"\",\"show_comments\":\"\",\"readmore_button_text\":\"Read More\",\"loadmore_button_text\":\"Load More\",\"caption_categories_in_text\":\"in \",\"caption_author_by_text\":\"By\",\"source_type\":\"custom\",\"exclude_blog_posts_type\":\"current\",\"pagination_type\":\"numbers\"},\"elements\":[],\"widgetType\":\"thegem-bloglist\"}],\"isInner\":false}],\"isInner\":false},{\"id\":\"87fbea3\",\"elType\":\"section\",\"settings\":[],\"elements\":[{\"id\":\"c32d4f1\",\"elType\":\"column\",\"settings\":{\"_column_size\":100,\"_inline_size\":null,\"thegem_column_breakpoints_list\":[]},\"elements\":[{\"id\":\"aecd2e9\",\"elType\":\"widget\",\"settings\":[],\"elements\":[],\"widgetType\":\"spacer\"},{\"id\":\"a1d11f5\",\"elType\":\"widget\",\"settings\":{\"prev_label\":\"Previous Post\",\"next_label\":\"Next Post\",\"show_borders\":\"\",\"title_typography_typography\":\"custom\",\"title_typography_font_size\":{\"unit\":\"px\",\"size\":14,\"sizes\":[]},\"title_typography_font_weight\":\"700\",\"__globals__\":{\"arrow_color\":\"globals\\\/colors?id=primary\",\"label_color\":\"globals\\\/colors?id=secondary\"},\"arrow\":\"fa fa-caret-left\",\"show_arrow\":\"\"},\"elements\":[],\"widgetType\":\"post-navigation\"}],\"isInner\":false}],\"isInner\":false}]"],"_yoast_wpseo_content_score":["30"],"_zilla_likes":["0"],"_thumbnail_id":["29759"],"_yoast_wpseo_focuskw":["OpenSearch Aggregations"],"_yoast_wpseo_metadesc":["In Lucene-based search engines like OpenSearch and Solr, keyword aggregations ignore duplicate values that occur within a multi-valued field. We built an OpenSearch plugin to overcome this limitation."],"_yoast_wpseo_linkdex":["67"],"_yoast_wpseo_schema_article_type":["BlogPosting"],"_yoast_wpseo_twitter-image":["https:\/\/kmwllc.com\/wp-content\/uploads\/2024\/05\/blog_opensearch-agg1200x900-min-1024x776.png"],"_yoast_wpseo_twitter-image-id":["29759"],"_last_editor_used_jetpack":["block-editor"],"_aioseo_title":[null],"_aioseo_description":[null],"_aioseo_keywords":["a:0:{}"],"_aioseo_og_title":[null],"_aioseo_og_description":[null],"_aioseo_og_article_section":[""],"_aioseo_og_article_tags":["a:0:{}"],"_aioseo_twitter_title":[null],"_aioseo_twitter_description":[null],"_elementor_edit_mode":["builder"],"_elementor_controls_usage":["a:12:{s:9:\"post-info\";a:3:{s:5:\"count\";i:1;s:15:\"control_percent\";i:0;s:8:\"controls\";a:2:{s:7:\"content\";a:1:{s:12:\"section_icon\";a:1:{s:9:\"icon_list\";i:1;}}s:5:\"style\";a:1:{s:18:\"section_text_style\";a:1:{s:26:\"icon_typography_typography\";i:1;}}}}s:7:\"heading\";a:3:{s:5:\"count\";i:14;s:15:\"control_percent\";i:1;s:8:\"controls\";a:2:{s:7:\"general\";a:1:{s:11:\"__dynamic__\";a:1:{s:5:\"count\";i:1;}}s:7:\"content\";a:1:{s:13:\"section_title\";a:4:{s:5:\"title\";i:14;s:11:\"header_size\";i:10;s:20:\"thegem_heading_style\";i:3;s:4:\"size\";i:13;}}}}s:10:\"author-box\";a:3:{s:5:\"count\";i:1;s:15:\"control_percent\";i:3;s:8:\"controls\";a:3:{s:7:\"content\";a:1:{s:19:\"section_author_info\";a:5:{s:6:\"source\";i:1;s:13:\"author_avatar\";i:1;s:11:\"author_name\";i:1;s:15:\"author_name_tag\";i:1;s:10:\"author_bio\";i:1;}}s:5:\"style\";a:2:{s:19:\"section_image_style\";a:4:{s:20:\"image_vertical_align\";i:1;s:12:\"image_border\";i:1;s:18:\"image_border_width\";i:1;s:19:\"image_border_radius\";i:1;}s:18:\"section_text_style\";a:1:{s:8:\"name_gap\";i:1;}}s:8:\"advanced\";a:1:{s:14:\"_section_style\";a:3:{s:8:\"_padding\";i:1;s:15:\"_padding_tablet\";i:1;s:15:\"_padding_mobile\";i:1;}}}}s:7:\"divider\";a:3:{s:5:\"count\";i:1;s:15:\"control_percent\";i:0;s:8:\"controls\";a:1:{s:5:\"style\";a:1:{s:21:\"section_divider_style\";a:2:{s:6:\"weight\";i:1;s:3:\"gap\";i:1;}}}}s:6:\"spacer\";a:3:{s:5:\"count\";i:5;s:15:\"control_percent\";i:0;s:8:\"controls\";a:0:{}}s:11:\"text-editor\";a:3:{s:5:\"count\";i:16;s:15:\"control_percent\";i:0;s:8:\"controls\";a:1:{s:7:\"content\";a:1:{s:14:\"section_editor\";a:1:{s:6:\"editor\";i:16;}}}}s:14:\"code-highlight\";a:3:{s:5:\"count\";i:4;s:15:\"control_percent\";i:1;s:8:\"controls\";a:1:{s:7:\"content\";a:1:{s:15:\"section_content\";a:4:{s:4:\"code\";i:4;s:12:\"line_numbers\";i:4;s:9:\"word_wrap\";i:4;s:5:\"theme\";i:4;}}}}s:6:\"column\";a:3:{s:5:\"count\";i:4;s:15:\"control_percent\";i:0;s:8:\"controls\";a:1:{s:6:\"layout\";a:1:{s:6:\"layout\";a:2:{s:12:\"_inline_size\";i:4;s:19:\"_inline_size_tablet\";i:2;}}}}s:21:\"thegem-social-sharing\";a:3:{s:5:\"count\";i:1;s:15:\"control_percent\";i:2;s:8:\"controls\";a:2:{s:7:\"content\";a:1:{s:13:\"section_icons\";a:6:{s:9:\"pinterest\";i:1;s:6:\"tumblr\";i:1;s:8:\"telegram\";i:1;s:8:\"whatsapp\";i:1;s:5:\"viber\";i:1;s:4:\"xing\";i:1;}}s:5:\"style\";a:1:{s:5:\"Style\";a:1:{s:11:\"icons_color\";i:1;}}}}s:15:\"thegem-bloglist\";a:3:{s:5:\"count\";i:1;s:15:\"control_percent\";i:0;s:8:\"controls\";a:1:{s:7:\"content\";a:3:{s:14:\"section_layout\";a:1:{s:23:\"thegem_elementor_preset\";i:1;}s:12:\"section_blog\";a:2:{s:6:\"source\";i:1;s:23:\"exclude_blog_posts_type\";i:1;}s:15:\"section_caption\";a:2:{s:14:\"show_separator\";i:1;s:13:\"show_comments\";i:1;}}}}s:7:\"section\";a:3:{s:5:\"count\";i:2;s:15:\"control_percent\";i:0;s:8:\"controls\";a:1:{s:6:\"layout\";a:1:{s:17:\"section_structure\";a:1:{s:9:\"structure\";i:1;}}}}s:15:\"post-navigation\";a:3:{s:5:\"count\";i:1;s:15:\"control_percent\";i:2;s:8:\"controls\";a:2:{s:7:\"content\";a:1:{s:31:\"section_post_navigation_content\";a:5:{s:10:\"prev_label\";i:1;s:10:\"next_label\";i:1;s:12:\"show_borders\";i:1;s:5:\"arrow\";i:1;s:10:\"show_arrow\";i:1;}}s:5:\"style\";a:1:{s:11:\"title_style\";a:3:{s:27:\"title_typography_typography\";i:1;s:26:\"title_typography_font_size\";i:1;s:28:\"title_typography_font_weight\";i:1;}}}}}"],"_elementor_css":["a:6:{s:4:\"time\";i:1775577487;s:5:\"fonts\";a:0:{}s:5:\"icons\";a:0:{}s:20:\"dynamic_elements_ids\";a:1:{i:0;s:7:\"cb40088\";}s:6:\"status\";s:4:\"file\";i:0;s:0:\"\";}"],"_elementor_page_assets":["a:2:{s:6:\"styles\";a:11:{i:0;s:16:\"widget-post-info\";i:1;s:16:\"widget-icon-list\";i:2;s:26:\"elementor-icons-fa-regular\";i:3;s:24:\"elementor-icons-fa-solid\";i:4;s:14:\"widget-heading\";i:5;s:17:\"widget-author-box\";i:6;s:14:\"widget-divider\";i:7;s:13:\"widget-spacer\";i:8;s:21:\"widget-code-highlight\";i:9;s:15:\"thegem-bloglist\";i:10;s:22:\"widget-post-navigation\";}s:7:\"scripts\";a:10:{i:0;s:18:\"elementor-frontend\";i:1;s:12:\"prismjs_core\";i:2;s:14:\"prismjs_loader\";i:3;s:17:\"prismjs_normalize\";i:4;s:17:\"highlight_handler\";i:5;s:25:\"prismjs_copy_to_clipboard\";i:6;s:23:\"thegem-items-animations\";i:7;s:11:\"thegem-blog\";i:8;s:19:\"thegem-blog-isotope\";i:9;s:15:\"post-navigation\";}}"],"_elementor_element_cache":["{\"timeout\":1775969746,\"value\":{\"content\":\"\\t\\t<section class=\\\"elementor-section elementor-top-section elementor-element elementor-element-b9d2795 elementor-section-boxed elementor-section-height-default elementor-section-height-default\\\" data-id=\\\"b9d2795\\\" data-element_type=\\\"section\\\" data-e-type=\\\"section\\\">\\r\\n\\t\\t\\t\\t\\t\\t<div class=\\\"elementor-container elementor-column-gap-thegem\\\"><div class=\\\"elementor-row\\\">\\r\\n\\t\\t\\t\\t\\t<div class=\\\"elementor-column elementor-col-33 elementor-top-column elementor-element elementor-element-849c1d1\\\" data-id=\\\"849c1d1\\\" data-element_type=\\\"column\\\" data-e-type=\\\"column\\\">\\n\\t\\t\\t<div class=\\\"elementor-widget-wrap elementor-element-populated\\\">\\n\\t\\t\\t\\t[elementor-element k=\\\"9109a976d8649ee6d2c8fef8daebbb8b\\\" data=\\\"eyJpZCI6IjEyOThmOWEiLCJlbFR5cGUiOiJ3aWRnZXQiLCJzZXR0aW5ncyI6eyJpY29uX2xpc3QiOlt7InNlbGVjdGVkX2ljb24iOnsidmFsdWUiOiJmYXMgZmEtY2FsZW5kYXIiLCJsaWJyYXJ5IjoiZmEtc29saWQifSwiX2lkIjoiOTFhMGY1MiIsImN1c3RvbV9kYXRlX2Zvcm1hdCI6IkYgaiwgWSIsImN1c3RvbV90aW1lX2Zvcm1hdCI6Imc6aSBhIiwibGluayI6IiIsInNob3dfaWNvbiI6Im5vbmUifV0sImljb25fdHlwb2dyYXBoeV90eXBvZ3JhcGh5IjoiY3VzdG9tIiwiX19nbG9iYWxzX18iOnsidGV4dF9jb2xvciI6Imdsb2JhbHNcL2NvbG9ycz9pZD1wcmltYXJ5In19LCJlbGVtZW50cyI6W10sIndpZGdldFR5cGUiOiJwb3N0LWluZm8ifQ==\\\"][elementor-element k=\\\"9109a976d8649ee6d2c8fef8daebbb8b\\\" data=\\\"eyJpZCI6ImNiNDAwODgiLCJlbFR5cGUiOiJ3aWRnZXQiLCJzZXR0aW5ncyI6eyJ0aXRsZSI6IkFkZCBZb3VyIEhlYWRpbmcgVGV4dCBIZXJlIiwiaGVhZGVyX3NpemUiOiJkaXYiLCJ0aGVnZW1faGVhZGluZ19zdHlsZSI6InN0eWxlZC1zdWJ0aXRsZSIsIl9fZHluYW1pY19fIjp7InRpdGxlIjoiW2VsZW1lbnRvci10YWcgaWQ9XCI3YjZhZDE0XCIgbmFtZT1cInRoZWdlbS1wb3N0LWV4Y2VycHRcIiBzZXR0aW5ncz1cIiU3QiU3RFwiXSJ9fSwiZWxlbWVudHMiOltdLCJ3aWRnZXRUeXBlIjoiaGVhZGluZyJ9\\\"][elementor-element k=\\\"9109a976d8649ee6d2c8fef8daebbb8b\\\" data=\\\"eyJpZCI6Ijk4NGI1ZDMiLCJlbFR5cGUiOiJ3aWRnZXQiLCJzZXR0aW5ncyI6eyJzb3VyY2UiOiJjdXN0b20iLCJhdXRob3JfYXZhdGFyIjp7InVybCI6Imh0dHBzOlwvXC9rbXdsbGNjb20uc3RhZ2Uuc2l0ZVwvd3AtY29udGVudFwvdXBsb2Fkc1wvMjAyNFwvMDFcL0FiaWppdDIwMjMucG5nIiwiaWQiOjI5NjUyLCJhbHQiOiIiLCJzb3VyY2UiOiJsaWJyYXJ5Iiwic2l6ZSI6IiJ9LCJhdXRob3JfbmFtZSI6IkFiaWppdCBSYW5nZXNoIiwiYXV0aG9yX25hbWVfdGFnIjoiZGl2IiwiYXV0aG9yX2JpbyI6IlNlYXJjaCBFbmdpbmVlciBhdCBLTVcgVGVjaG5vbG9neSIsImxpbmtfdGV4dCI6IkFsbCBQb3N0cyIsImltYWdlX3ZlcnRpY2FsX2FsaWduIjoidG9wIiwiaW1hZ2VfYm9yZGVyIjoieWVzIiwiaW1hZ2VfYm9yZGVyX3dpZHRoIjp7InVuaXQiOiJweCIsInNpemUiOjMsInNpemVzIjpbXX0sImltYWdlX2JvcmRlcl9yYWRpdXMiOnsidW5pdCI6InB4Iiwic2l6ZSI6MTAwLCJzaXplcyI6W119LCJuYW1lX2dhcCI6eyJ1bml0IjoicHgiLCJzaXplIjowLCJzaXplcyI6W119LCJfX2dsb2JhbHNfXyI6eyJpbWFnZV9ib3JkZXJfY29sb3IiOiJnbG9iYWxzXC9jb2xvcnM\\\/aWQ9NDI4ZjI3NyIsImJpb19jb2xvciI6Imdsb2JhbHNcL2NvbG9ycz9pZD1zZWNvbmRhcnkifSwiX3BhZGRpbmciOnsidW5pdCI6ImVtIiwidG9wIjoiMiIsInJpZ2h0IjoiMiIsImJvdHRvbSI6IjIiLCJsZWZ0IjoiMiIsImlzTGlua2VkIjp0cnVlfSwiX3BhZGRpbmdfdGFibGV0Ijp7InVuaXQiOiJlbSIsInRvcCI6IiIsInJpZ2h0IjoiIiwiYm90dG9tIjoiIiwibGVmdCI6IiIsImlzTGlua2VkIjp0cnVlfSwiX3BhZGRpbmdfbW9iaWxlIjp7InVuaXQiOiJlbSIsInRvcCI6IiIsInJpZ2h0IjoiIiwiYm90dG9tIjoiIiwibGVmdCI6IiIsImlzTGlua2VkIjp0cnVlfX0sImVsZW1lbnRzIjpbXSwid2lkZ2V0VHlwZSI6ImF1dGhvci1ib3gifQ==\\\"]\\t\\t<div class=\\\"elementor-element elementor-element-57774d5 elementor-widget-divider--view-line flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-divider\\\" data-id=\\\"57774d5\\\" data-element_type=\\\"widget\\\" data-e-type=\\\"widget\\\" data-widget_type=\\\"divider.default\\\">\\n\\t\\t\\t\\t<div class=\\\"elementor-widget-container\\\">\\n\\t\\t\\t\\t\\t\\t\\t<div class=\\\"elementor-divider\\\">\\n\\t\\t\\t<span class=\\\"elementor-divider-separator\\\">\\n\\t\\t\\t\\t\\t\\t<\\\/span>\\n\\t\\t<\\\/div>\\n\\t\\t\\t\\t\\t\\t<\\\/div>\\n\\t\\t\\t\\t<\\\/div>\\n\\t\\t\\t\\t<div class=\\\"elementor-element elementor-element-2f6bf75 flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-spacer\\\" data-id=\\\"2f6bf75\\\" data-element_type=\\\"widget\\\" data-e-type=\\\"widget\\\" data-widget_type=\\\"spacer.default\\\">\\n\\t\\t\\t\\t<div class=\\\"elementor-widget-container\\\">\\n\\t\\t\\t\\t\\t\\t\\t<div class=\\\"elementor-spacer\\\">\\n\\t\\t\\t<div class=\\\"elementor-spacer-inner\\\"><\\\/div>\\n\\t\\t<\\\/div>\\n\\t\\t\\t\\t\\t\\t<\\\/div>\\n\\t\\t\\t\\t<\\\/div>\\n\\t\\t\\t\\t<div class=\\\"elementor-element elementor-element-6d550b8 flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-heading\\\" data-id=\\\"6d550b8\\\" data-element_type=\\\"widget\\\" data-e-type=\\\"widget\\\" data-widget_type=\\\"heading.default\\\">\\n\\t\\t\\t\\t<div class=\\\"elementor-widget-container\\\">\\n\\t\\t\\t\\t\\t<h2 class=\\\"elementor-heading-title elementor-size-large\\\">What We\\u2019ve Accomplished<\\\/h2>\\t\\t\\t\\t<\\\/div>\\n\\t\\t\\t\\t<\\\/div>\\n\\t\\t[elementor-element k=\\\"9109a976d8649ee6d2c8fef8daebbb8b\\\" data=\\\"eyJpZCI6ImMzZmVjMWQiLCJlbFR5cGUiOiJ3aWRnZXQiLCJzZXR0aW5ncyI6eyJlZGl0b3IiOiI8cD48c3BhbiBzdHlsZT1cImZvbnQtd2VpZ2h0OiA0MDA7XCI+SW4gTHVjZW5lLWJhc2VkIHNlYXJjaCBlbmdpbmVzIGxpa2UgT3BlblNlYXJjaCBhbmQgU29sciwga2V5d29yZCBhZ2dyZWdhdGlvbnMgaWdub3JlIGR1cGxpY2F0ZSB2YWx1ZXMgdGhhdCBvY2N1ciB3aXRoaW4gYSBtdWx0aS12YWx1ZWQgZmllbGQuIElmIGEgZG9jdW1lbnQgaGFzIGEgbXVsdGktdmFsdWVkIGZpZWxkIGNvbnRhaW5pbmcgdGhlIHZhbHVlcyBbXCJmb29cIiwgXCJmb29cIiwgXCJiYXJcIl0gdGhlbiBhbiBhZ2dyZWdhdGlvbiB3b3VsZCBpbmNyZW1lbnQgdGhlIGNvdW50IGZvciB0aGUgXCJmb29cIiBhbmQgXHUyMDFjYmFyXHUyMDFkIGJ1Y2tldCBvbmNlLCBldmVuIHRob3VnaCBcdTIwMWNmb29cdTIwMWQgb2NjdXJzIHR3aWNlLiBXZSBidWlsdCBhbiBPcGVuU2VhcmNoIHBsdWdpbiB0byBvdmVyY29tZSB0aGlzIGxpbWl0YXRpb24uPFwvc3Bhbj48XC9wPlxuPHA+PHNwYW4gc3R5bGU9XCJmb250LXdlaWdodDogNDAwO1wiPkluIHRoaXMgYmxvZyBwb3N0LCB3ZSBkZXRhaWwgdGhlIGludmVzdGlnYXRpb24gcHJvY2VzcyBpbnRvIGR1cGxpY2F0ZSB0ZXJtcyBhZ2dyZWdhdGlvbiBzb2x1dGlvbnMgYW5kIHRoZSBzdWJzZXF1ZW50IGRldmVsb3BtZW50IHByb2Nlc3MgYnkgd2hpY2ggYSBwbHVnLWluIHdhcyBidWlsdCBmb3IgT3BlblNlYXJjaC4gUHJldmlvdXNseSwgb25seSB0aGUgbmVzdGVkIGZpZWxkIHR5cGUgYW5kIHNjcmlwdGVkIGFnZ3JlZ2F0aW9uIG1ldGhvZHMgc2VlbWVkIHRvIGJlIHZpYWJsZSBzb2x1dGlvbnMuIE91ciBwbHVnLWluIGFpbXMgdG8gYmUgYSB0aGlyZCBvcHRpb24gdG8gc29sdmUgdGhpcyBwcm9ibGVtLiBUaGlzIHBsdWctaW4gc2VydmVzIHRvIGJlIHRoZSBmYXN0ZXN0IHNvbHV0aW9uIGZvciBhIGR1cGxpY2F0ZSB0ZXJtcyBhZ2dyZWdhdGlvbiBvbiBhIG11bHRpdmFsdWVkIGtleXdvcmQgZmllbGQgaW4gT3BlblNlYXJjaCB3aXRob3V0IGNvbXByb21pc2luZyBpbmRleCBzaXplLjxcL3NwYW4+PFwvcD5cbjxwPjxzcGFuIHN0eWxlPVwiZm9udC13ZWlnaHQ6IDQwMDtcIj5UaGUgbGluayB0byB0aGUgcGx1Zy1pbiByZXBvc2l0b3J5IGNhbiBiZSBmb3VuZCA8XC9zcGFuPjxhIGhyZWY9XCJodHRwczpcL1wvZ2l0aHViLmNvbVwva213dGVjaG5vbG9neVwvb3BlbnNlYXJjaC1kdXBsaWNhdGUtdGVybXMtYWdnXCI+PHNwYW4gc3R5bGU9XCJmb250LXdlaWdodDogNDAwO1wiPmhlcmU8XC9zcGFuPjxcL2E+PHNwYW4gc3R5bGU9XCJmb250LXdlaWdodDogNDAwO1wiPi4gUGxlYXNlIGZvbGxvdyB0aGUgc3RlcHMgaW4gdGhlIFJFQURNRS5tZCB0byBpbnN0YWxsIHRoaXMgcGx1Zy1pbiBpbnRvIGFuIE9wZW5TZWFyY2ggZGlzdHJpYnV0aW9uIGFuZCBpbnRlcmFjdCB3aXRoIHRoZSBjdXN0b20gYWdncmVnYXRpb24uXHUwMGEwPFwvc3Bhbj48XC9wPiJ9LCJlbGVtZW50cyI6W10sIndpZGdldFR5cGUiOiJ0ZXh0LWVkaXRvciJ9\\\"]\\t\\t<div class=\\\"elementor-element elementor-element-0ef200a flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-spacer\\\" data-id=\\\"0ef200a\\\" data-element_type=\\\"widget\\\" data-e-type=\\\"widget\\\" data-widget_type=\\\"spacer.default\\\">\\n\\t\\t\\t\\t<div class=\\\"elementor-widget-container\\\">\\n\\t\\t\\t\\t\\t\\t\\t<div class=\\\"elementor-spacer\\\">\\n\\t\\t\\t<div class=\\\"elementor-spacer-inner\\\"><\\\/div>\\n\\t\\t<\\\/div>\\n\\t\\t\\t\\t\\t\\t<\\\/div>\\n\\t\\t\\t\\t<\\\/div>\\n\\t\\t\\t\\t<div class=\\\"elementor-element elementor-element-26d3771 flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-heading\\\" data-id=\\\"26d3771\\\" data-element_type=\\\"widget\\\" data-e-type=\\\"widget\\\" data-widget_type=\\\"heading.default\\\">\\n\\t\\t\\t\\t<div class=\\\"elementor-widget-container\\\">\\n\\t\\t\\t\\t\\t<h2 class=\\\"elementor-heading-title elementor-size-large\\\">The Problem  <\\\/h2>\\t\\t\\t\\t<\\\/div>\\n\\t\\t\\t\\t<\\\/div>\\n\\t\\t[elementor-element k=\\\"9109a976d8649ee6d2c8fef8daebbb8b\\\" data=\\\"eyJpZCI6ImMwYjc0NDYiLCJlbFR5cGUiOiJ3aWRnZXQiLCJzZXR0aW5ncyI6eyJlZGl0b3IiOiI8cD48c3BhbiBzdHlsZT1cImZvbnQtd2VpZ2h0OiA0MDA7XCI+SW1hZ2luZSB5b3VcdTIwMTlyZSBydW1tYWdpbmcgdGhyb3VnaCB5b3VyIGF0dGljIGF0IHlvdXIgZmFtaWx5IGhvbWUgYW5kIHlvdVx1MjAxOXZlIGZvdW5kIGEgbGFyZ2UgcmVjaXBlIGJvb2suIEl0IHNlZW1zIHRvIGJlIHNvbWV0aGluZyB5b3VyIGdyZWF0LWdyYW5kbW90aGVyIGNoZXJpc2hlZC4gQXMgYm90aCBhIGRldm90ZWQgZ3JlYXQtZ3JhbmRjaGlsZCBhbmQgYSBmYW4gb2Ygc2VhcmNoIHNvbHV0aW9ucywgeW91XHUyMDE5ZCBsaWtlIHRvIGNhdGFsb2d1ZSB0aGUgZGF0YSBmb3VuZCBpbiB0aGlzIHJlY2lwZSBib29rIGluIGEgc2VhcmNoIGVuZ2luZSwgc3BlY2lmaWNhbGx5IE9wZW5TZWFyY2guXHUwMGEwPFwvc3Bhbj48XC9wPjxwPjxzcGFuIHN0eWxlPVwiZm9udC13ZWlnaHQ6IDQwMDtcIj5Zb3Ugd2lzaCB0byByZXByZXNlbnQgZWFjaCByZWNpcGUgYXMgYSBkb2N1bWVudCBhbmQgZWFjaCBkb2N1bWVudCB3b3VsZCBzdG9yZSBmaWVsZHMgZm9yIGRpZmZlcmVudCBhc3BlY3RzIG9mIHRoZSByZWNpcGU6IGNvb2tfdGltZSwgc3RlcHMsIHRlY2huaXF1ZSwgaW5ncmVkaWVudHMsIGV0Yy4gSW5ncmVkaWVudHMgY291bGQgaGF2ZSBkdXBsaWNhdGUgdmFsdWVzLCBkZXNpZ25hdGluZyBob3cgbWFueSBvZiB0aGVtIHRvIGluY2x1ZGUgaS5lLiBbY2Fycm90LCBjYXJyb3QsIGFwcGxlLCBjdWN1bWJlcl0gd291bGQgcmVwcmVzZW50IDIgY2Fycm90cywgMSBhcHBsZSwgYW5kIDEgY3VjdW1iZXIgZm9yIG91ciByZWNpcGUuXHUwMGEwPFwvc3Bhbj48XC9wPjxwPjxzcGFuIHN0eWxlPVwiZm9udC13ZWlnaHQ6IDQwMDtcIj5VcG9uIGNvbXBsZXRpb24gb2YgeW91ciBpbmRleCwgeW91IHdpc2ggdG8gYWdncmVnYXRlIHVwb24gYWxsIHRoZSBpbmdyZWRpZW50cyBhbmQgZmluZCBvdXQgaG93IG1hbnkgb2YgZWFjaCBpbmdyZWRpZW50IHRvIHB1cmNoYXNlIGluIG9yZGVyIHRvIG1ha2UgYWxsIG9mIHlvdXIgZ3JlYXQgZ3JhbmRtb3RoZXJcdTIwMTlzIHJlY2lwZXMuIFlvdSBub3RpY2UgYSBwcm9ibGVtIHF1aXRlIHF1aWNrbHk6IE9wZW5TZWFyY2ggYWdncmVnYXRpb25zIGRvIG5vdCB0YWtlIGludG8gYWNjb3VudCBkdXBsaWNhdGUgdmFsdWVzIG9uIG11bHRpLXZhbHVlZCBmaWVsZHMuIFdoaWxlIHRoZSByZWNpcGVzIG1heSBoYXZlIGNhbGxlZCBmb3IgYSB0b3RhbCBvZiB0aHJlZSBjYXJyb3RzICh0d28gZm9yIG9uZSByZWNpcGUgYW5kIG9uZSBmb3IgYSBkaWZmZXJlbnQgcmVjaXBlKSwgdGhlIGFnZ3JlZ2F0aW9uIHJlc3VsdCBvbmx5IHRlbGxzIHlvdSB0byBidXkgdHdvIChvbmUgZm9yIGVhY2ggcmVjaXBlKS48XC9zcGFuPjxcL3A+In0sImVsZW1lbnRzIjpbXSwid2lkZ2V0VHlwZSI6InRleHQtZWRpdG9yIn0=\\\"]\\t\\t<div class=\\\"elementor-element elementor-element-199285c flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-code-highlight\\\" data-id=\\\"199285c\\\" data-element_type=\\\"widget\\\" data-e-type=\\\"widget\\\" data-widget_type=\\\"code-highlight.default\\\">\\n\\t\\t\\t\\t<div class=\\\"elementor-widget-container\\\">\\n\\t\\t\\t\\t\\t\\t\\t<div class=\\\"prismjs-tomorrow copy-to-clipboard word-wrap\\\">\\n\\t\\t\\t<pre data-line=\\\"\\\" class=\\\"highlight-height language-javascript \\\">\\n\\t\\t\\t\\t<code readonly=\\\"true\\\" class=\\\"language-javascript\\\">\\n\\t\\t\\t\\t\\t<xmp>Documents & Aggregation: \\r\\n\\r\\ncurl -XPUT \\\"http:\\\/\\\/localhost:9200\\\/recipe-book\\\/_doc\\\/1\\\" -H 'Content-Type: application\\\/json' -d'\\r\\n{\\r\\n  \\\"favorite_foods\\\": [\\\"carrot\\\", \\\"carrot\\\", \\\"apple\\\", \\\"cucumber\\\"]\\r\\n}'\\r\\n\\r\\ncurl -XPUT \\\"http:\\\/\\\/localhost:9200\\\/recipe-book\\\/_doc\\\/2\\\" -H 'Content-Type: application\\\/json' -d'\\r\\n{\\r\\n  \\\"favorite_foods\\\": [\\\"carrot\\\", \\\"apple\\\", \\\"cucumber\\\"]\\r\\n}'\\r\\n\\r\\ncurl -XPUT \\\"http:\\\/\\\/localhost:9200\\\/recipe-book\\\/_doc\\\/3\\\" -H 'Content-Type: application\\\/json' -d'\\r\\n{\\r\\n  \\\"favorite_foods\\\": [\\\"cucumber\\\", \\\"cucumber\\\", \\\"cucumber\\\"]\\r\\n}'\\r\\n\\r\\ncurl -XGET \\\"http:\\\/\\\/localhost:9200\\\/recipe-book\\\/_search\\\" -H 'Content-Type: application\\\/json' -d'\\r\\n{\\r\\n  \\\"size\\\": 0,\\r\\n  \\\"aggregations\\\": {\\r\\n    \\\"ingredient_frequency\\\": {\\r\\n      \\\"terms\\\": {\\r\\n   \\t   \\\"field\\\": \\\"favorite_foods\\\"\\r\\n      }\\r\\n    }\\r\\n  }\\r\\n}'\\r\\n\\r\\nResult: \\r\\n\\\"aggregations\\\":{\\r\\n  \\t\\\"ingredient_frequency\\\":{\\r\\n     \\t  \\\"doc_count_error_upper_bound\\\":0,\\r\\n     \\t  \\\"sum_other_doc_count\\\":0,\\r\\n     \\t  \\\"buckets\\\":[\\r\\n        \\t{\\r\\n           \\t\\\"key\\\":\\\"cucumber\\\",\\r\\n           \\t\\\"doc_count\\\":3\\r\\n        \\t},\\r\\n        \\t{\\r\\n           \\t\\\"key\\\":\\\"apple\\\",\\r\\n           \\t\\\"doc_count\\\":2\\r\\n        \\t},\\r\\n        \\t{\\r\\n           \\t\\\"key\\\":\\\"carrot\\\",\\r\\n           \\t\\\"doc_count\\\":2\\r\\n        \\t}\\r\\n     \\t  ]\\r\\n  \\t}\\r\\n}\\r\\n\\r\\n<\\\/xmp>\\n\\t\\t\\t\\t<\\\/code>\\n\\t\\t\\t<\\\/pre>\\n\\t\\t<\\\/div>\\n\\t\\t\\t\\t\\t\\t<\\\/div>\\n\\t\\t\\t\\t<\\\/div>\\n\\t\\t\\t\\t<div class=\\\"elementor-element elementor-element-aecaba2 flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-heading\\\" data-id=\\\"aecaba2\\\" data-element_type=\\\"widget\\\" data-e-type=\\\"widget\\\" data-widget_type=\\\"heading.default\\\">\\n\\t\\t\\t\\t<div class=\\\"elementor-widget-container\\\">\\n\\t\\t\\t\\t\\t<h3 class=\\\"elementor-heading-title elementor-size-large\\\">Delving Deeper Into the Problem<\\\/h3>\\t\\t\\t\\t<\\\/div>\\n\\t\\t\\t\\t<\\\/div>\\n\\t\\t[elementor-element k=\\\"9109a976d8649ee6d2c8fef8daebbb8b\\\" data=\\\"eyJpZCI6Ijk3NTlkYmIiLCJlbFR5cGUiOiJ3aWRnZXQiLCJzZXR0aW5ncyI6eyJlZGl0b3IiOiI8cD48c3BhbiBzdHlsZT1cImZvbnQtd2VpZ2h0OiA0MDA7XCI+V2h5IGlzIGl0IHRoYXQgT3BlblNlYXJjaCBpcyB1bmFibGUgdG8gcGVyZm9ybSBhZ2dyZWdhdGlvbnMgb24gZHVwbGljYXRlIHZhbHVlcyBpbiBrZXl3b3JkIGZpZWxkcz8gQmVoaW5kIHRoZSBzY2VuZXMsIE9wZW5TZWFyY2ggaXMgdXNpbmcgYSBkb2NfdmFsdWVzIGRhdGEgc3RydWN0dXJlIGZvciBvcGVyYXRpb25zIGxpa2UgYWdncmVnYXRpb25zLCBhcyB0aGV5IHBlcmZvcm0gZmFyIGJldHRlciB0aGFuIHRoZSB0cmFkaXRpb25hbCBpbnZlcnRlZC1pbmRleCBkYXRhIHN0cnVjdHVyZS4gVGhlIHNwZWNpZmljIHR5cGUgb2YgZG9jX3ZhbHVlcyBzdXBwb3J0ZWQgYnkgTHVjZW5lIGZvciBrZXl3b3JkIGZpZWxkcyBkbyBub3Qgc3RvcmUgZHVwbGljYXRlIHZhbHVlcy4gQ29udmVyc2VseSwgYSBtYXRjaF9hbGwgcXVlcnkgd291bGQgcmV0dXJuIHVzIGR1cGxpY2F0ZSB2YWx1ZXMgYXMgaXQgd291bGQgYmUgdXNpbmcgYSBzZWdtZW50IGxvb2t1cCB1bmxpa2UgYWdncmVnYXRpb25zIHdoaWNoIHdvdWxkIGJlIHVzaW5nIHRoZSBhZm9yZW1lbnRpb25lZCBkb2NfdmFsdWVzIGRhdGEgc3RydWN0dXJlLlx1MDBhMDxcL3NwYW4+PFwvcD48cD48c3BhbiBzdHlsZT1cImZvbnQtd2VpZ2h0OiA0MDA7XCI+VGhlIGZvbGxvd2luZyA8XC9zcGFuPjxhIGhyZWY9XCJodHRwczpcL1wvc29sci5hcGFjaGUub3JnXC9ndWlkZVwvOF83XC9kb2N2YWx1ZXMuaHRtbFwiPjxzcGFuIHN0eWxlPVwiZm9udC13ZWlnaHQ6IDQwMDtcIj5saW5rPFwvc3Bhbj48XC9hPjxzcGFuIHN0eWxlPVwiZm9udC13ZWlnaHQ6IDQwMDtcIj4gcHJvdmlkZXMgbW9yZSBpbmZvcm1hdGlvbiBhYm91dCBzcGVjaWZpYyBmaWVsZCB0eXBlcyBhbmQgd2hldGhlciB0aGV5IHN1cHBvcnQgZHVwbGljYXRlcyBvciBub3QuIE5vdGUgdGhhdCB3aGlsZSB0aGlzIGxpbmtzIHRvIFNvbHIgZG9jdW1lbnRhdGlvbiBhbmQgcHJlc2VudHMgU29sciBzcGVjaWZpYyBpbmZvcm1hdGlvbiwgdGhlIHNlY3Rpb24gb24gZG9jVmFsdWVzIHR5cGVzIGlzIGEgTHVjZW5lIHNwZWNpZmljIGltcGxlbWVudGF0aW9uIGRldGFpbCB0aGF0IGFwcGxpZXMgdG8gT3BlblNlYXJjaCBhcyB3ZWxsLlx1MDBhMDxcL3NwYW4+PFwvcD4ifSwiZWxlbWVudHMiOltdLCJ3aWRnZXRUeXBlIjoidGV4dC1lZGl0b3IifQ==\\\"]\\t\\t<div class=\\\"elementor-element elementor-element-495477a flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-heading\\\" data-id=\\\"495477a\\\" data-element_type=\\\"widget\\\" data-e-type=\\\"widget\\\" data-widget_type=\\\"heading.default\\\">\\n\\t\\t\\t\\t<div class=\\\"elementor-widget-container\\\">\\n\\t\\t\\t\\t\\t<h3 class=\\\"elementor-heading-title elementor-size-medium\\\">Scripting<\\\/h3>\\t\\t\\t\\t<\\\/div>\\n\\t\\t\\t\\t<\\\/div>\\n\\t\\t[elementor-element k=\\\"9109a976d8649ee6d2c8fef8daebbb8b\\\" data=\\\"eyJpZCI6ImVjZmZhMjEiLCJlbFR5cGUiOiJ3aWRnZXQiLCJzZXR0aW5ncyI6eyJlZGl0b3IiOiI8cD48c3BhbiBzdHlsZT1cImZvbnQtd2VpZ2h0OiA0MDA7XCI+T3BlblNlYXJjaCBvZmZlcnMgdXNlcnMgdGhlIGFiaWxpdHkgdG8gaW5jbHVkZSBzY3JpcHRzIHdpdGggYWdncmVnYXRpb25zIHZpYSB0aGUgXHUyMDFjc2NyaXB0ZWRfbWV0cmljXHUyMDFkIGFnZ3JlZ2F0aW9uIHR5cGUuIFRoaXMgbGV2ZXJhZ2VzIHRoZSBwYWlubGVzcyBzY3JpcHRpbmcgbGFuZ3VhZ2UsIGJ1aWx0IHNwZWNpZmljYWxseSBmb3IgRWxhc3RpY3NlYXJjaCAoYW5kIHN1YnNlcXVlbnRseSBPcGVuU2VhcmNoKS4gUGFpbmxlc3MgaGFzIEphdmEtbGlrZSBzeW50YXggYW5kIGNvbXBpbGVzIGRpcmVjdGx5IGludG8gSlZNIGJ5dGVjb2RlLCBsZXZlcmFnaW5nIGFueSBvcHRpbWl6YXRpb25zIHRoYXQgdGhlIEpWTSBoYXMuXHUwMGEwPFwvc3Bhbj48XC9wPjxwPjxzcGFuIHN0eWxlPVwiZm9udC13ZWlnaHQ6IDQwMDtcIj5XaXRoIHBhaW5sZXNzLCB3ZSBoYXZlIGFjY2VzcyB0byB0aGUgXHUyMDFjX3NvdXJjZVx1MjAxZCB2YXJpYWJsZSB0aGF0IG9mZmVycyB1cyB0aGUgYWJpbGl0eSB0byB2aWV3IHRoZSBzZWdtZW50IGRhdGEgb24gc3BlY2lmaWMgZmllbGRzLiBXaXRoIHRoaXMgYXBwcm9hY2gsIHdlIHNob3VsZCBiZSBhYmxlIHRvIGFjY2VzcyBkdXBsaWNhdGVzIG9uIG91ciBrZXl3b3JkIGZpZWxkIHR5cGUgYW5kIGFnZ3JlZ2F0ZSB0aGVtIHRvZ2V0aGVyIHZpYSBhIGhhc2htYXAgZGVmaW5lZCBieSBvdXIgc2NyaXB0Llx1MDBhMDxcL3NwYW4+PFwvcD48cD48c3BhbiBzdHlsZT1cImZvbnQtd2VpZ2h0OiA0MDA7XCI+SGVyZVx1MjAxOXMgd2hhdCB0aGUgc2NyaXB0IGxvb2tlZCBsaWtlIGluc2lkZSBvZiBhbiBhZ2dyZWdhdGlvbiBxdWVyeTo8XC9zcGFuPjxcL3A+In0sImVsZW1lbnRzIjpbXSwid2lkZ2V0VHlwZSI6InRleHQtZWRpdG9yIn0=\\\"]\\t\\t<div class=\\\"elementor-element elementor-element-e071421 flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-code-highlight\\\" data-id=\\\"e071421\\\" data-element_type=\\\"widget\\\" data-e-type=\\\"widget\\\" data-widget_type=\\\"code-highlight.default\\\">\\n\\t\\t\\t\\t<div class=\\\"elementor-widget-container\\\">\\n\\t\\t\\t\\t\\t\\t\\t<div class=\\\"prismjs-tomorrow copy-to-clipboard word-wrap\\\">\\n\\t\\t\\t<pre data-line=\\\"\\\" class=\\\"highlight-height language-javascript \\\">\\n\\t\\t\\t\\t<code readonly=\\\"true\\\" class=\\\"language-javascript\\\">\\n\\t\\t\\t\\t\\t<xmp>{\\r\\n\\t\\\"size\\\": 0,\\r\\n\\t\\\"aggs\\\": {\\r\\n    \\t\\\"ingredient_frequency\\\": {\\r\\n      \\t\\\"scripted_metric\\\": {\\r\\n        \\t\\\"init_script\\\": \\\"state.foodFreq = new HashMap();\\\",\\r\\n        \\t\\\"map_script\\\": \\\"for (f in params._source.favorite_foods) { if (state.foodFreq.get(f) == null) { state.foodFreq.put(f, 1); } else { state.foodFreq.put(f, state.foodFreq.get(f) + 1); }}\\\",\\r\\n        \\t\\\"combine_script\\\": \\\"return state.foodFreq;\\\",\\r\\n        \\t\\\"reduce_script\\\": \\\"\\\"\\\"\\r\\nMap finalMap = new HashMap(); \\r\\nfor (map in states) { \\r\\n for (key in map.keySet()) { \\r\\n  if (finalMap.get(key) == null) { \\r\\n   def val = map[key]; \\r\\n   finalMap.put(key, map[key]); \\r\\n  } \\r\\n  else {\\r\\n   def prevVal = finalMap[key]; \\r\\n   finalMap.put(key, prevVal + map[key]); \\r\\n  }\\r\\n  }\\r\\n} \\r\\nreturn finalMap;\\r\\n\\\"\\\"\\\"\\r\\n      \\t}\\r\\n    \\t}\\r\\n  \\t    }\\r\\n  }\\r\\n<\\\/xmp>\\n\\t\\t\\t\\t<\\\/code>\\n\\t\\t\\t<\\\/pre>\\n\\t\\t<\\\/div>\\n\\t\\t\\t\\t\\t\\t<\\\/div>\\n\\t\\t\\t\\t<\\\/div>\\n\\t\\t[elementor-element k=\\\"9109a976d8649ee6d2c8fef8daebbb8b\\\" data=\\\"eyJpZCI6Ijk1MjlhNTMiLCJlbFR5cGUiOiJ3aWRnZXQiLCJzZXR0aW5ncyI6eyJlZGl0b3IiOiI8cD48c3BhbiBzdHlsZT1cImZvbnQtd2VpZ2h0OiA0MDA7XCI+Tm90aWNlIHRoYXQgdGhpcyBpcyBxdWl0ZSBicnV0ZS1mb3JjZS4gV2UgaGF2ZSB0byBhY2NvdW50IGZvciBlYWNoIGFuZCBldmVyeSB2YWx1ZSwgcGxhY2UgdGhlbSBpbiBhIGhhc2htYXAsIGFuZCB0aGVuIGNvbWJpbmUgdGhlc2UgaGFzaG1hcHMgYWNyb3NzIHNoYXJkcyB2aWEgdGhlIFx1MjAxY3JlZHVjZV9zY3JpcHRcdTIwMWQuIEFsc28sIHdlIGRvblx1MjAxOXQgbGV2ZXJhZ2UgdGhlIGhpZ2hseSBwZXJmb3JtYW50IGRvY192YWx1ZXMgZGF0YSBzdHJ1Y3R1cmUsIGJ1aWx0IGZvciBhZ2dyZWdhdGlvbnMuIFdlIGtub3cgdGhpcywgYXMgd2UgYXJlIGFjY2Vzc2luZyBcdTIwMWNfc291cmNlXHUyMDFkIHdoaWNoIHRha2VzIGluZm9ybWF0aW9uIGRpcmVjdGx5IGZyb20gTHVjZW5lIHNlZ21lbnRzLCByYXRoZXIgdGhhbiBmcm9tIGRvY192YWx1ZXMuIEluIHRoZSBiZW5jaG1hcmtpbmcgc2VjdGlvbiwgdGhlc2Ugb2JzZXJ2YXRpb25zIHdpbGwgYmUgc3Vic3RhbnRpYXRlZCBieSBvdXIgZ2F0aGVyZWQgcGVyZm9ybWFuY2Ugc3RhdGlzdGljcy5cdTAwYTA8XC9zcGFuPjxcL3A+PHA+PHNwYW4gc3R5bGU9XCJmb250LXdlaWdodDogNDAwO1wiPkZvciBtb3JlIGluZm9ybWF0aW9uIG9uIHRoZSBzY3JpcHRlZF9tZXRyaWMgYWdncmVnYXRpb24sIGhlcmVcdTIwMTlzIGEgbGluayB0byA8XC9zcGFuPjxhIGhyZWY9XCJodHRwczpcL1wvd3d3LmVsYXN0aWMuY29cL2d1aWRlXC9lblwvZWxhc3RpY3NlYXJjaFwvcmVmZXJlbmNlXC9jdXJyZW50XC9tb2R1bGVzLXNjcmlwdGluZy1wYWlubGVzcy5odG1sXCI+PHNwYW4gc3R5bGU9XCJmb250LXdlaWdodDogNDAwO1wiPm9mZmljaWFsIGRvY3VtZW50YXRpb248XC9zcGFuPjxcL2E+PHNwYW4gc3R5bGU9XCJmb250LXdlaWdodDogNDAwO1wiPi48XC9zcGFuPjxcL3A+In0sImVsZW1lbnRzIjpbXSwid2lkZ2V0VHlwZSI6InRleHQtZWRpdG9yIn0=\\\"]\\t\\t<div class=\\\"elementor-element elementor-element-8a8978f flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-heading\\\" data-id=\\\"8a8978f\\\" data-element_type=\\\"widget\\\" data-e-type=\\\"widget\\\" data-widget_type=\\\"heading.default\\\">\\n\\t\\t\\t\\t<div class=\\\"elementor-widget-container\\\">\\n\\t\\t\\t\\t\\t<h3 class=\\\"elementor-heading-title elementor-size-medium\\\">Nested Fields<\\\/h3>\\t\\t\\t\\t<\\\/div>\\n\\t\\t\\t\\t<\\\/div>\\n\\t\\t[elementor-element k=\\\"9109a976d8649ee6d2c8fef8daebbb8b\\\" data=\\\"eyJpZCI6ImY2ZjY2MzAiLCJlbFR5cGUiOiJ3aWRnZXQiLCJzZXR0aW5ncyI6eyJlZGl0b3IiOiI8cD48c3BhbiBzdHlsZT1cImZvbnQtd2VpZ2h0OiA0MDA7XCI+U2NyaXB0aW5nIHdvcmtlZCB3aXRoaW4gdGhlIGNvbmZpbmVzIG9mIG91ciBvcmlnaW5hbCBvcmdhbmlzYXRpb24gb2YgdGhlIHJlY2lwZSBib29rLiBXZSB3YW50ZWQgb3VyIGluZ3JlZGllbnRzIHRvIGJlIHJlcHJlc2VudGVkIGluIGEgbXVsdGktdmFsdWVkIGZpZWxkLiBIb3dldmVyLCBpZiB3ZSBjYW5cdTIwMTl0IHNlZSBkdXBsaWNhdGUgdmFsdWVzIGFjcm9zcyBtdWx0aS12YWx1ZWQgZmllbGRzIGR1ZSB0byB0aGUgZG9jX3ZhbHVlIGxpbWl0YXRpb24sIHdoeSBub3QgdHJ5IHRvIGNoYW5nZSBob3cgdGhlIGRvY3VtZW50cyB0aGVtc2VsdmVzIGFyZSBpbmRleGVkPzxcL3NwYW4+PFwvcD48cD48c3BhbiBzdHlsZT1cImZvbnQtd2VpZ2h0OiA0MDA7XCI+XHUwMGEwPFwvc3Bhbj48c3BhbiBzdHlsZT1cImZvbnQtd2VpZ2h0OiA0MDA7XCI+T3BlblNlYXJjaCBvZmZlcnMgdXNlcnMgdGhlIGFiaWxpdHkgdG8gY3JlYXRlIGlubmVyIG9yIFx1MjAxY25lc3RlZFx1MjAxZCBkb2N1bWVudHMgd2l0aGluIG90aGVyIGRvY3VtZW50cy4gRWFjaCBuZXN0ZWQgZG9jdW1lbnQgaXMgdW5kZXJseWluZ2x5IHRyZWF0ZWQgYXMgYSBcdTIwMWNoaWRkZW5cdTIwMWQgTHVjZW5lIGRvY3VtZW50LCBhbGxvd2luZyBmb3IgYSBuZXN0ZWQgYWdncmVnYXRpb24gdGhhdCB3b3VsZCBndWFyYW50ZWUgdGhhdCB3ZSB3b3VsZCBiZSBhYmxlIHRvIHNlZSBkdXBsaWNhdGUgZG9jdW1lbnRzLlx1MDBhMDxcL3NwYW4+PFwvcD48cD48c3BhbiBzdHlsZT1cImZvbnQtd2VpZ2h0OiA0MDA7XCI+V2UgY2FuIGltcGxlbWVudCB0aGlzLCBzaW1wbHksIHdpdGggdGhlIGZvbGxvd2luZzo8XC9zcGFuPjxcL3A+In0sImVsZW1lbnRzIjpbXSwid2lkZ2V0VHlwZSI6InRleHQtZWRpdG9yIn0=\\\"]\\t\\t<div class=\\\"elementor-element elementor-element-71c1c92 flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-code-highlight\\\" data-id=\\\"71c1c92\\\" data-element_type=\\\"widget\\\" data-e-type=\\\"widget\\\" data-widget_type=\\\"code-highlight.default\\\">\\n\\t\\t\\t\\t<div class=\\\"elementor-widget-container\\\">\\n\\t\\t\\t\\t\\t\\t\\t<div class=\\\"prismjs-tomorrow copy-to-clipboard word-wrap\\\">\\n\\t\\t\\t<pre data-line=\\\"\\\" class=\\\"highlight-height language-javascript \\\">\\n\\t\\t\\t\\t<code readonly=\\\"true\\\" class=\\\"language-javascript\\\">\\n\\t\\t\\t\\t\\t<xmp>PUT \\\/recipe-book\\r\\n{\\r\\n  \\\"mappings\\\": {\\r\\n    \\\"properties\\\": {\\r\\n      \\\"favorite_foods\\\": {\\r\\n   \\t \\\"type\\\": \\\"nested\\\",\\r\\n   \\t \\\"properties\\\": {\\r\\n \\t\\t \\\"food\\\": {\\r\\n \\t\\t \\\"type\\\": \\\"keyword\\\"\\r\\n \\t\\t }\\r\\n   \\t  }\\r\\n     }\\r\\n    }\\r\\n  }\\r\\n}   \\r\\n\\r\\nPUT \\\/recipe-book\\\/_doc\\\/1\\r\\n{\\r\\n  \\\"favorite_foods\\\": [\\r\\n    {\\r\\n      \\\"food\\\": \\\"carrot\\\"\\r\\n    },\\r\\n    {\\r\\n      \\\"food\\\": \\\"carrot\\\"\\r\\n    },\\r\\n    {\\r\\n      \\\"food\\\": \\\"apple\\\"\\r\\n    },\\r\\n    {\\r\\n      \\\"food\\\": \\\"cucumber\\\"\\r\\n    }\\r\\n  ]\\r\\n}\\r\\n\\r\\nPUT \\\/recipe-book\\\/_doc\\\/2\\r\\n{\\r\\n  \\\"favorite_foods\\\": [\\r\\n    {\\r\\n      \\\"food\\\": \\\"carrot\\\"\\r\\n    },\\r\\n    {\\r\\n      \\\"food\\\": \\\"apple\\\"\\r\\n    },\\r\\n    {\\r\\n      \\\"food\\\": \\\"cucumber\\\"\\r\\n    }\\r\\n  ]\\r\\n}\\r\\n\\r\\nPUT \\\/recipe-book\\\/_doc\\\/3\\r\\n{\\r\\n  \\\"favorite_foods\\\": [\\r\\n    {\\r\\n      \\\"food\\\": \\\"cucumber\\\"\\r\\n    },\\r\\n    {\\r\\n      \\\"food\\\": \\\"cucumber\\\"\\r\\n    },\\r\\n    {\\r\\n      \\\"food\\\": \\\"cucumber\\\"\\r\\n    }\\r\\n  ]\\r\\n}\\r\\n\\r\\n{\\r\\n  \\\"size\\\": 0,\\r\\n  \\\"aggs\\\": {\\r\\n\\t\\\"favorite_foods\\\": {\\r\\n  \\t\\\"nested\\\": {\\r\\n    \\t\\\"path\\\": \\\"favorite_foods\\\"\\r\\n  \\t},\\r\\n  \\t\\\"aggs\\\": {\\r\\n    \\t\\\"food_freq\\\": {\\r\\n      \\t\\\"terms\\\": {\\r\\n        \\t\\\"size\\\": 10000,\\r\\n        \\t\\\"field\\\": \\\"favorite_foods.data\\\"\\r\\n      \\t}\\r\\n    \\t}\\r\\n    \\t}\\r\\n    \\t}\\r\\n  }\\r\\n}\\r\\n\\r\\n\\\"aggregations\\\": {\\r\\n\\t\\\"favorite_foods\\\": {\\r\\n  \\t\\\"doc_count\\\": 10,\\r\\n  \\t\\\"food_freq\\\": {\\r\\n    \\t\\\"doc_count_error_upper_bound\\\": 0,\\r\\n    \\t\\\"sum_other_doc_count\\\": 0,\\r\\n    \\t\\\"buckets\\\": [\\r\\n      \\t{\\r\\n        \\t\\\"key\\\": \\\"cucumber\\\",\\r\\n        \\t\\\"doc_count\\\": 5\\r\\n      \\t},\\r\\n      \\t{\\r\\n        \\t\\\"key\\\": \\\"carrot\\\",\\r\\n        \\t\\\"doc_count\\\": 3\\r\\n      \\t},\\r\\n      \\t{\\r\\n        \\t\\\"key\\\": \\\"apple\\\",\\r\\n        \\t\\\"doc_count\\\": 2\\r\\n      \\t}\\r\\n    \\t]\\r\\n  \\t    }\\r\\n\\t    }\\r\\n}<\\\/xmp>\\n\\t\\t\\t\\t<\\\/code>\\n\\t\\t\\t<\\\/pre>\\n\\t\\t<\\\/div>\\n\\t\\t\\t\\t\\t\\t<\\\/div>\\n\\t\\t\\t\\t<\\\/div>\\n\\t\\t[elementor-element k=\\\"9109a976d8649ee6d2c8fef8daebbb8b\\\" data=\\\"eyJpZCI6ImJhNDg0YTIiLCJlbFR5cGUiOiJ3aWRnZXQiLCJzZXR0aW5ncyI6eyJlZGl0b3IiOiI8cD48c3BhbiBzdHlsZT1cImZvbnQtd2VpZ2h0OiA0MDA7XCI+VGhpcyBpbXBsZW1lbnRhdGlvbiBpcyBzaW1wbGUgYXQgZmlyc3QgZ2xhbmNlLCBidXQgdGhpcyBhcHByb2FjaCBjYW4gcXVpY2tseSBjYXVzZSBwcm9ibGVtcyBhdCBzY2FsZS4gTmVzdGVkIGRvY3VtZW50cyBhcmUgaW5oZXJlbnRseSBkb2N1bWVudHMsIHRoZXJlZm9yZSB0aGV5IHRha2UgdXAgdGhlaXIgb3duIHNwYWNlIGluIHRoZSBpbmRleC4gMjAwIHJlY2lwZXMgd2l0aCAyMCBhdmVyYWdlIGluZ3JlZGllbnRzIGluIGVhY2ggd291bGQgbGVhZCB0byBvdmVyIDQwMDAgZG9jdW1lbnRzLiBBZ2Fpbiwgd2VcdTIwMTlsbCBzZWUgaG93IHRoaXMgaW1wbGVtZW50YXRpb24gZmFyZXMgaW4gb3VyIGJlbmNobWFya3MuXHUwMGEwPFwvc3Bhbj48XC9wPjxwPjxzcGFuIHN0eWxlPVwiZm9udC13ZWlnaHQ6IDQwMDtcIj5Gb3IgbW9yZSBpbmZvcm1hdGlvbiBvbiB0aGUgbmVzdGVkIGZpZWxkIGFnZ3JlZ2F0aW9ucywgaGVyZVx1MjAxOXMgYSBsaW5rIHRvIDxcL3NwYW4+PGEgaHJlZj1cImh0dHBzOlwvXC93d3cuZWxhc3RpYy5jb1wvZ3VpZGVcL2VuXC9lbGFzdGljc2VhcmNoXC9yZWZlcmVuY2VcL2N1cnJlbnRcL3NlYXJjaC1hZ2dyZWdhdGlvbnMtYnVja2V0LW5lc3RlZC1hZ2dyZWdhdGlvbi5odG1sXCI+PHNwYW4gc3R5bGU9XCJmb250LXdlaWdodDogNDAwO1wiPm9mZmljaWFsIGRvY3VtZW50YXRpb248XC9zcGFuPjxcL2E+PHNwYW4gc3R5bGU9XCJmb250LXdlaWdodDogNDAwO1wiPi48XC9zcGFuPjxcL3A+In0sImVsZW1lbnRzIjpbXSwid2lkZ2V0VHlwZSI6InRleHQtZWRpdG9yIn0=\\\"]\\t\\t<div class=\\\"elementor-element elementor-element-93e1cde flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-heading\\\" data-id=\\\"93e1cde\\\" data-element_type=\\\"widget\\\" data-e-type=\\\"widget\\\" data-widget_type=\\\"heading.default\\\">\\n\\t\\t\\t\\t<div class=\\\"elementor-widget-container\\\">\\n\\t\\t\\t\\t\\t<h3 class=\\\"elementor-heading-title elementor-size-medium\\\">Underscore Representation<\\\/h3>\\t\\t\\t\\t<\\\/div>\\n\\t\\t\\t\\t<\\\/div>\\n\\t\\t[elementor-element k=\\\"9109a976d8649ee6d2c8fef8daebbb8b\\\" data=\\\"eyJpZCI6ImI1NjJiNWIiLCJlbFR5cGUiOiJ3aWRnZXQiLCJzZXR0aW5ncyI6eyJlZGl0b3IiOiI8cD48c3BhbiBzdHlsZT1cImZvbnQtd2VpZ2h0OiA0MDA7XCI+TGV0XHUyMDE5cyB0cnkgc29tZXRoaW5nIGRpZmZlcmVudC4gTGV0XHUyMDE5cyBnbyBiYWNrIHRvIHVzaW5nIG11bHRpLXZhbHVlZCBmaWVsZHMsIGJ1dCB0aGlzIHRpbWUsIGxldFx1MjAxOXMgbG9vayBhdCBob3cgdGhlIGluZ3JlZGllbnRzIHRoZW1zZWx2ZXMgYXJlIHJlcHJlc2VudGVkLiBXaGF0IGlmIHdlIGNoYW5nZWQgdGhlIHJlcHJlc2VudGF0aW9uIGZyb20gW2NhcnJvdHMsIGNhcnJvdHMsIGFwcGxlLCBjdWN1bWJlcl0gdG8gW2NhcnJvdHNfMiwgYXBwbGVfMSwgY3VjdW1iZXJfMV0\\\/IEJ5IGFwcGVuZGluZyBvdXIgY291bnRzLCB3ZSByZXRhaW4gaW5mb3JtYXRpb24gYWJvdXQgZHVwbGljYXRlcywgd2l0aG91dCBleHBvc2luZyBkdXBsaWNhdGVzIHRvIHRoZSB1bmRlcmx5aW5nIGRvY192YWx1ZXMgZGF0YSBzdHJ1Y3R1cmUuIFdlIGNhbiBwZXJmb3JtIHRoaXMgY29udmVyc2lvbiBhdCBpbmRleCB0aW1lIHdlbGwgaW4gYWR2YW5jZS4gVGhlIHF1ZXN0aW9uIG5vdyByZW1haW5zIGFzIHRvIGhvdyB3ZSBjYW4gYWdncmVnYXRlIHVwb24gdGhvc2UgXHUyMDFjc3VmZml4ZXNcdTIwMWQgb3IgbnVtYmVycyBhZnRlciBvdXIgdW5kZXJzY29yZSBkZWxpbWl0ZXIuXHUwMGEwPFwvc3Bhbj48XC9wPjxwPjxzcGFuIHN0eWxlPVwiZm9udC13ZWlnaHQ6IDQwMDtcIj5XZSBjYW4gdHJ5IHRvIHdyaXRlIGNvZGUgZGlyZWN0bHkgd2l0aGluIGEgY2xvbmVkIHJlcG9zaXRvcnkgb2YgdGhlIE9wZW5TZWFyY2ggY29kZWJhc2VcdTAwYTAgYW5kIHRlc3QgdG8gc2VlIGlmIHdlIGNhbiBjcmVhdGUgYSBwZXJmb3JtYW50IHNvbHV0aW9uIHdpdGggcmVnYXJkcyB0byB0aGlzIHJlcHJlc2VudGF0aW9uIG9mIG91ciBpbmdyZWRpZW50cy4gSWYgdGhpcyBzb2x1dGlvbiBwcm92ZXMgdG8gYmUgYSB3aW5uZXIgaW4gb3VyIGJlbmNobWFya3MsIHdlIGNhbiBtb3ZlIHRoaXMgY29kZSBvdmVyIHRvIGEgcGx1Zy1pbiBhcmNoaXRlY3R1cmUgdGhhdFx1MjAxOXMgZWFzaWx5IHBhY2thZ2VhYmxlIGFuZCBjYW4gYmUgaW5zdGFsbGVkIHZpYSBhIHNpbmdsZSBjb21tYW5kIGJ5IG90aGVyIHVzZXJzLlx1MDBhMDxcL3NwYW4+PFwvcD48cD48c3BhbiBzdHlsZT1cImZvbnQtd2VpZ2h0OiA0MDA7XCI+SGVyZVx1MjAxOXMgaG93IHRoZSBleGFtcGxlIGZyb20gYmVmb3JlIG1pZ2h0IGxvb2sgbGlrZSB3aXRoIG91ciBuZXcgcmVwcmVzZW50YXRpb246PFwvc3Bhbj48XC9wPiJ9LCJlbGVtZW50cyI6W10sIndpZGdldFR5cGUiOiJ0ZXh0LWVkaXRvciJ9\\\"]\\t\\t<div class=\\\"elementor-element elementor-element-8a11f9b flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-code-highlight\\\" data-id=\\\"8a11f9b\\\" data-element_type=\\\"widget\\\" data-e-type=\\\"widget\\\" data-widget_type=\\\"code-highlight.default\\\">\\n\\t\\t\\t\\t<div class=\\\"elementor-widget-container\\\">\\n\\t\\t\\t\\t\\t\\t\\t<div class=\\\"prismjs-tomorrow copy-to-clipboard word-wrap\\\">\\n\\t\\t\\t<pre data-line=\\\"\\\" class=\\\"highlight-height language-javascript \\\">\\n\\t\\t\\t\\t<code readonly=\\\"true\\\" class=\\\"language-javascript\\\">\\n\\t\\t\\t\\t\\t<xmp>curl -XPUT \\\"http:\\\/\\\/localhost:9200\\\/recipe-book\\\" -H 'Content-Type: application\\\/json' -d' \\t \\r\\n{\\r\\n  \\\"mappings\\\": {\\r\\n    \\\"properties\\\": {\\r\\n    \\t \\\"favorite_foods\\\": {\\r\\n   \\t\\t\\t \\\"type\\\": \\\"keyword\\\"\\r\\n     \\t }\\r\\n     }\\r\\n   }\\r\\n}'\\r\\n\\r\\ncurl -XPUT \\\"http:\\\/\\\/localhost:9200\\\/recipe-book\\\/_doc\\\/1\\\" -H 'Content-Type: application\\\/json' -d'\\r\\n{\\r\\n  \\\"favorite_foods\\\": [\\\"apple_1\\\", \\\"carrot_2\\\", \\\"cucumber_1\\\"]\\r\\n}'\\r\\n\\r\\ncurl -XPUT \\\"http:\\\/\\\/localhost:9200\\\/recipe-book\\\/_doc\\\/2\\\" -H 'Content-Type: application\\\/json' -d'\\r\\n{\\r\\n  \\\"favorite_foods\\\": [\\\"apple_1\\\", \\\"carrot_1\\\", \\\"cucumber_1\\\"]\\r\\n}'\\r\\n\\r\\ncurl -XPUT \\\"http:\\\/\\\/localhost:9200\\\/recipe-book\\\/_doc\\\/3\\\" -H 'Content-Type: application\\\/json' -d'\\r\\n{\\r\\n  \\\"favorite_foods\\\": [\\\"cucumber_3\\\"]\\r\\n}'\\r\\n<\\\/xmp>\\n\\t\\t\\t\\t<\\\/code>\\n\\t\\t\\t<\\\/pre>\\n\\t\\t<\\\/div>\\n\\t\\t\\t\\t\\t\\t<\\\/div>\\n\\t\\t\\t\\t<\\\/div>\\n\\t\\t[elementor-element k=\\\"9109a976d8649ee6d2c8fef8daebbb8b\\\" data=\\\"eyJpZCI6IjlhODM2MTMiLCJlbFR5cGUiOiJ3aWRnZXQiLCJzZXR0aW5ncyI6eyJlZGl0b3IiOiI8cD48c3BhbiBzdHlsZT1cImZvbnQtd2VpZ2h0OiA0MDA7XCI+V2UgdG9vayBhIGxvb2sgYXQgdGhlIE9wZW5TZWFyY2ggY29kZWJhc2UsIGZpbmRpbmcgdGhlIGNvZGUgcGF0aCBieSB3aGljaCB0cmFkaXRpb25hbCB0ZXJtcyBhZ2dyZWdhdGlvbnMgd2VyZSBwZXJmb3JtZWQuIFRoZXJlIHdlcmUgdHdvIFx1MjAxY2FnZ3JlZ2F0b3JcdTIwMWQgY2xhc3NlcyB0aGF0IE9wZW5TZWFyY2ggdXNlcyBpbiBhIHRlcm1zIGFnZ3JlZ2F0aW9uLCBlaXRoZXIgdGhlIEdsb2JhbE9yZGluYWxzU3RyaW5nVGVybXNBZ2dyZWdhdG9yIG9yIHRoZSBNYXBTdHJpbmdUZXJtc0FnZ3JlZ2F0b3IuIFRoZSBHbG9iYWwgT3JkaW5hbHMgYWdncmVnYXRpb24gdGFrZXMgYWR2YW50YWdlIG9mIGdsb2JhbCBvcmRpbmFscywgbWFwcGluZ3Mgb2Ygc2VnbWVudCBvcmRpbmFscyB0byB0aGVpciBvcmlnaW5hbCBsb2NhdGlvbnMgYXQgYSBcdTIwMWNnbG9iYWxcdTIwMWQgbGV2ZWwuIFdoaWxlIHRoaXMgaXMgdGhlIHRyYWRpdGlvbmFsIGFnZ3JlZ2F0b3IgdXNlZCBmb3IgdGVybXMgYWdncmVnYXRpb25zLCBzZWVpbmcgdGhhdCBhZ2dyZWdhdGlvbnMgb2NjdXIgYWNyb3NzIHNoYXJkcyBhbmQgc2VnbWVudHMsIHdlIG9wdGVkIHRvIGJhc2Ugb3VyIGN1c3RvbSBpbXBsZW1lbnRhdGlvbiBpbiB0aGUgTWFwU3RyaW5nVGVybXNBZ2dyZWdhdG9yLlx1MDBhMDxcL3NwYW4+PFwvcD48cD48c3BhbiBzdHlsZT1cImZvbnQtd2VpZ2h0OiA0MDA7XCI+VGhlIEdsb2JhbE9yZGluYWxzU3RyaW5nVGVybXNBZ2dyZWdhdG9yIGRlYWxzIGluIGdsb2JhbE9yZHMgcmVwcmVzZW50ZWQgYXMgbG9uZ3MsIHdoaWNoIGFyZSBub3QgZWFzaWx5IGNvbnZlcnRpYmxlIGludG8gU3RyaW5ncy4gV2UgbmVlZCB0byBkZWFsIHdpdGggU3RyaW5ncyBpbiBvcmRlciB0byBzZXBhcmF0ZSB0aGUgc3VmZml4IGNvdW50IGZyb20gdGhlIGRlbGltaXRlci4gVGhlIE1hcFN0cmluZ1Rlcm1zQWdncmVnYXRvciB1c2VzIGEgcmVwcmVzZW50YXRpb24gb2YgZG9jIHZhbHVlcyB0aGF0IGVuYWJsZXMgZm9yIG9yZGluYWwgcmVwcmVzZW50YXRpb25zIHRvIGJlIGNvbnZlcnRlZCB0byBCeXRlc1JlZnMgYW5kIHN1YnNlcXVlbnRseSB0byBTdHJpbmdzLlx1MDBhMDxcL3NwYW4+PFwvcD48cD48c3BhbiBzdHlsZT1cImZvbnQtd2VpZ2h0OiA0MDA7XCI+Rm9sbG93aW5nIGZ1cnRoZXIgZG93biB0aGUgY29kZSBwYXRoLCB3ZSB0aGVuIG1vZGlmaWVkIHRoZSBkb2MgdmFsdWVzIHR5cGluZyB1c2VkIGJ5IHRoZSBNYXBTdHJpbmdUZXJtc0FnZ3JlZ2F0b3IsIHNwZWNpZmljYWxseSB0aGUgU29ydGVkQmluYXJ5RG9jVmFsdWVzIHR5cGUsIGFuZCBjcmVhdGVkIGEgY3VzdG9tIGltcGxlbWVudGF0aW9uIHRoYXQgc2VwYXJhdGVkIHRoZSBzdWZmaXggZnJvbSBvdXIgdGVybSAoYXBwbGVfMyBcdTIxOTIgYXBwbGUsIDMpIGFuZCBjcmVhdGVkIG5ldyBidWNrZXRzIHdpdGggdGhlc2UgbmV3IHRlcm1zIGFzIGtleXMgYW5kIHN1ZmZpeGVzIGFzIGNvdW50cy4gV2UgdGhlbiBzZW50IFx1MjAxY2Zha2VcdTIwMWQgdmFsdWVzIHRvIHRoZSBMZWFmQ29sbGVjdG9yIG1ldGhvZCB0aGF0IHdvdWxkIG1pbWljIHRoZSBidWNrZXQgY291bnRzIHRoYXQgd2UgcmVxdWlyZWQuIEZvciBleGFtcGxlLCB0aGUgdmFsdWUgYXBwbGVfMyB3b3VsZCBiZSBzZWVuIGJ5IHRoZSBjb2xsZWN0b3IgYXMgYXBwbGUsIGFwcGxlKGZha2UpLCBhcHBsZShmYWtlKS5cdTAwYTA8XC9zcGFuPjxcL3A+PHA+PHNwYW4gc3R5bGU9XCJmb250LXdlaWdodDogNDAwO1wiPk9uIGZ1cnRoZXIgaXRlcmF0aW9uLCBjYWNoaW5nIHZpYSBIYXNobWFwIHdhcyBzdXBwb3J0ZWQgdG8gcHJldmVudCBtdWx0aXBsZSBvcmRpbmFsIGxvb2t1cHMgYW5kIG11bHRpcGxlIGNvbnZlcnNpb25zIGZyb20gQnl0ZXNSZWYgdG8gU3RyaW5ncywgaW1wcm92aW5nIHBlcmZvcm1hbmNlIGluIHRoZSBwcm9jZXNzLlx1MDBhMDxcL3NwYW4+PFwvcD4ifSwiZWxlbWVudHMiOltdLCJ3aWRnZXRUeXBlIjoidGV4dC1lZGl0b3IifQ==\\\"]\\t\\t<div class=\\\"elementor-element elementor-element-c6abd2e flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-spacer\\\" data-id=\\\"c6abd2e\\\" data-element_type=\\\"widget\\\" data-e-type=\\\"widget\\\" data-widget_type=\\\"spacer.default\\\">\\n\\t\\t\\t\\t<div class=\\\"elementor-widget-container\\\">\\n\\t\\t\\t\\t\\t\\t\\t<div class=\\\"elementor-spacer\\\">\\n\\t\\t\\t<div class=\\\"elementor-spacer-inner\\\"><\\\/div>\\n\\t\\t<\\\/div>\\n\\t\\t\\t\\t\\t\\t<\\\/div>\\n\\t\\t\\t\\t<\\\/div>\\n\\t\\t\\t\\t<div class=\\\"elementor-element elementor-element-8ca4920 flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-heading\\\" data-id=\\\"8ca4920\\\" data-element_type=\\\"widget\\\" data-e-type=\\\"widget\\\" data-widget_type=\\\"heading.default\\\">\\n\\t\\t\\t\\t<div class=\\\"elementor-widget-container\\\">\\n\\t\\t\\t\\t\\t<h3 class=\\\"elementor-heading-title elementor-size-large\\\">Benchmarks &amp; Takeaways<\\\/h3>\\t\\t\\t\\t<\\\/div>\\n\\t\\t\\t\\t<\\\/div>\\n\\t\\t[elementor-element k=\\\"9109a976d8649ee6d2c8fef8daebbb8b\\\" data=\\\"eyJpZCI6IjhjZGY4MWEiLCJlbFR5cGUiOiJ3aWRnZXQiLCJzZXR0aW5ncyI6eyJlZGl0b3IiOiI8cD48c3BhbiBzdHlsZT1cImZvbnQtd2VpZ2h0OiA0MDA7XCI+V2Ugbm93IGhhdmUgdGhyZWUgaW1wbGVtZW50YXRpb25zIHRoYXQgZWFjaCBuZXQgdXMgdGhlIGV4cGVjdGVkIHJlc3VsdC4gSXQgbm93IHJlbWFpbnMgdG8gc2VlIHdoaWNoIGltcGxlbWVudGF0aW9uIHdpbGwgb2ZmZXIgdXMgdGhlIGJlc3Qgc29sdXRpb24gaW4gYWNjb3JkYW5jZSB3aXRoIG91ciBndWlkZWxpbmVzLlx1MDBhMDxcL3NwYW4+PFwvcD48cD48c3BhbiBzdHlsZT1cImZvbnQtd2VpZ2h0OiA0MDA7XCI+V2UgdXNlZCBKTWV0ZXIgdG8gdGVzdCB0aGUgcXVlcnkgcGVyZm9ybWFuY2UuIEhlcmUgYXJlIGltcG9ydGFudCBwb2ludHMgcmVnYXJkaW5nIGhvdyB0aGUgaW1wbGVtZW50YXRpb25zIHdlcmUgYmVuY2htYXJrZWQ6PFwvc3Bhbj48XC9wPjx1bD48bGkgc3R5bGU9XCJmb250LXdlaWdodDogNDAwO1wiIGFyaWEtbGV2ZWw9XCIxXCI+PHNwYW4gc3R5bGU9XCJmb250LXdlaWdodDogNDAwO1wiPkRvY3VtZW50cyB3ZXJlIGluZGV4ZWQgdmlhIDxhIGhyZWY9XCJodHRwczpcL1wvZ2l0aHViLmNvbVwva213dGVjaG5vbG9neVwvbHVjaWxsZVwiPkx1Y2lsbGU8XC9hPiwgYW4gb3Blbi1zb3VyY2UgSmF2YSBmcmFtZXdvcmsgZm9yIEVUTCBwaXBlbGluZXMgY3JlYXRlZCBieSBLTVcgVGVjaG5vbG9neTsgTHVjaWxsZSBzdXBwb3J0cyBhIGJlbmNobWFya2luZyB3b3JrZmxvdyB3aXRoIHJhbmRvbWlzZWQgZG9jdW1lbnQgY3JlYXRpb248XC9zcGFuPjxcL2xpPjxsaSBzdHlsZT1cImZvbnQtd2VpZ2h0OiA0MDA7XCIgYXJpYS1sZXZlbD1cIjFcIj48c3BhbiBzdHlsZT1cImZvbnQtd2VpZ2h0OiA0MDA7XCI+MSBpbmRleCB3YXMgY3JlYXRlZCBwZXIgaW1wbGVtZW50YXRpb24sIGVhY2ggd2l0aGluIHRoZWlyIG93biBpbnN0YW5jZSBvZiBPUzxcL3NwYW4+PFwvbGk+PGxpIHN0eWxlPVwiZm9udC13ZWlnaHQ6IDQwMDtcIiBhcmlhLWxldmVsPVwiMVwiPjxzcGFuIHN0eWxlPVwiZm9udC13ZWlnaHQ6IDQwMDtcIj4xMDBrIGRvY3VtZW50cyB3ZXJlIGluZGV4ZWQgaW50byBlYWNoIGluZGV4PFwvc3Bhbj48XC9saT48bGkgc3R5bGU9XCJmb250LXdlaWdodDogNDAwO1wiIGFyaWEtbGV2ZWw9XCIxXCI+PHNwYW4gc3R5bGU9XCJmb250LXdlaWdodDogNDAwO1wiPkVhY2ggZG9jdW1lbnQgYXZlcmFnZWQgYXQgMTAwMCB2YWx1ZXMgaW4gaXRzIGZpZWxkLCB3aXRoIHRoZSByYW5nZSBzcGFubmluZyBmcm9tIDc1MCB0byAxMjUwPFwvc3Bhbj48XC9saT48bGkgc3R5bGU9XCJmb250LXdlaWdodDogNDAwO1wiIGFyaWEtbGV2ZWw9XCIxXCI+PHNwYW4gc3R5bGU9XCJmb250LXdlaWdodDogNDAwO1wiPkFsbCBxdWVyaWVzIGhhZCByYW5kb20gYm9vbGVhbiBtYXRjaCBmaWx0ZXJzIGFsb25nc2lkZSB0aGUgYWdncmVnYXRpb25zIHNvIGFzIHRvIHByZXZlbnQgdGhlIGltcGFjdCBvZiBjYWNoZXM8XC9zcGFuPjx1bD48bGkgc3R5bGU9XCJmb250LXdlaWdodDogNDAwO1wiIGFyaWEtbGV2ZWw9XCIyXCI+PHNwYW4gc3R5bGU9XCJmb250LXdlaWdodDogNDAwO1wiPlRoZSB1bmRlcnNjb3JlIHJlcHJlc2VudGF0aW9uIHF1ZXJpZXMgdXNlZCBhIFx1MjAxY3ByZWZpeFx1MjAxZCBtYXRjaCBzZWVpbmcgdGhhdCB0aGVpciB2YWx1ZXMgaGFkIGFuIGFkZGl0aW9uYWwgZGVsaW1pdGVyIGFuZCBjb3VudCBhdHRhY2hlZDxcL3NwYW4+PFwvbGk+PGxpIHN0eWxlPVwiZm9udC13ZWlnaHQ6IDQwMDtcIiBhcmlhLWxldmVsPVwiMlwiPjxzcGFuIHN0eWxlPVwiZm9udC13ZWlnaHQ6IDQwMDtcIj5UaGlzIFx1MjAxY3ByZWZpeFx1MjAxZCBhbmFseXNpcyBtYXkgcG90ZW50aWFsbHkgaGF2ZSBoYWQgcmFtaWZpY2F0aW9ucyBmb3IgcXVlcnkgcGVyZm9ybWFuY2UgZm9yIHRoZSB1bmRlcnNjb3JlIGltcGxlbWVudGF0aW9uPFwvc3Bhbj48XC9saT48XC91bD48XC9saT48bGkgc3R5bGU9XCJmb250LXdlaWdodDogNDAwO1wiIGFyaWEtbGV2ZWw9XCIxXCI+PHNwYW4gc3R5bGU9XCJmb250LXdlaWdodDogNDAwO1wiPjUwIHVzZXJzIHNlbnQgcXVlcmllcyBzaW11bHRhbmVvdXNseSB3aXRoIGEgMSBzZWNvbmQgcmFtcC11cCB0aW1lPFwvc3Bhbj48XC9saT48XC91bD4ifSwiZWxlbWVudHMiOltdLCJ3aWRnZXRUeXBlIjoidGV4dC1lZGl0b3IifQ==\\\"][elementor-element k=\\\"9109a976d8649ee6d2c8fef8daebbb8b\\\" data=\\\"eyJpZCI6ImMyNjEzMWMiLCJlbFR5cGUiOiJ3aWRnZXQiLCJzZXR0aW5ncyI6eyJlZGl0b3IiOiI8cD48IS0tIHdwOnRhYmxlIHtcImhhc0ZpeGVkTGF5b3V0XCI6dHJ1ZSxcImNsYXNzTmFtZVwiOlwiaXMtc3R5bGUtcmVndWxhclwifSAtLT48XC9wPjxmaWd1cmUgY2xhc3M9XCJ3cC1ibG9jay10YWJsZSBpcy1zdHlsZS1yZWd1bGFyXCI+PHRhYmxlIGNsYXNzPVwiaGFzLWZpeGVkLWxheW91dFwiPjx0Ym9keT48dHI+PHRkPlx1MDBhMDxcL3RkPjx0ZD48c3Ryb25nPlNjcmlwdGVkIEltcC48XC9zdHJvbmc+PFwvdGQ+PHRkPjxzdHJvbmc+VW5kZXJzY29yZSBJbXAuPFwvc3Ryb25nPjxcL3RkPjx0ZD48c3Ryb25nPk5lc3RlZCBJbXAuPFwvc3Ryb25nPjxcL3RkPjxcL3RyPjx0cj48dGQ+IyBvZiBzYW1wbGVzPFwvdGQ+PHRkPjUwPFwvdGQ+PHRkPjUwPFwvdGQ+PHRkPjUwPFwvdGQ+PFwvdHI+PHRyPjx0ZD5BdmVyYWdlIExhdGVuY3kgKG1zKTxcL3RkPjx0ZD4xMDM5MDcgbXM8XC90ZD48dGQ+MzQ1MDUgbXM8XC90ZD48dGQ+MTE4NzcgbXM8XC90ZD48XC90cj48dHI+PHRkPk1pbiBMYXRlbmN5IChtcyk8XC90ZD48dGQ+MCBtczxcL3RkPjx0ZD4wIG1zPFwvdGQ+PHRkPjAgbXM8XC90ZD48XC90cj48dHI+PHRkPk1heCBMYXRlbmN5IChtcyk8XC90ZD48dGQ+MTQ3NDUxIG1zPFwvdGQ+PHRkPjQxNjIzIG1zPFwvdGQ+PHRkPjE2MjAzIG1zPFwvdGQ+PFwvdHI+PHRyPjx0ZD5TdGQuIERldjxcL3RkPjx0ZD4zOTUyMi4wNTxcL3RkPjx0ZD43ODIzLjUxPFwvdGQ+PHRkPjI3NjEuNzE8XC90ZD48XC90cj48dHI+PHRkPkVycm9yICU8XC90ZD48dGQ+MCU8XC90ZD48dGQ+MCU8XC90ZD48dGQ+MCU8XC90ZD48XC90cj48dHI+PHRkPlRocm91Z2hwdXQgKHJlcXVlc3RzIHBlciBzZWNvbmQpPFwvdGQ+PHRkPjAlPFwvdGQ+PHRkPjAlPFwvdGQ+PHRkPjAlPFwvdGQ+PFwvdHI+PFwvdGJvZHk+PFwvdGFibGU+PFwvZmlndXJlPiJ9LCJlbGVtZW50cyI6W10sIndpZGdldFR5cGUiOiJ0ZXh0LWVkaXRvciJ9\\\"][elementor-element k=\\\"9109a976d8649ee6d2c8fef8daebbb8b\\\" data=\\\"eyJpZCI6ImZjZjlmYzIiLCJlbFR5cGUiOiJ3aWRnZXQiLCJzZXR0aW5ncyI6eyJlZGl0b3IiOiI8cD48c3BhbiBzdHlsZT1cImZvbnQtd2VpZ2h0OiA0MDA7XCI+VGhlIHNjcmlwdGVkIGltcGxlbWVudGF0aW9uIHNhdyB0aGUgbG9uZ2VzdCBhdmVyYWdlIHF1ZXJ5IHRpbWUgYXQgYXJvdW5kIDEwNCBzZWNvbmRzLiBUaGUgdW5kZXJzY29yZSBpbXBsZW1lbnRhdGlvbiBzYXQgaW4gdGhlIG1pZGRsZSB3aXRoIGFuIGF2ZXJhZ2UgcXVlcnkgdGltZSBvZiBhcm91bmQgMzUgc2Vjb25kcy48XC9zcGFuPjxzcGFuIHN0eWxlPVwiZm9udC13ZWlnaHQ6IDQwMDtcIj5UaGUgbmVzdGVkIGltcGxlbWVudGF0aW9uIHdhcyB0aGUgZmFzdGVzdCB3aXRoIGFuIGF2ZXJhZ2UgcXVlcnkgdGltZSBvZiBhcm91bmQgMTIgc2Vjb25kcy48XC9zcGFuPjxcL3A+PHA+PHNwYW4gc3R5bGU9XCJmb250LXdlaWdodDogNDAwO1wiPldpdGggdGhpcyBpbmZvcm1hdGlvbiwgaXQgbWF5IHNlZW0gY2xlYXIgdGhhdCB0aGUgbmVzdGVkIGFwcHJvYWNoIGlzIHRoZSBiZXN0IGFwcHJvYWNoIGZvciBoYW5kbGluZyBkdXBsaWNhdGUgdGVybXMgYWdncmVnYXRpb25zIGluIE9wZW5TZWFyY2guIEhvd2V2ZXIsIHRha2luZyBhIGNsb3NlciBsb29rIGF0IG91ciBwcm9wb3NlZCBndWlkZWxpbmVzLCB3ZSBub3RpY2UgdGhhdCB3ZVx1MjAxOXZlIHlldCB0byBldmFsdWF0ZSBpbmRleCBzaXplLiBMb29raW5nIGF0IGluZGV4IHNpemUgYmVuY2htYXJrcyBmb3IgYm90aCB0aGUgbmVzdGVkIGFuZCB1bmRlcnNjb3JlIGltcGxlbWVudGF0aW9ucywgd2Ugc2VlIGEgcG90ZW50aWFsbHkgbmV3IGNvbmNsdXNpb24uIFRoZSBuZXN0ZWQgZG9jdW1lbnQgaW5kZXggaG9sZHMgYSBsYXJnZSAxLjQgR0IgaW5kZXggc2l6ZS4gTWVhbndoaWxlLCB0aGUgdW5kZXJzY29yZSBpbmRleCBib2FzdHMgYSBzaWduaWZpY2FudGx5IHNtYWxsZXIgMTg3IE1CIGluZGV4IHNpemUuIFRoaXMgdHJhbnNsYXRlcyB0byBhIDxlbT43LjV4IHNtYWxsZXIgaW5kZXg8XC9lbT4gc2l6ZSBmb3IgdGhlIHVuZGVyc2NvcmUgaW1wbGVtZW50YXRpb24sIHdpdGggYSAyLjl4IHNsb3dlciBhdmVyYWdlIHF1ZXJ5IHRpbWUuXHUwMGEwPFwvc3Bhbj48XC9wPjxwPjxzcGFuIHN0eWxlPVwiZm9udC13ZWlnaHQ6IDQwMDtcIj5XaGlsZSB3ZSBkaWRuXHUyMDE5dCBleHBsaWNpdGx5IHdlaWdoIGVhY2ggZ3VpZGVsaW5lXHUyMDE5cyBpbXBvcnRhbmNlLCBpdCB3YXMgY2xlYXIgdG8gdXMgdGhhdCBhIHNpZ25pZmljYW50bHkgbGFyZ2VyIGluZGV4IHdvdWxkIHByZXNlbnQgbW9yZSBwcm9ibGVtcyB0aGFuIHRoZSBxdWVyeSB0aW1lIHBlcmZvcm1hbmNlIGhpdCwgZXNwZWNpYWxseSB3aXRoIHRoZSBtYWduaXR1ZGVzIG1lbnRpb25lZCBiZWZvcmUuIFRoaXMgbGVkIHVzIHRvIGJlbGlldmUgdGhhdCB0aGUgdW5kZXJzY29yZSBpbXBsZW1lbnRhdGlvbiB3YXMgdGhlIGJlc3QgZml0IGZvciBvdXIgbmVlZHMgYW5kIHRoZSBndWlkZWxpbmVzIHRoYXQgd2Ugc2V0IGZvcnRoLiBJZiBpbmRleCBzaXplIGlzIG5vdCBhIGNvbnNpZGVyYXRpb24gZm9yIHVzZXJzLCB0aGVuIHRoZSBuZXN0ZWQgYXBwcm9hY2ggd291bGQgYmUgdGhlIGJlc3QsIHNlZWluZyB0aGF0IGl0IG9mZmVycyBleHRyZW1lbHkgZmFzdCBsb29rdXAgXC8gcXVlcnkgdGltZXMuPFwvc3Bhbj48XC9wPiJ9LCJlbGVtZW50cyI6W10sIndpZGdldFR5cGUiOiJ0ZXh0LWVkaXRvciJ9\\\"]\\t\\t<div class=\\\"elementor-element elementor-element-7dc0602 flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-spacer\\\" data-id=\\\"7dc0602\\\" data-element_type=\\\"widget\\\" data-e-type=\\\"widget\\\" data-widget_type=\\\"spacer.default\\\">\\n\\t\\t\\t\\t<div class=\\\"elementor-widget-container\\\">\\n\\t\\t\\t\\t\\t\\t\\t<div class=\\\"elementor-spacer\\\">\\n\\t\\t\\t<div class=\\\"elementor-spacer-inner\\\"><\\\/div>\\n\\t\\t<\\\/div>\\n\\t\\t\\t\\t\\t\\t<\\\/div>\\n\\t\\t\\t\\t<\\\/div>\\n\\t\\t\\t\\t<div class=\\\"elementor-element elementor-element-0070c1d flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-heading\\\" data-id=\\\"0070c1d\\\" data-element_type=\\\"widget\\\" data-e-type=\\\"widget\\\" data-widget_type=\\\"heading.default\\\">\\n\\t\\t\\t\\t<div class=\\\"elementor-widget-container\\\">\\n\\t\\t\\t\\t\\t<h2 class=\\\"elementor-heading-title elementor-size-large\\\">The Plug-in<\\\/h2>\\t\\t\\t\\t<\\\/div>\\n\\t\\t\\t\\t<\\\/div>\\n\\t\\t[elementor-element k=\\\"9109a976d8649ee6d2c8fef8daebbb8b\\\" data=\\\"eyJpZCI6IjhhYTc5NGEiLCJlbFR5cGUiOiJ3aWRnZXQiLCJzZXR0aW5ncyI6eyJlZGl0b3IiOiI8cD48c3BhbiBzdHlsZT1cImZvbnQtd2VpZ2h0OiA0MDA7XCI+SXQgbm93IG1ha2VzIHNlbnNlIHRvIHBhY2thZ2UgdGhpcyBzb2x1dGlvbiBpbnRvIGEgcGx1Zy1pbi4gV2hpbGUgT3BlblNlYXJjaCBkb2VzIG9mZmVyIGFuIGVhc3ktdG8tdXNlIDxcL3NwYW4+PGEgaHJlZj1cImh0dHBzOlwvXC9naXRodWIuY29tXC9vcGVuc2VhcmNoLXByb2plY3RcL29wZW5zZWFyY2gtcGx1Z2luLXRlbXBsYXRlLWphdmFcIj48c3BhbiBzdHlsZT1cImZvbnQtd2VpZ2h0OiA0MDA7XCI+dGVtcGxhdGU8XC9zcGFuPjxcL2E+PHNwYW4gc3R5bGU9XCJmb250LXdlaWdodDogNDAwO1wiPiBmb3IgZGV2ZWxvcGVycyB0byBnZXQgc3RhcnRlZCB3aXRoIHBsdWctaW4gZGV2ZWxvcG1lbnQsIHRoZSBjb252ZW5pZW5jZSBzdG9wcyBzaG9ydGx5IHRoZXJlYWZ0ZXIuIFdlIGVuY291bnRlcmVkIHNvbWUgcHJvYmxlbXMgd2hpbGUgZGV2ZWxvcGluZyB0aGUgcGx1Zy1pbi48XC9zcGFuPjxcL3A+In0sImVsZW1lbnRzIjpbXSwid2lkZ2V0VHlwZSI6InRleHQtZWRpdG9yIn0=\\\"]\\t\\t<div class=\\\"elementor-element elementor-element-eae5bdc flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-heading\\\" data-id=\\\"eae5bdc\\\" data-element_type=\\\"widget\\\" data-e-type=\\\"widget\\\" data-widget_type=\\\"heading.default\\\">\\n\\t\\t\\t\\t<div class=\\\"elementor-widget-container\\\">\\n\\t\\t\\t\\t\\t<h3 class=\\\"elementor-heading-title elementor-size-medium\\\">Difficulties in Plug-in Creation <\\\/h3>\\t\\t\\t\\t<\\\/div>\\n\\t\\t\\t\\t<\\\/div>\\n\\t\\t[elementor-element k=\\\"9109a976d8649ee6d2c8fef8daebbb8b\\\" data=\\\"eyJpZCI6IjE3OTZjMjAiLCJlbFR5cGUiOiJ3aWRnZXQiLCJzZXR0aW5ncyI6eyJlZGl0b3IiOiI8cD48c3BhbiBzdHlsZT1cImZvbnQtd2VpZ2h0OiA0MDA7XCI+VGhlIG1vc3QgY2hhbGxlbmdpbmcgaXNzdWUgaW4gcGx1Zy1pbiBkZXZlbG9wbWVudCB3aXRoIE9wZW5TZWFyY2ggaGFzIHRvIGRvIHdpdGggSmF2YSBjbGFzcyBsb2FkZXJzLiBXaGVuIGluc3RhbGxpbmcgYSBwbHVnLWluIGludG8gYW4gT3BlblNlYXJjaCBkaXN0cmlidXRpb24sIE9wZW5TZWFyY2ggdXNlcyBhIHBhcmVudCBjbGFzcyBsb2FkZXIgdG8gbG9hZCBpbiBPcGVuU2VhcmNoIHJlbGF0ZWQgZmlsZXMgYW5kIGEgY2hpbGQgY2xhc3MgbG9hZGVyIHRvIGxvYWQgaW4gb3VyIHBsdWctaW4gZmlsZXMuIE9wZW5TZWFyY2ggZmlsZXMgYXJlIGxhcmdlbHkgcGFja2FnZS1wcml2YXRlLCBwcmV2ZW50aW5nIHRoZSBjaGlsZCBjbGFzcyBsb2FkZXIgZnJvbSBoYXZpbmcgYWNjZXNzIHRvIHRoZWlyIG1ldGhvZHMsIGNvbnN0cnVjdG9ycywgZXRjLiBUaGlzIGNhdXNlcyBsYXJnZSBhbW91bnRzIG9mIGNvZGUgZHVwbGljYXRpb24gYW5kIHJlcXVpcmVzIGEgZGVlcCB1bmRlcnN0YW5kaW5nIG9mIHRoZSBpbm5lciB3b3JraW5ncyBvZiBPcGVuU2VhcmNoIGFnZ3JlZ2F0aW9ucy4gSGVyZSBpcyBhIGxpbmsgdG8gYSBjb2RlIGV4YW1wbGUgdGhhdCBpbGx1c3RyYXRlcyB0aGUgaXNzdWVzIHdlIGVuY291bnRlcmVkIHdpdGggY2xhc3MgbG9hZGVyczogPFwvc3Bhbj48YSBocmVmPVwiaHR0cHM6XC9cL2dpc3QuZ2l0aHViLmNvbVwvcnNlaXR6XC81OWJmZjU2OTM2NzU2ZmYyOWIyZTE1MWUyODU3YWEzN1wiPjxzcGFuIHN0eWxlPVwiZm9udC13ZWlnaHQ6IDQwMDtcIj5saW5rPFwvc3Bhbj48XC9hPjxzcGFuIHN0eWxlPVwiZm9udC13ZWlnaHQ6IDQwMDtcIj4uPFwvc3Bhbj48XC9wPjxwPjxzcGFuIHN0eWxlPVwiZm9udC13ZWlnaHQ6IDQwMDtcIj5Bbm90aGVyIGlzc3VlIGZhY2VkIHdhcyBhIGxhY2sgb2YgY2xlYXIgdGVzdGluZyBwcm90b2NvbCBmb3IgcGx1Zy1pbnMuIFRlc3RzIHNpdHVhdGVkIHdpdGhpbiB0aGUgT3BlblNlYXJjaCBjb3JlIGNvZGViYXNlLCBzcGVjaWZpY2FsbHkgYWdncmVnYXRpb24gdGVzdHMsIHJlbGllZCBoZWF2aWx5IG9uIGhlbHBlciBjbGFzc2VzIGFuZCBtZXRob2RzIGZvdW5kIHdpdGhpbiB0aGUgY29yZSBjb2RlYmFzZS4gT3VyIHBsdWctaW4gY29kZSwgZHVlIHRvIHRoZSBhZm9yZW1lbnRpb25lZCBjbGFzcyBsb2FkZXIgaXNzdWUsIGRpZCBub3QgaGF2ZSBhY2Nlc3MgdG8gdGhlc2UgYXNzaXN0aW5nIGNsYXNzZXMuIFRoaXMgbWFkZSBpdCBleHRyZW1lbHkgZGlmZmljdWx0IHRvIHdyaXRlIHVuaXQgdGVzdHMsIGxlYXZpbmcgdXMgb25seSB3aXRoIGludGVncmF0aW9uIHRlc3RzLjxcL3NwYW4+PFwvcD4ifSwiZWxlbWVudHMiOltdLCJ3aWRnZXRUeXBlIjoidGV4dC1lZGl0b3IifQ==\\\"]\\t\\t<div class=\\\"elementor-element elementor-element-f49451e flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-heading\\\" data-id=\\\"f49451e\\\" data-element_type=\\\"widget\\\" data-e-type=\\\"widget\\\" data-widget_type=\\\"heading.default\\\">\\n\\t\\t\\t\\t<div class=\\\"elementor-widget-container\\\">\\n\\t\\t\\t\\t\\t<h3 class=\\\"elementor-heading-title elementor-size-medium\\\">Future Points of Interest<\\\/h3>\\t\\t\\t\\t<\\\/div>\\n\\t\\t\\t\\t<\\\/div>\\n\\t\\t[elementor-element k=\\\"9109a976d8649ee6d2c8fef8daebbb8b\\\" data=\\\"eyJpZCI6IjIwNjczYzIiLCJlbFR5cGUiOiJ3aWRnZXQiLCJzZXR0aW5ncyI6eyJlZGl0b3IiOiI8cD48c3BhbiBzdHlsZT1cImZvbnQtd2VpZ2h0OiA0MDA7XCI+VG8gc2F5IHRoYXQgb3VyIGludmVzdGlnYXRpb24gZXhoYXVzdGVkIGFsbCBhdmVudWVzIGZvciBob3cgdG8gcGVyZm9ybSBhIGR1cGxpY2F0ZSB0ZXJtcyBhZ2dyZWdhdGlvbiB3b3VsZCBiZSBuYWl2ZS4gQSBmZXcgaWRlYXMgd2VyZSBicmFpbnN0b3JtZWQgKGFuZCBldmVuIHRlc3RlZCksIGJ1dCBkaWRuXHUyMDE5dCBzZWVtIHByb21pc2luZyBvciBkaWQgbm90IGZpdCBvdXIgb3JpZ2luYWwgZ3VpZGVsaW5lcy4gSGVyZSBhcmUgYSBmZXc6PFwvc3Bhbj48c3BhbiBzdHlsZT1cImZvbnQtd2VpZ2h0OiA0MDA7XCI+PGJyIFwvPjxcL3NwYW4+PFwvcD48cD48c3BhbiBzdHlsZT1cImZvbnQtd2VpZ2h0OiA0MDA7XCI+T3VyIHBsdWctaW4gaW1wbGVtZW50YXRpb24gbGV2ZXJhZ2VkIHRoZSBTb3J0ZWRCaW5hcnlEb2NWYWx1ZXMsIHRoZSBwcmltYXJ5IGRvYyB2YWx1ZXMgZGF0YSB0eXBlIGZvciBrZXl3b3JkIGZpZWxkIHR5cGVzLiBJZiB3ZSB3ZXJlIG9wZW4gdG8gY2hhbmdpbmcgdGhlIGZpZWxkIHR5cGUgb2Ygb3VyIGRhdGEsIHdlIGNvdWxkIGhhdmUgZXhwZXJpbWVudGVkIHdpdGggdGhlIFNvcnRlZE9yZGVyZWROdW1lcmljRG9jVmFsdWVzIHdoaWNoIHN0b3JlcyBkdXBsaWNhdGVzIGZvciB0aGUgbnVtZXJpYyBmaWVsZCB0eXBlLiBUaGlzIHR5cGUgaXMgdGhlIG9ubHkgZG9jIHZhbHVlcyBmaWVsZCB0eXBlIGluIEx1Y2VuZSB0aGF0IHJldGFpbnMgZHVwbGljYXRlcy4gSG93ZXZlciwgdGhlIGlzc3VlIHdvdWxkIGFyaXNlIGZvciBhIG5lZWQgdG8gY29udmVydCBmcm9tIG51bWVyaWMgdHlwZSB0byBzdHJpbmcgYXQgcXVlcnkgdGltZSwgbGVhZGluZyB0byBkZWZpbml0ZSBwZXJmb3JtYW5jZSBsb3NzLlx1MDBhMDxcL3NwYW4+PFwvcD48cD48c3BhbiBzdHlsZT1cImZvbnQtd2VpZ2h0OiA0MDA7XCI+QW5vdGhlciBwb3RlbnRpYWwgc29sdXRpb24gd291bGQgYmUgdG8gdXRpbGlzZSBMdWNlbmUgcGF5bG9hZHMuIFBheWxvYWRzIGFyZSBtZXRhZGF0YSB0aGF0IGNhbiBiZSBzdG9yZWQgd2l0aCB0ZXJtcyBhbmQgYWNjZXNzZWQgdmlhIEx1Y2VuZS4gVGhlIGNvbmNlcm4gcmVnYXJkaW5nIHRoaXMgc29sdXRpb24gd2FzIHRoYXQgcGF5bG9hZHMgd291bGQgbGlrZWx5IG5vdCBiZSBhY2Nlc3NpYmxlIHZpYSBkb2NfdmFsdWVzLCBsZWF2aW5nIHRoZW0gYXMgYSBsaWtlbHkgc2xvd2VyIGFsdGVybmF0aXZlLjxcL3NwYW4+PFwvcD48cD48c3BhbiBzdHlsZT1cImZvbnQtd2VpZ2h0OiA0MDA7XCI+T25lIHNvbHV0aW9uIHRoYXQgd2FzIGV4cGxvcmVkIHRob3JvdWdobHkgd2FzIHRlcm0gdmVjdG9ycy4gVGVybSB2ZWN0b3JzIHdvcmsgYnkgb2ZmZXJpbmcgc3RhdGlzdGljcyBmb3IgYWxsIHRoZSB0ZXJtcyBpbiB0aGUgZmllbGRzIG9mIGEgc3BlY2lmaWMgZG9jdW1lbnQsIHByb3ZpZGVkIGJ5IHRoZSB1c2VyLiBUaGlzIGFscmVhZHkgcmFpc2VkIGEgZmV3IGNvbmNlcm5zLCBlc3BlY2lhbGx5IHNpbmNlIHdlIHdvdWxkIHJlcXVpcmUgYW4gYXJ0aWZpY2lhbCBcdTIwMWNtYXN0ZXJcdTIwMWQgZG9jdW1lbnQgdGhhdCBjb250YWluZWQgYWxsIHBvc3NpYmxlIHRlcm1zIGFuZCBmaWVsZHMgc28gdGhhdCBpdHMgXHUyMDE4aWRcdTIwMTkgY291bGQgYmUgcHJvdmlkZWQuIElmIHVzaW5nIHRoaXMgYXJ0aWZpY2lhbCBkb2N1bWVudCBhcHByb2FjaCwgdGVybSB2ZWN0b3JzIHdvdWxkIGdhdGhlciBzdGF0aXN0aWNzIGZyb20gYSByYW5kb21seSBzZWxlY3RlZCBzaGFyZC4gVGhlIHVzZXIgbXVzdCB0aGVuIGNob29zZSB0byB1c2Ugb25seSBhIHNpbmdsZS1zaGFyZCBpbnN0YW5jZSBvciB0b3RhbCB0aGUgY291bnRzIGFjcm9zcyBhbGwgc2hhcmRzIGFuZCBjcmVhdGUgXHUyMDFjbWFzdGVyXHUyMDFkIGRvY3VtZW50cyB3aXRoaW4gZWFjaCBzaGFyZC4gRGVzcGl0ZSB0aGlzLCB3ZSBjcmVhdGVkIGNvZGUgYWdhaW5zdCBMdWNlbmUgaXRzZWxmIGNvbXBhcmluZyBkb2MgdmFsdWVzIHRvIHRlcm0gdmVjdG9ycy4gRm9yIDEwIG1pbGxpb24gZG9jdW1lbnRzLCB0ZXJtIHZlY3RvcnMgc2VlbWVkIHRvIGJlIGF2ZXJhZ2luZyA1MCBzZWNvbmRzIHNsb3dlciB0aGFuIGRvYyB2YWx1ZXMuXHUwMGEwPFwvc3Bhbj48XC9wPiJ9LCJlbGVtZW50cyI6W10sIndpZGdldFR5cGUiOiJ0ZXh0LWVkaXRvciJ9\\\"]\\t\\t<div class=\\\"elementor-element elementor-element-c9a6ce9 flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-heading\\\" data-id=\\\"c9a6ce9\\\" data-element_type=\\\"widget\\\" data-e-type=\\\"widget\\\" data-widget_type=\\\"heading.default\\\">\\n\\t\\t\\t\\t<div class=\\\"elementor-widget-container\\\">\\n\\t\\t\\t\\t\\t<h2 class=\\\"elementor-heading-title elementor-size-large\\\">Conclusion<\\\/h2>\\t\\t\\t\\t<\\\/div>\\n\\t\\t\\t\\t<\\\/div>\\n\\t\\t[elementor-element k=\\\"9109a976d8649ee6d2c8fef8daebbb8b\\\" data=\\\"eyJpZCI6ImU5NGJiYWIiLCJlbFR5cGUiOiJ3aWRnZXQiLCJzZXR0aW5ncyI6eyJlZGl0b3IiOiI8cD48c3BhbiBzdHlsZT1cImZvbnQtd2VpZ2h0OiA0MDA7XCI+T3ZlcmFsbCwgd2UgYmVsaWV2ZSBvdXIgaW52ZXN0aWdhdGlvbiB0byBiZSBhIHRob3JvdWdoIGFuYWx5c2lzIG9mIHRoZSBleGlzdGluZyBwb3NzaWJsZSB0b29scyB0byBwZXJmb3JtIGEgZHVwbGljYXRlIHRlcm1zIGFnZ3JlZ2F0aW9uLiBUaGUgcGx1Zy1pbiB3ZVx1MjAxOXZlIGNyZWF0ZWQgc2VlbXMgbGlrZWx5IHRvIGJlIHRoZSBiZXN0IHNvbHV0aW9uIGZvciBkdXBsaWNhdGUgdGVybXMgYWdncmVnYXRpb24gZGVwZW5kaW5nIG9uIHRoZSBpbmRpdmlkdWFsIGNvbnRleHQgYW5kIHVzZS1jYXNlLlx1MDBhMDxcL3NwYW4+PFwvcD48cD48c3BhbiBzdHlsZT1cImZvbnQtd2VpZ2h0OiA0MDA7XCI+V2l0aCB0aGlzIHNvbHV0aW9uIHVuZGVyIG91ciBiZWx0LCB3ZSBjYW4gbm93IG1ha2Ugb3VyIHNob3BwaW5nIGxpc3QgYW5kIG1ha2Ugb3VyIGdyZWF0LWdyYW5kbW90aGVyIHByb3VkIVx1MDBhMDxcL3NwYW4+PFwvcD4ifSwiZWxlbWVudHMiOltdLCJ3aWRnZXRUeXBlIjoidGV4dC1lZGl0b3IifQ==\\\"]\\t\\t\\t<\\\/div>\\n\\t\\t<\\\/div>\\n\\t\\t\\t\\t<div class=\\\"elementor-column elementor-col-33 elementor-top-column elementor-element elementor-element-7295c69\\\" data-id=\\\"7295c69\\\" data-element_type=\\\"column\\\" data-e-type=\\\"column\\\">\\n\\t\\t\\t<div class=\\\"elementor-widget-wrap\\\">\\n\\t\\t\\t\\t\\t\\t\\t<\\\/div>\\n\\t\\t<\\\/div>\\n\\t\\t\\t\\t<div class=\\\"elementor-column elementor-col-33 elementor-top-column elementor-element elementor-element-1f8e61f\\\" data-id=\\\"1f8e61f\\\" data-element_type=\\\"column\\\" data-e-type=\\\"column\\\">\\n\\t\\t\\t<div class=\\\"elementor-widget-wrap elementor-element-populated\\\">\\n\\t\\t\\t\\t\\t\\t<div class=\\\"elementor-element elementor-element-b2890c3 flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-heading\\\" data-id=\\\"b2890c3\\\" data-element_type=\\\"widget\\\" data-e-type=\\\"widget\\\" data-widget_type=\\\"heading.default\\\">\\n\\t\\t\\t\\t<div class=\\\"elementor-widget-container\\\">\\n\\t\\t\\t\\t\\t<div class=\\\"title-h6 elementor-heading-title elementor-size-small\\\">Share Post<\\\/div>\\t\\t\\t\\t<\\\/div>\\n\\t\\t\\t\\t<\\\/div>\\n\\t\\t[elementor-element k=\\\"9109a976d8649ee6d2c8fef8daebbb8b\\\" data=\\\"eyJpZCI6IjVmZTdkNDMiLCJlbFR5cGUiOiJ3aWRnZXQiLCJzZXR0aW5ncyI6eyJwaW50ZXJlc3QiOiIiLCJ0dW1ibHIiOiIiLCJ0ZWxlZ3JhbSI6IiIsIndoYXRzYXBwIjoiIiwidmliZXIiOiIiLCJ4aW5nIjoiIiwiaWNvbnNfY29sb3IiOiIjMDBERUZGIn0sImVsZW1lbnRzIjpbXSwid2lkZ2V0VHlwZSI6InRoZWdlbS1zb2NpYWwtc2hhcmluZyJ9\\\"]\\t\\t<div class=\\\"elementor-element elementor-element-0a5e46b flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-heading\\\" data-id=\\\"0a5e46b\\\" data-element_type=\\\"widget\\\" data-e-type=\\\"widget\\\" data-widget_type=\\\"heading.default\\\">\\n\\t\\t\\t\\t<div class=\\\"elementor-widget-container\\\">\\n\\t\\t\\t\\t\\t<div class=\\\"title-h6 elementor-heading-title elementor-size-small\\\">More From the KMW Blog<\\\/div>\\t\\t\\t\\t<\\\/div>\\n\\t\\t\\t\\t<\\\/div>\\n\\t\\t[elementor-element k=\\\"9109a976d8649ee6d2c8fef8daebbb8b\\\" data=\\\"eyJpZCI6ImExY2JhNzQiLCJlbFR5cGUiOiJ3aWRnZXQiLCJzZXR0aW5ncyI6eyJ0aGVnZW1fZWxlbWVudG9yX3ByZXNldCI6ImNvbXBhY3QtdGlueS0yIiwic291cmNlIjpbInBvc3RzIl0sInNob3dfc2VwYXJhdG9yIjoiIiwic2hvd19jb21tZW50cyI6IiIsInJlYWRtb3JlX2J1dHRvbl90ZXh0IjoiUmVhZCBNb3JlIiwibG9hZG1vcmVfYnV0dG9uX3RleHQiOiJMb2FkIE1vcmUiLCJjYXB0aW9uX2NhdGVnb3JpZXNfaW5fdGV4dCI6ImluICIsImNhcHRpb25fYXV0aG9yX2J5X3RleHQiOiJCeSIsInNvdXJjZV90eXBlIjoiY3VzdG9tIiwiZXhjbHVkZV9ibG9nX3Bvc3RzX3R5cGUiOiJjdXJyZW50IiwicGFnaW5hdGlvbl90eXBlIjoibnVtYmVycyJ9LCJlbGVtZW50cyI6W10sIndpZGdldFR5cGUiOiJ0aGVnZW0tYmxvZ2xpc3QifQ==\\\"]\\t\\t\\t<\\\/div>\\n\\t\\t<\\\/div>\\n\\t\\t\\t\\t\\t<\\\/div><\\\/div>\\r\\n\\t\\t<\\\/section>\\r\\n\\t\\t\\t\\t<section class=\\\"elementor-section elementor-top-section elementor-element elementor-element-87fbea3 elementor-section-boxed elementor-section-height-default elementor-section-height-default\\\" data-id=\\\"87fbea3\\\" data-element_type=\\\"section\\\" data-e-type=\\\"section\\\">\\r\\n\\t\\t\\t\\t\\t\\t<div class=\\\"elementor-container elementor-column-gap-thegem\\\"><div class=\\\"elementor-row\\\">\\r\\n\\t\\t\\t\\t\\t<div class=\\\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-c32d4f1\\\" data-id=\\\"c32d4f1\\\" data-element_type=\\\"column\\\" data-e-type=\\\"column\\\">\\n\\t\\t\\t<div class=\\\"elementor-widget-wrap elementor-element-populated\\\">\\n\\t\\t\\t\\t\\t\\t<div class=\\\"elementor-element elementor-element-aecd2e9 flex-horizontal-align-default flex-horizontal-align-tablet-default flex-horizontal-align-mobile-default flex-vertical-align-default flex-vertical-align-tablet-default flex-vertical-align-mobile-default elementor-widget elementor-widget-spacer\\\" data-id=\\\"aecd2e9\\\" data-element_type=\\\"widget\\\" data-e-type=\\\"widget\\\" data-widget_type=\\\"spacer.default\\\">\\n\\t\\t\\t\\t<div class=\\\"elementor-widget-container\\\">\\n\\t\\t\\t\\t\\t\\t\\t<div class=\\\"elementor-spacer\\\">\\n\\t\\t\\t<div class=\\\"elementor-spacer-inner\\\"><\\\/div>\\n\\t\\t<\\\/div>\\n\\t\\t\\t\\t\\t\\t<\\\/div>\\n\\t\\t\\t\\t<\\\/div>\\n\\t\\t[elementor-element k=\\\"9109a976d8649ee6d2c8fef8daebbb8b\\\" data=\\\"eyJpZCI6ImExZDExZjUiLCJlbFR5cGUiOiJ3aWRnZXQiLCJzZXR0aW5ncyI6eyJwcmV2X2xhYmVsIjoiUHJldmlvdXMgUG9zdCIsIm5leHRfbGFiZWwiOiJOZXh0IFBvc3QiLCJzaG93X2JvcmRlcnMiOiIiLCJ0aXRsZV90eXBvZ3JhcGh5X3R5cG9ncmFwaHkiOiJjdXN0b20iLCJ0aXRsZV90eXBvZ3JhcGh5X2ZvbnRfc2l6ZSI6eyJ1bml0IjoicHgiLCJzaXplIjoxNCwic2l6ZXMiOltdfSwidGl0bGVfdHlwb2dyYXBoeV9mb250X3dlaWdodCI6IjcwMCIsIl9fZ2xvYmFsc19fIjp7ImFycm93X2NvbG9yIjoiZ2xvYmFsc1wvY29sb3JzP2lkPXByaW1hcnkiLCJsYWJlbF9jb2xvciI6Imdsb2JhbHNcL2NvbG9ycz9pZD1zZWNvbmRhcnkifSwiYXJyb3ciOiJmYSBmYS1jYXJldC1sZWZ0Iiwic2hvd19hcnJvdyI6IiJ9LCJlbGVtZW50cyI6W10sIndpZGdldFR5cGUiOiJwb3N0LW5hdmlnYXRpb24ifQ==\\\"]\\t\\t\\t<\\\/div>\\n\\t\\t<\\\/div>\\n\\t\\t\\t\\t\\t<\\\/div><\\\/div>\\r\\n\\t\\t<\\\/section>\\r\\n\\t\\t\",\"scripts\":[],\"styles\":[]}}"]},"jetpack_featured_media_url":"https:\/\/kmwllc.com\/wp-content\/uploads\/2024\/05\/blog_opensearch-agg1200x900-min.png","menu_order":0,"_links":{"self":[{"href":"https:\/\/kmwllc.com\/index.php\/wp-json\/wp\/v2\/posts\/29639","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/kmwllc.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/kmwllc.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/kmwllc.com\/index.php\/wp-json\/wp\/v2\/users\/11"}],"replies":[{"embeddable":true,"href":"https:\/\/kmwllc.com\/index.php\/wp-json\/wp\/v2\/comments?post=29639"}],"version-history":[{"count":10,"href":"https:\/\/kmwllc.com\/index.php\/wp-json\/wp\/v2\/posts\/29639\/revisions"}],"predecessor-version":[{"id":30196,"href":"https:\/\/kmwllc.com\/index.php\/wp-json\/wp\/v2\/posts\/29639\/revisions\/30196"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/kmwllc.com\/index.php\/wp-json\/wp\/v2\/media\/29759"}],"wp:attachment":[{"href":"https:\/\/kmwllc.com\/index.php\/wp-json\/wp\/v2\/media?parent=29639"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/kmwllc.com\/index.php\/wp-json\/wp\/v2\/categories?post=29639"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/kmwllc.com\/index.php\/wp-json\/wp\/v2\/tags?post=29639"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}