Skip to content

Instantly share code, notes, and snippets.

@webgago
Created May 26, 2016 04:39
Show Gist options
  • Save webgago/96da7a263c5b27c43a7be7101b93561f to your computer and use it in GitHub Desktop.
Save webgago/96da7a263c5b27c43a7be7101b93561f to your computer and use it in GitHub Desktop.
chewy example
# app/search/base_search.rb
class BaseSearch
class_attribute :index
class_attribute :per_page
self.per_page = 20
def initialize(params={}, &block)
@index = self.index.constantize
@params = params.dup
@q = params[:query].presence
yield self if block_given?
end
def search(&block)
rescue_search do
@query ||= if block_given?
paginate yield(query)
else
paginate query
end
end
end
def query
raise NotImplementedError
end
def result_from
offset + 1
end
def result_to
offset + @query.count
end
def offset
(page - 1) * per_page
end
def page
(@params[:page].presence || 1).to_i
end
def total_count
@query.total_count
end
private
def paginate(query)
query.offset(offset).limit(per_page)
end
def q
return {} unless @q.present?
{
query_string: {
fields: searchable_attributes,
query: @q,
default_operator: 'and'}
}
end
def searchable_attributes
raise NotImplementedError
end
def by_term(name, value=@params[name])
return {} unless value.present?
{
term: {
name => value
}
}
end
def by_boolean(name, value=@params[name])
{
term: {
name => !!value
}
}
end
def by_terms(name, value=@params[name])
return {} unless value.present?
{
terms: {
name => value,
execution: 'bool'
}
}
end
def by_range(name, to: @params[:"#{name}_to"], from: @params[:"#{name}_from"])
range = {}
return range unless to.present? || from.present?
range[:gte] = from.to_f if from.present?
range[:lte] = to.to_f if to.present?
{
range: {
name => range
}
}
end
def by_range_dates(name, to: @params[:"#{name}_from"], from: @params[:"#{name}_to"])
range = {}
return range unless to.present? || from.present?
range[:gte] = from if from.present?
range[:lte] = to if to.present?
{
range: {
name => range
}
}
end
def rescue_search &block
block.call.tap { |scope| scope.to_a }
rescue Elasticsearch::Transport::Transport::Errors::BadRequest => e
@error = e.message.match(/QueryParsingException\[([^;]+)\]/).try(:[], 1)
Rails.logger.error(e)
@index.none
end
end
# app/chewy/concerns/index_analizers.rb
module Concerns
module IndexAnalizers
def self.included(base)
base.class_eval do
settings analysis: {
analyzer: {
name: {
tokenizer: 'standard',
filter: ['lowercase']
},
sorted: {
tokenizer: 'keyword',
filter: ['lowercase']
},
prase: {
tokenizer: 'keyword',
filter: ['lowercase']
}
}
}
end
end
end
end
# app/chewy/properties_index.rb
class PropertysIndex < Chewy::Index
include Concerns::IndexAnalizers
define_type Property do
field :type, index: 'not_analyzed'
field :title, analyzer: 'name'
field :manager, analyzer: 'name', value: -> { manager.try(:full_title) }
field :manager_id, index: 'not_analyzed' # to be able filter out by manager for example
field :company, analyzer: 'name', value: -> { company.name }
field :company_id, index: 'not_analyzed'
field :address, analyzer: 'name', value: -> { full_address }
field :created_at, type: 'date', include_in_all: false
end
end
# app/search/properties_search.rb
class PropertiesSearch < BaseSearch
self.index = 'PropertiesIndex'
def query
@index.
query(q).
filter(by_manager).
filter(by_company).
load(scope: scope)
end
def scope
Property.includes(:manager, :company)
end
private
def by_manager
by_term(:manager_id)
end
def by_company
by_term(:company_id)
end
def searchable_attributes
[
:type,
:title,
:manager,
:company,
:address
]
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment