{"id":15784687,"url":"https://github.com/secretworry/elaxto","last_synced_at":"2026-05-17T15:35:36.724Z","repository":{"id":147708254,"uuid":"74748767","full_name":"secretworry/elaxto","owner":"secretworry","description":"ElasticSearch query dsl \u0026 client for Elixir","archived":false,"fork":false,"pushed_at":"2017-07-20T08:27:43.000Z","size":49,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-10-11T20:14:58.231Z","etag":null,"topics":["dsl","elasticsearch","elasticsearch-queries","elixir"],"latest_commit_sha":null,"homepage":"","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/secretworry.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2016-11-25T10:26:47.000Z","updated_at":"2024-07-17T09:42:14.000Z","dependencies_parsed_at":"2023-05-27T05:00:36.558Z","dependency_job_id":null,"html_url":"https://github.com/secretworry/elaxto","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/secretworry/elaxto","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/secretworry%2Felaxto","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/secretworry%2Felaxto/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/secretworry%2Felaxto/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/secretworry%2Felaxto/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/secretworry","download_url":"https://codeload.github.com/secretworry/elaxto/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/secretworry%2Felaxto/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279004005,"owners_count":26083661,"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","status":"online","status_checked_at":"2025-10-10T02:00:06.843Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["dsl","elasticsearch","elasticsearch-queries","elixir"],"created_at":"2024-10-04T20:04:56.264Z","updated_at":"2025-10-10T13:05:22.635Z","avatar_url":"https://github.com/secretworry.png","language":"Elixir","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Elaxto\n\nThe real DSL for ElasticSearch in Elixir\n\n# Why Elaxto\n\nSince ElasticSearch has defined a DSL using JSON, why bother writing another lib to write a DSL\nfor another DSL? The answer is JSON is too verbose. Especially, the map expression in Elixir\nmakes the situation worse(`%{}` instead of `{}`, `=\u003e` instead of `:`).\n\nConsidering a ElasticSearch query is just a series of nested function calls, why don't we just\nuse function calls in the Elixir to emulate the ES Query DSL?\n\nHere is a quick compare using a bool query example from [ES Official site](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-bool-query.html)\n\nFirstly, our function-based DSL\n\n  ```elixir\n  query(\n    bool(\n      must: term(user: \"kimchy\"),\n      filter: term(tag: \"tech\"),\n      must_not: range(age: [from: 10, to: 20]),\n      should: [term(tag: \"wow\"), term(tag: \"elasticsearch\")],\n      minimum_should_match: 1,\n      boost: 1.0\n    )\n  )\n  ```\nHere the original query expression\n  ```javascript\n  {\n    \"query\": {\n      \"bool\" : {\n        \"must\" : {\n          \"term\" : { \"user\" : \"kimchy\" }\n        },\n        \"filter\": {\n          \"term\" : { \"tag\" : \"tech\" }\n        },\n        \"must_not\" : {\n          \"range\" : {\n            \"age\" : { \"from\" : 10, \"to\" : 20 }\n          }\n        },\n        \"should\" : [\n          { \"term\" : { \"tag\" : \"wow\" } },\n          { \"term\" : { \"tag\" : \"elasticsearch\" } }\n        ],\n        \"minimum_should_match\" : 1,\n        \"boost\" : 1.0\n      }\n    }\n  }\n  ```\nand the Elixir version\n  ```elixir\n  %{\"query\"=\u003e %{\n      \"bool\" =\u003e %{\n        \"must\" =\u003e %{\n          \"term\" =\u003e %{ \"user\" =\u003e \"kimchy\" }\n        },\n        \"filter\"=\u003e %{\n          \"term\" =\u003e %{ \"tag\" =\u003e \"tech\" }\n        },\n        \"must_not\" =\u003e %{\n          \"range\" =\u003e %{\n            \"age\" =\u003e %{ \"from\" =\u003e 10, \"to\" =\u003e 20 }\n          }\n        },\n        \"should\" =\u003e [\n          %{ \"term\" =\u003e %{ \"tag\" =\u003e \"wow\" } },\n          %{ \"term\" =\u003e %{ \"tag\" =\u003e \"elasticsearch\" } }\n        ],\n        \"minimum_should_match\" =\u003e 1,\n        \"boost\" =\u003e 1.0\n      }\n    }\n  }\n  ```\n\nI think the result is clear enough, our solution wins out with more concise expression, and less LOC.\n\nBesides, we provided a simple ElasticSearch abstraction helping you to organize your ElasticSearch related code.\n\n## Installation\n\nStill under construction, wants to be an early bird?\n\n  Add `elaxto` to your list of dependencies in `mix.exs`:\n\n      ```elixir\n      def deps do\n        [{:elaxto, github: \"secretworry/elaxto\", branch: :master}]\n      end\n      ```\n\n# Usage\n\n## Building Query\n\nJust `import Elaxto.Query` in your module, you can use the macro `query/1` and `suggest/1` to build ElasticSearch query.\n  ```elixir\n  defmodule MyApp.UserIndex do\n    import Elaxto.Query\n    def search_by_user_name(user_name) do\n      MyApp.Elacto.post({:my_app, :user},\n        query(\n          term(user_name: ^user_name) # Don't forget to use the escape character ^ here\n        )\n      )\n    end\n  end\n  ```\nNow you can defining ES Query like invoking a bunch of elixir calls, but here's some hint.\n\n  1. Since it's still a elixir call, you can only put the keyword-like args at the tail of args\n    To construct a query like this\n    ```javascript\n    {\"query\": { \"bool\": {\"boot\": 1.0, \"must\": { \"term\": {\"user\": \"name\"}}}}}\n    ```\n    instead of adding the `boot` args at the front of the `bool` call, you have to push it to the end of argument list,\n    like this\n    ```elixir\n    query(bool(must: term(user: \"name\"), boot: 1.0))\n    # instead of\n    # query(boot: 1.0, bool(must: term(user: \"name\")))\n    ```\n  2. Use `^` to escape variables in the query\n    ```elixir\n    name = \"Alice\"\n    query(term(user_name: ^name))\n    ```\n  3. Be conscious about how the queries should be composed.\n    We can compose two queries in two ways, the first is to let them merge into a list, the second would be composing them\n    into a map.\n    \n    ```elixir\n    # We archive the first one through wrapping the two query into an array\n    bool(\n      should: [term(tag: \"elaxto\"), term(tag: \"woo\")]\n    )\n    # generates: {should: [ {term: {tag: \"elaxto\"}, {term: {tag: \"woo\"}]}\n    \n    # We archive the second on through wrapping the two query into an double-array `[[` and `]]\n    bool(\n      must: [[term(tag: \"elaxto\", match(message: \"awesome\")]]\n    )\n    # generates: {must: {term: {tag: \"elaxto\"}, match: {message: \"awesome\"}}}\n    ```\n\n## Send queries to the server\n\nCode for this section is still under *frequently* reconstruction\n\n  1. Define your own `Elaxto.Http.Adapter` or use the provided `Elaxto.Http.Adapters.Maxwell`(thanks to [Maxwell](https://github.com/zhongwencool/maxwell) a awesome http client adapter)\n  2. Define a `Elaxto` in your project\n    ```elixir\n    defmodule MyApp.Elaxto do\n      use Elaxto, otp_app: :my_app\n    end\n    ```\n  3. Add configuration for the `Elaxto` in your config file\n    ```elixir\n    config :my_app, MyApp.Elaxto,\n      http_adapter: Elaxto.Http.Adapters.Maxwell\n    ```\n    you can also pass options to the adapter in the config\n    ```elixir\n    config :my_app, MyApp.Elaxto,\n      http_adapter: {Elaxto.Http.Adapters.Maxwell, [key: value]}\n    ```\n    \n    The available options are\n    \n    * `http_adapter` - (required) the Http Adapter used for the Elaxto, you can config different adapter for different env\n    * `host`         - (optional) the host \u0026 port for ElasticSearch server, defaults to `http://localhost:9200`\n  4. Now you can use `get/1`, `post/2`, `put/2`, `delete/1` to interact with the server\n\n## Defining index schema\n\nAn index schema defines how to create an index, and how to convert models into documents of ES\n\n(To Be Continued)\n    \n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsecretworry%2Felaxto","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsecretworry%2Felaxto","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsecretworry%2Felaxto/lists"}