Skip to content

Commit

Permalink
Clarified usage of custom queries, made internal methods private.
Browse files Browse the repository at this point in the history
  • Loading branch information
dblock committed Jan 27, 2017
1 parent 5639fe1 commit 8134660
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 59 deletions.
20 changes: 7 additions & 13 deletions .rubocop_todo.yml
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
# This configuration was generated by
# `rubocop --auto-gen-config`
# on 2017-01-25 11:50:14 -0500 using RuboCop version 0.47.1.
# on 2017-01-27 12:52:56 -0500 using RuboCop version 0.47.1.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again.

# Offense count: 2
# Offense count: 1
Metrics/AbcSize:
Max: 24
Max: 18

# Offense count: 3
# Configuration parameters: CountComments, ExcludedMethods.
Metrics/BlockLength:
Max: 117
Max: 134

# Offense count: 28
# Offense count: 30
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
# URISchemes: http, https
Metrics/LineLength:
Expand All @@ -24,7 +24,7 @@ Metrics/LineLength:
# Offense count: 1
# Configuration parameters: CountComments.
Metrics/MethodLength:
Max: 14
Max: 13

# Offense count: 3
# Cop supports --auto-correct.
Expand All @@ -34,11 +34,6 @@ Performance/RedundantMerge:
- 'lib/estella/parser.rb'
- 'lib/estella/searchable.rb'

# Offense count: 1
Style/AccessorMethodName:
Exclude:
- 'lib/estella/helpers.rb'

# Offense count: 1
Style/ClassVars:
Exclude:
Expand All @@ -55,11 +50,10 @@ Style/Documentation:
- 'lib/estella/query.rb'
- 'lib/estella/searchable.rb'

# Offense count: 3
# Offense count: 1
# Configuration parameters: MinBodyLength.
Style/GuardClause:
Exclude:
- 'lib/estella/query.rb'
- 'lib/estella/searchable.rb'

# Offense count: 9
Expand Down
43 changes: 31 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,17 @@ Just include the `Estella::Searchable` module and add a `searchable` block in yo

```ruby
class Artist < ActiveRecord::Base
include Estella::Searchable

searchable do
field :name, type: :string, analysis: Estella::Analysis::FULLTEXT_ANALYSIS, factor: 1.0
field :keywords, type: :string, analysis: ['snowball', 'shingle'], factor: 0.5
field :bio, using: :biography, type: :string, index: :not_analyzed
field :birth_date, type: :date
field :follows, type: :integer
field :published, type: :boolean, filter: true
boost :follows, modifier: 'log1p', factor: 1E-3
end
...
include Estella::Searchable

searchable do
field :name, type: :string, analysis: Estella::Analysis::FULLTEXT_ANALYSIS, factor: 1.0
field :keywords, type: :string, analysis: ['snowball', 'shingle'], factor: 0.5
field :bio, using: :biography, type: :string, index: :not_analyzed
field :birth_date, type: :date
field :follows, type: :integer
field :published, type: :boolean, filter: true
boost :follows, modifier: 'log1p', factor: 1E-3
end
end
```

Expand Down Expand Up @@ -173,6 +172,12 @@ Artist.estella_search(term: 'frank', published: true)
Artist.estella_search(term: 'frank', size: 10, from: 5)
```

You can exclude records.

```ruby
Artist.estella_search(term: 'frank', exclude: { keywords: 'sinatra' })
```

If you'd like to customize your query further, you can extend `Estella::Query` and override the `query_definition`:

```ruby
Expand All @@ -187,6 +192,20 @@ class MyQuery < Estella::Query
end
```

Or manipulate the query in the initializer directly via `query` or using built-in helpers `must` and `exclude`.

```ruby
class MyQuery < Estella::Query
def initialize(params)
super
# same as query[:filter][:bool][:must] = { keywords: 'frank' }
must term: { keywords: 'frank' }
# same as query[:filter][:bool][:must_not] = { keywords: 'sinatra' }
exclude term: { keywords: 'sinatra' }
end
end
```

And then override class method `estella_search_query` to direct Estella to use your query object:

```ruby
Expand Down
73 changes: 39 additions & 34 deletions lib/estella/query.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,11 @@ def initialize(params)
aggregations: {}
}
add_query
add_filters
add_indexed_fields
add_exclusions
add_pagination
add_aggregations if params[:aggregations]
add_sort
end

# override if needed
def add_aggregations; end

# override if needed
def add_sort; end

def must(filter)
query[:filter][:bool][:must] << filter
end
Expand All @@ -35,6 +28,18 @@ def exclude(filter)
query[:filter][:bool][:must_not] << filter
end

def query_definition
{
multi_match: {
type: 'most_fields',
fields: term_search_fields,
query: params[:term]
}
}
end

private

def add_pagination
query[:size] = params[:size] if params[:size]
query[:from] = params[:from] if params[:from]
Expand All @@ -59,28 +64,19 @@ def add_term_query
add_field_boost
end

def query_definition
{
multi_match: {
type: 'most_fields',
fields: term_search_fields,
query: params[:term]
}
}
end

def add_field_boost
if params[:boost]
query[:query][:function_score][:field_value_factor] = {
field: params[:boost][:field],
modifier: params[:boost][:modifier],
factor: params[:boost][:factor]
}
boost = params[:boost]
return unless boost

if params[:boost][:max]
query[:query][:function_score][:max_boost] = params[:boost][:max]
end
end
query[:query][:function_score][:field_value_factor] = {
field: boost[:field],
modifier: boost[:modifier],
factor: boost[:factor]
}

max = boost[:max]
return unless max
query[:query][:function_score][:max_boost] = max
end

def field_factors
Expand All @@ -102,11 +98,20 @@ def term_search_fields
.flatten
end

def add_filters
if params[:indexed_fields]
params[:indexed_fields].each do |field, opts|
must term: { field => params[field] } if opts[:filter] && params[field]
end
def add_indexed_fields
indexed_fields = params[:indexed_fields]
return unless indexed_fields
indexed_fields.each do |field, opts|
next unless opts[:filter] && params[field]
must term: { field => params[field] }
end
end

def add_exclusions
exclude = params[:exclude]
return unless exclude
exclude.each do |k, v|
exclude term: { k => v }
end
end
end
Expand Down
19 changes: 19 additions & 0 deletions spec/searchable_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ def self.slug
it 'searches all text fields by default' do
expect(SearchableModel.estella_search(term: 'jez')).to eq([@jez])
end
it 'can exclude an instance' do
expect(SearchableModel.estella_search(term: 'jez tez fab', exclude: { keywords: 'jez' })).to eq([@fab, @tez])
end
it 'boosts on follows_count' do
popular_jeremy = SearchableModel.create(title: 'jeremy corban', follows_count: 20_000)
SearchableModel.refresh_index!
Expand Down Expand Up @@ -105,6 +108,22 @@ def self.slug
expect(SearchableModel.estella_search(term: 'david')).to eq([@fab])
end
end
context 'with query customization' do
before do
class CustomQuery < Estella::Query
def initialize(params)
super
exclude term: { keywords: 'jez' }
end
end

allow(SearchableModel).to receive(:estella_search_query).and_return(CustomQuery)
end

it 'uses the custom query' do
expect(SearchableModel.estella_search(term: 'jez tez fab')).to eq([@fab, @tez])
end
end
end

describe 'configuration errors' do
Expand Down

0 comments on commit 8134660

Please sign in to comment.