## Goal
Have Notes (and possible Users) search using Algolia following the logic described in [this Jira issue](https://mindvalley.atlassian.net/browse/INS-96) in the most performant and scalable way possible.
## Issues with the current implementation
### Post processing
The desired ranking logic is being applied after the Algolia search result by our BE
- Brings down performance, especially with larger datasets.
- Possibily flawed logic, some of the rules written in the Jira are not considered at all for what I could see.
- Shifts the responsibility of ranking most relevant entries to our side (open a lot of room for mistake).
- Blocks direct FE querying.
- Increases code complexity.
### Cross domain search
We're using the post processing of the algolia search to not only rank the note but to also bring a complete different list of Users based on those notes.
- Again performance is hurt, in this case especially for making a lot of queries to user table while processing the notes.
- Possibily flawed logic as we are only considering the users returned by the notes search (is that really how it should work?).
- Increases code complexity.
### Back-end search
We're using BE search method that is highly [discouraged by Alogilia](https://github.com/algolia/algoliasearch-rails#backend-search).
- Increases search latentcy and our servers load, again hurting performance.
- Increases failure points
## Proposed solution
### Reindexing
Restructure and reindex the current Models in the following way:
#### Note
```json=
{
"objectId": <note_id>, #Reference
"tages_names": [<string>], #Searchable
"content_meta_titles": [<string>], #Searchable
"title": <string>, #Searchable
"content": <string>, #Searchable
"user_full_name": <string>, #Searchable
"username": <string>, #Searchable
"user_id": <string>, #Filterable
"is_public": <boolean>, #Filterable
}
```
#### User
```json=
"objectId": <note_id>, #Reference
"first_name": <string>, #Searchable
"last_name": <string>, #Searchable
"username": <string> #Searchable
"profile_url": <string> #Display
```
### Replace Ruby post processing for Algolia filtering
After reindexing we can achieve the desired results without any post processing lavering Algolia [default ranking](https://www.algolia.com/doc/guides/managing-results/relevance-overview/in-depth/ranking-criteria/#filters), [`optionalFilters`](https://www.algolia.com/doc/api-reference/api-parameters/optionalFilters/) and [filter scores](https://www.algolia.com/doc/guides/managing-results/refine-results/filtering/in-depth/filter-scoring/#how-scoring-is-calculated).
For instance, when performing the search to Algolia we'd give a filter similar to the following:
```javascript=
`(tag_names:${search}<score=4> OR content_meta_titles:${search}<score=2> OR title:${search}<score=1>)`
```
And same goes for User but with the appropiate fields for scoring.
### Use Front-end search and Algolia multi index search.
Instead of performing the search in our BE we'll do it straight on the FE using [Agolia Javascript API](https://github.com/algolia/algoliasearch-client-javascript) and the BE ramains responsable only for indexing.
We'll also use the [multi search feature](https://www.algolia.com/doc/api-reference/api-methods/multiple-queries/) to query for both Notes and Users in one API hit.
**:warning: Attention: :warning:** Given we the search on the FE every other client we might have in the future (Android, IOS, etc) would have to call Algolia directly using one their [API clients](https://www.algolia.com/doc/guides/getting-started/how-algolia-works/in-depth/ecosystem/) to achieve the same result.
## Action Plan
1. Implement indexing code on Elixir
2. Implement Note and User mutations on Elixir (create, update, delete)
3. Implement new search using filters (JS, Elixir?)
4. Run reindex in all the current entries