README.md

# Autocompletex

![hex.pm](https://img.shields.io/hexpm/v/autocompletex.svg)

Autocompletex is a low-latency plug-and-play autocomplete tool using Redis sorted set. Written in pure Elixir, it focuses on rapid prototyping using your existing stack: simply start a redis instance, and start_link a GenServer.

Currently, it provides these implementation:

* Google-like query prediction based on popularity. E.G. ne -> netflix, new york times 
* Lexicographic. Sorted in alphabetical order (faster)

There are two ways to run it:

* Use it as a standalone microservice with HTTP connection.
* GenServer

## Installation

Add the `:autocompletex` to your `mix.ecs` file:

```elixir
def deps do
  [{:autocompletex, "~> 0.1.0"}]
end
```

Then add it to `applications`:

```elixir
defp application() do
  [applications: [:logger, :redix]]
end
```

Then, run mix deps.get in your shell to fetch the new dependency.


## Usage

### Overview

Currently, two types of autocompletion is support:

* Lexicographic
* Predictive

If you want to suggest another scheme, please post an issue.

There are 3 ways to run it.

1. Standalone HTTP service
2. Using a GenServer
3. Supervision tree

### Manual

To start a GenServer manually:

```elixir
# For Lexicographic:
{:ok, conn} = Redix.start_link
db = "testdb"
{:ok, worker} = Autocompletex.Lexicographic.start_link(conn, db, Autocompletex)

# For Predictive:
{:ok, conn} = Redix.start_link
{:ok, worker} = start_link(conn, :ac)
```

Alternatively, you can use it in a supervision tree.

Add this to `config.exs`:

```elixir
config :autocompletex,
  redis_host: "localhost",
  redis_port: 6379,
  redis_string: nil,
  http_server: true,
  http_port: 3000,
  debug: false, # runs :observer.start if true
  type: :lexicographic #:predictive
```

Then call

```elixir
Autocompletex.Lexicographic.upsert(Autocompletex.Lexicographic, ["test", "example"])
```

If `http_server` is set to `true`, two http endpoints will be accessible at the designated `http_port`(default: 3000).

```
upsert   -> /add?term=Elixir
complete -> /complete?term=te
```

## API

There are two functions: `upsert` and `complete`.

`upsert/2` means insert or update. For Lexicographic, if a query is already inserted, it will do nothing. For Predictive, it will increment the score of the query.

`complete/3` returns a list of matched results. It takes 3 parameters: `pid`, `prefix`, `rangelen`. rangelen is the number of results to be returned. Defaults to 50.


```elixir
:ok = Autocompletex.Lexicographic.upsert(worker, ["test", "example"])
{:ok, val} == complete(worker, "te") # assert val == ["test"]
```

## Misc

If you have a list of user-generated search queries, you can use a mix task to index and provision the redis instance.

Simply do:

`mix autocompletex.import --filename [path/to/file] [--predictive]`

## Docs

To be updated. In the meantime, I'm happy to answer questions in issues.