{"id":22152143,"url":"https://github.com/findinpath/elastic-price-range-aggregation","last_synced_at":"2025-07-11T13:43:54.837Z","repository":{"id":112790927,"uuid":"297452771","full_name":"findinpath/elastic-price-range-aggregation","owner":"findinpath","description":"Find the buckets for the price range aggregations in Elasticsearch searches","archived":false,"fork":false,"pushed_at":"2020-09-21T20:26:02.000Z","size":64,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-01-29T18:32:14.470Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/findinpath.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-09-21T20:24:46.000Z","updated_at":"2020-09-21T20:26:05.000Z","dependencies_parsed_at":null,"dependency_job_id":"8ff72b15-7fbe-46e4-ba59-e401e7cfb019","html_url":"https://github.com/findinpath/elastic-price-range-aggregation","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/findinpath%2Felastic-price-range-aggregation","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/findinpath%2Felastic-price-range-aggregation/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/findinpath%2Felastic-price-range-aggregation/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/findinpath%2Felastic-price-range-aggregation/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/findinpath","download_url":"https://codeload.github.com/findinpath/elastic-price-range-aggregation/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245277481,"owners_count":20589154,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-02T00:47:24.619Z","updated_at":"2025-03-24T13:25:32.410Z","avatar_url":"https://github.com/findinpath.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"Elasticsearch Price Range Aggregations\n======================================\n\nA common functionality in each webshop is the ability to show price ranges\nwhen searching for products.\n\nWhen searching for a generic product (e.g. : backpack, shoes) the users\nare nowadays accustomed to receive a relevant price aggregation showing \nthe distribution of the product prices from the shop.\n\ne.g.: when searching for `backpack` on a marketplace website, there could \nbe displayed the following price range listing:\n\n* up to 20 EUR - 10\n* 20 to 40 EUR - 28\n* 40 to 80 EUR - 52\n* 80 to 180 EUR - 12\n* from 180 EUR - 4\n\n\nElasticsearch supports performing [range aggregations](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-range-aggregation.html) \non a search request, but it requires the user to specify explicitly the price ranges:\n\n```bash\ncurl -X GET \"localhost:9200/products/_search?pretty\" -H 'Content-Type: application/json' -d'\n{\n  \"query\": { \n     \"match\": {\n     \t\"category\": \"Luggage\"\n     } \n  },\n  \"aggs\": {\n    \"price_ranges\": {\n      \"range\": {\n        \"field\": \"price\",\n        \"ranges\": [\n          { \"to\": 100.0 },\n          { \"from\": 100.0, \"to\": 200.0 },\n          { \"from\": 200.0 }\n        ]\n      }\n    }\n  }  \n}\n'\n``` \n\nThe ranges in the price aggregation depend on the other hand pretty much on what\nis being searched.\nThe price ranges that may be relevant to the users when searching for `shoes` will \nvery likely be different from the ones that will be shown when searching for `laptop`\nbecause most of the shoes won't cost more than 150 EUR, where most of the decent laptops \nstart at 300-400 EUR. \n\nThere is currently quite an old open feature request to support \ndynamically calculated price ranges:\n\nhttps://github.com/elastic/elasticsearch/issues/9572\n\nThis proof of concept project tries to come with a few answers on how to come\nup with balanced ranges for the price aggregations on Elasticsearch searches.\n\n\n## Static price ranges\n\nAs described above, Elasticsearch already offers the ability of specifying\nranges for the price in a search request.\nThe users like to choose from a list of up to 5 price ranges in order to\navoid being overwhelmed with options.\n\nThe main drawback when using this approach is that at the request time\nthere is no way to know how the prices of the products will be distributed.\nAs a consequence, the price ranges used will sometimes not contain relevant\ninformation.\n\n## Use two queries\n\nObtain first the distribution of prices for the search by using the \n[percentiles aggregation](https://www.elastic.co/guide/en/elasticsearch/reference/7.9/search-aggregations-metrics-percentile-aggregation.html)\nand subsequently use this information for building up the buckets of the price\naggregation to be used in the actual search.\n\nThe few buckets that will be shown to the user for the price ranges will mirror \nthe actual price distribution for the product searched.\nOn the other hand, there are two search requests needed to be made against Elasticsearch\nin order to obtain this information.\n\n## Collapse the buckets\n\nThis method builds on top of the static price ranges previously described.\nInstead of retrieving a handful of buckets for the price range aggregation,\nthis method relies on specifying a lot of price range buckets (e.g. : 30/40/50)   \nwhich are then collapsed on the client side on a handful (e.g. : 3/4/5) of relevant price range\nbuckets.\n\nThe main performance drawback in this approach is that there are much more price range buckets\nspecified to be aggregated in the search request compared to the number price range buckets that are\nactually needed to be displayed to the user.\n\n## Run the project\n\nThis project contains a JUnit testcase that spawns a [testcontainers](https://www.testcontainers.org/) \n[Elasticsearch container](https://www.testcontainers.org/modules/elasticsearch/) fills it with\ntest data and tries through different strategies to retrieve the price range aggregations. \n\nCheck the source code of the [PriceRangeAggregationTest.kt](src/test/kotlin/com/findinpath/PriceRangeAggregationTest.kt)\nJUnit test class to see the implementation of the aggregation methods exposed above. \n\nRun the command\n\n```\n./gradlew test\n```\n\nfor executing the tests from this project.\n\n## Feedback\n\nAs already mentioned, this project serves as a proof of concept for performing\nprice aggregations. Eventual improvements to the project code or ideas regarding\nalternative ways to get the price aggregations are very much welcome. ","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffindinpath%2Felastic-price-range-aggregation","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffindinpath%2Felastic-price-range-aggregation","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffindinpath%2Felastic-price-range-aggregation/lists"}