Elasticsearch extensions for Vase and Fern.
This library adds a few literals which make it possible to quickly create APIs using Elasticsearch. This uses the Elasticsearch library Spandex for the underlying Elasticsearch client.
This literal will connect to an Elasticsearch and return an interceptor which injects the connection in the context on every request.
The only required argument is :hosts
which accepts a collection of
URIs of nodes. Additional allowed arguments specified here
(fern/lit vase.elasticsearch/connect
{:hosts ["http://localhost:9200"]})
Create an Elasticsearch index using the provided name and settings. If an index with the same name exists, this is a no-op.
Param | Meaning |
---|---|
:name |
Optional. The name of the interceptor. |
:index |
The name of the index. |
:settings |
The index settings specified inline, in a JSON, or in a YAML file. |
This creates an index named tmdb
using the Elasticsearch
configuration specified in the file settings.json
.
(fern/lit vase.elasticsearch/create
{:name :tmdb/create
:index "tmdb"
:settings "settings.json"})
Get a document from the index by its id.
Param | Meaning |
---|---|
:name |
Optional. The name of the interceptor. |
:index |
The name of the index. |
:type |
Optional. The document type. Defaults to :_doc |
:id-path |
The path within the context map to the document id. |
This builds an interceptor which will lool up a document of type
:_doc
in the index my-index
. The id is sourced from the path
paramter :id
.
(fern/lit vase.elasticsearch/get-document
{:name :tmdb/get-document
:index "my-index"
:type :_doc
:id-path [:request :path-params :id]})
Put a document into the index.
Param | Meaning |
---|---|
:name |
Optional. The name of the interceptor. |
:index |
The name of the index. |
:type |
Optional. The document type. Defaults to :_doc . |
:id-path |
The path within the context map to the document id. |
:body-path |
The path within the context map to the document body. This is what will get indexed into Elasticsearch. |
(fern/lit vase.elasticsearch/put-document
{:name :tmdb/put-document
:index "my-index"
:type :_doc
:id-path [:request :path-params :id]
:body-path [:request :body]})
Delete a document from the index by its id.
Param | Meaning |
---|---|
:name |
Optional. The name of the interceptor. |
:index |
The name of the index. |
:type |
Optional. The document type. |
:id-path |
The path within the context map to the document id. |
(fern/lit vase.elasticsearch/delete-document
{:name :tmdb/delete-document
:index "my-index"
:type :_doc
:id-path [:request :path-params :id]})
Perform a search against an Elasticsearch index (or indices if a vector of index names). See the Elasticsearch docs for more details.
Param | Meaning |
---|---|
:name |
Optional. The name of the interceptor. |
:index |
The name of the index. |
:method |
Optional. The HTTP method to use when querying Elasticsearch. Defaults to :get . |
:params |
Variables to bind from the request map. These values come from query and path parameters. |
:body |
The query to send to Elasticsearch. You may use programming constructs within the body. See the Elasticsearch docs for more details. |
(fern/lit vase.elasticsearch/search
{:name :tmdb/count
:index "my-index"
;; The variable `q` comes a query paramter. So, e.g., if we
;; have some endpoint that's queryied like so
;; `/search?q=nytimes`, `q` would be bound to `nytimes`.
:params [q]
;; Notice that we are using a programming construct within
;; an otherwise declarative query. This opens up a wide
;; possibility of behavior within a compact form.
:body {:query
(if q
{:multi_match {:query q
:fields ["overview"
"title"
"directors.name"
"cast.name"]}}
{:match_all {}})}})
Return a count for the number of matches for a given query. See the Elasticsearch docs for more details.
Param | Meaning |
---|---|
:name |
Optional. The name of the interceptor. |
:index |
The name of the index. |
:method |
Optional. The HTTP method to use when querying Elasticsearch. Defaults to :get . |
:params |
Variables to bind from the request map. These values come from query and path parameters. |
:body |
The count query to send to Elasticsearch. You may use programming constructs within the body. See the Elasticsearch docs for more details. |
Perform an abritrary HTTP request against Elasticsearch. You can use this to peform any request not covered by one of the named actions above.
Param | Meaning |
---|---|
:name |
Optional. The name of the interceptor. |
:index |
The name of the index. |
:method |
Optional. The HTTP method to use when querying Elasticsearch. Defaults to :get . |
:params |
Variables to bind from the request map. These values come from query and path parameters. |
:body |
The query to send to Elasticsearch. You may use programming constructs within the body. |
(fern/lit vase.elasticsearch/request
{:params [q dbg]
:url [:tmdb :_search]
:method :get
:body {:_source [:title :release_year]
:explain (or dbg false)
:query (let [q (or q "")]
{:multi_match
{:query q
:fields ["title^0.1", "overview"]}})}})
(fern/lit vase.elasticsearch/request
{:params [id]
:url [:tmdb :_doc id]
:method :put})
Start an Elasticsearch cluster with Docker compose:
docker-compose up
In a new terminal, start the example API:
clj -A:test:service
In a new terminal, index content:
clj -A:test:index
You can now start issuing queries against the API:
curl -s 'localhost:8080/search?q=basketball+with+cartoon+aliens' | jq .hits.hits[]._source.title
"Space Jam"
"Just Wright"
"Who Wants To Kill Jessie?"
"He Got Game"
"Grown Ups"
"Air Bud"
"Glory Road"
"Semi-Pro"
"Coach Carter"
"Speed Racer"
The entire API is define using the configuration file in
dev/tmdb.fern
. You can easily iterate on this query to make a search
that works for you.
Example:
$ make release/patch clean jar deploy