Skip to content

Instantly share code, notes, and snippets.

@izelnakri
Last active October 5, 2023 14:59
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save izelnakri/b9d569dda9d873222a3d077bd5cd4461 to your computer and use it in GitHub Desktop.
Save izelnakri/b9d569dda9d873222a3d077bd5cd4461 to your computer and use it in GitHub Desktop.
ecto/elixir search functionality
# SELECT company,
# GREATEST(similarity(company.sourced_name, 'search term'), similarity(company.local_name, 'search term'), similarity(company.name, 'search term')) AS rank
# FROM "companies" company
# WHERE (similarity(company.sourced_name, 'search term') > 0.1::float) OR
# (similarity(company.local_name, 'search term') > 0.1::float) OR
# (similarity(company.name, 'search term') > 0.1::float)
# ORDER BY rank DESC
# LIMIT 5;
defmodule Company do
use Application.Web, :model
# relationships: industry
schema "companies" do
field :sourced_name, :string
field :local_name, :string
field :name, :string
# other fields
end
def search(search_term) do
from(
company in Company, # normally these even have joins
select: %{
company: company,
rank: fragment("GREATEST(similarity(?, ?), similarity(?, ?), similarity(?, ?)) AS rank",
company.local_name, ^search_term, company.sourced_name, ^search_term, company.name, ^search_term
),
},
where: fragment("similarity(?, ?)", company.sourced_name, ^search_term) > 0.1 or
fragment("similarity(?, ?)", company.name, ^search_term) > 0.1 or
fragment("similarity(?, ?)", company.local_name, ^search_term) > 0.1,
order_by: fragment("rank DESC"),
limit: 5
)
end
end
defmodule Controller do
use Web, :controller
import BaseSerializer
def search(conn, %{"query" => search_input}) do
companies_results = Company.search(search_input) |> Repo.all
# other two table searchs
results = complex_elixir_manipulation_stuff(companies_results ++ other_searches)
# data manipulation here to sort the order, merge some objects in two highly relational tables,
# prepare the data for ember.
json conn, %{results: results}
# the entire request takes like ~20-60ms locally, with all the things above
end
end
// not very well written/simple concept for turning the search results to Ember Data Objects
// also useful for search-and-associate type of input fields.
import fetch from 'ember-network/fetch';
import Ember from 'ember';
import config from 'frontend/config/environment';
const { Component, computed, inject } = Ember;
export default Component.extend({
store: inject.service(),
keyUp() {
let query = $(event.target).val();
if (this.get('searchPath') && query.length > 0) {
fetch(config.apiHost + `/${this.get('searchPath')}?search=${query}`).then((response) => {
return response.json();
}).then((json) => {
var array = [];
json.results.forEach((result) => {
if (result.company) {
this.get('store').pushPayload({ company: result.company });
array.push(this.get('store').peekRecord('company', result.company.id));
} else if (result.person) {
this.get('store').pushPayload({ person: result.person });
array.push(this.get('store').peekRecord('person', result.person.id));
}
});
this.set('results', Ember.A(array));
});
}
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment