defmodule Elastix.Search do
@moduledoc """
The search APIs are used to query indices.
[Elastic documentation](https://www.elastic.co/guide/en/elasticsearch/reference/current/search.html)
"""
import Elastix.HTTP, only: [prepare_url: 2]
alias Elastix.{HTTP, JSON}
@doc """
Makes a request to the `_search` or the `_msearch` endpoint depending on the type of
`data`.
When passing a map for data, it'll make a simple search, but you can pass a list of
header and body params to make a [multi search](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-multi-search.html).
## Examples
iex> Elastix.Search.search("http://localhost:9200", "twitter", ["tweet"], %{query: %{term: %{user: "kimchy"}}})
{:ok, %HTTPoison.Response{...}}
iex> Elastix.Search.search("http://localhost:9200", ["twitter", "other-index"], ["tweet"], %{query: %{term: %{user: "kimchy"}}})
{:ok, %HTTPoison.Response{...}}
"""
@spec search(
elastic_url :: String.t(),
index :: String.t() | list,
types :: list,
data :: map | list
) :: HTTP.resp()
def search(elastic_url, index, types, data) when is_list(data),
do: search(elastic_url, index, types, data, [])
def search(elastic_url, index, types, data),
do: search(elastic_url, index, types, data, [])
@doc """
Same as `search/4` but allows to specify query params and options for
[`HTTPoison.request/5`](https://hexdocs.pm/httpoison/HTTPoison.html#request/5).
"""
@spec search(
elastic_url :: String.t(),
index :: String.t() | list,
types :: list,
data :: map | list,
query_params :: Keyword.t(),
options :: Keyword.t()
) :: HTTP.resp()
def search(elastic_url, index, types, data, query_params, options \\ [])
def search(elastic_url, index, types, data, query_params, options)
when is_list(index) do
search(elastic_url, Enum.join(index, ","), types, data, query_params, options)
end
def search(elastic_url, index, types, data, query_params, options)
when is_list(data) do
data =
Enum.reduce(data, [], fn d, acc -> ["\n", JSON.encode!(d) | acc] end)
|> Enum.reverse()
|> IO.iodata_to_binary()
prepare_url(elastic_url, make_path(index, types, query_params, "_msearch"))
|> HTTP.post(data, [], options)
end
def search(elastic_url, index, types, data, query_params, options) do
prepare_url(elastic_url, make_path(index, types, query_params))
|> HTTP.post(JSON.encode!(data), [], options)
end
@doc """
Uses the [Scroll API](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-scroll.html)
to allow scrolling through a list of results.
## Examples
iex> Elastix.Search.scroll("http://localhost:9200", %{query: %{term: %{user: "kimchy"}}})
{:ok, %HTTPoison.Response{...}}
"""
@spec scroll(elastic_url :: String.t(), data :: map, options :: Keyword.t()) ::
HTTP.resp()
def scroll(elastic_url, data, options \\ []) do
prepare_url(elastic_url, "_search/scroll")
|> HTTP.post(JSON.encode!(data), [], options)
end
@doc """
Returns the number of results for a query using the
[Count API](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-count.html).
## Examples
iex> Elastix.Search.count("http://localhost:9200", "twitter", ["tweet"], %{query: %{term: %{user: "kimchy"}}})
{:ok, %HTTPoison.Response{...}}
"""
@spec count(elastic_url :: String.t(), index :: String.t(), types :: list, data :: map) ::
HTTP.resp()
def count(elastic_url, index, types, data),
do: count(elastic_url, index, types, data, [])
@doc """
Same as `count/4` but allows to specify query params and options for
[`HTTPoison.request/5`](https://hexdocs.pm/httpoison/HTTPoison.html#request/5).
"""
@spec count(
elastic_url :: String.t(),
index :: String.t(),
types :: list,
data :: map,
query_params :: Keyword.t(),
options :: Keyword.t()
) :: HTTP.resp()
def count(elastic_url, index, types, data, query_params, options \\ []) do
(elastic_url <> make_path(index, types, query_params, "_count"))
|> HTTP.post(JSON.encode!(data), [], options)
end
@doc false
def make_path(index, types, query_params, api_type \\ "_search") do
path_root = "/#{index}"
path =
case types do
[] -> path_root
_ -> path_root <> "/" <> Enum.join(types, ",")
end
full_path = "#{path}/#{api_type}"
case query_params do
[] -> full_path
_ -> HTTP.append_query_string(full_path, query_params)
end
end
end