Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add conversions factor option to searchkick and inline search #1691

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -790,6 +790,21 @@ And set it up to run daily.
UpdateConversionsJob.perform_later("Product", since: 1.day.ago)
```

### Conversions Factor
By default, conversions are added to the score. To have a greater impact on the score with fewer conversions, you can define a conversion factor to multiply the number of conversions before adding them to the score. See [ElasticSearch docs](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-function-score-query.html#function-field-value-factor).

You can set the factor in the `searchkick` method:
```ruby
class Product < ApplicationRecord
searchkick conversions: :conversions, conversions_factor: 100
end
```

Or, call the search method with the `conversions_factor` option:
```ruby
Product.search("ice cream", conversions_factor: 100)
```

## Personalized Results

Order results differently for each user. For example, show a user’s previously purchased products before other results.
Expand Down
4 changes: 2 additions & 2 deletions lib/searchkick/model.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ module Model
def searchkick(**options)
options = Searchkick.model_options.merge(options)

unknown_keywords = options.keys - [:_all, :_type, :batch_size, :callbacks, :case_sensitive, :conversions, :deep_paging, :default_fields,
:filterable, :geo_shape, :highlight, :ignore_above, :index_name, :index_prefix, :inheritance, :language,
unknown_keywords = options.keys - [:_all, :_type, :batch_size, :callbacks, :case_sensitive, :conversions, :conversions_factor,
:deep_paging, :default_fields, :filterable, :geo_shape, :highlight, :ignore_above, :index_name, :index_prefix, :inheritance, :language,
:locations, :mappings, :match, :max_result_window, :merge_mappings, :routing, :searchable, :search_synonyms, :settings, :similarity,
:special_characters, :stem, :stemmer, :stem_conversions, :stem_exclusion, :stemmer_override, :suggest, :synonyms, :text_end,
:text_middle, :text_start, :unscope, :word, :word_end, :word_middle, :word_start]
Expand Down
9 changes: 6 additions & 3 deletions lib/searchkick/query.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ class Query

def initialize(klass, term = "*", **options)
unknown_keywords = options.keys - [:aggs, :block, :body, :body_options, :boost,
:boost_by, :boost_by_distance, :boost_by_recency, :boost_where, :conversions, :conversions_term, :debug, :emoji, :exclude, :explain,
:fields, :highlight, :includes, :index_name, :indices_boost, :limit, :load,
:boost_by, :boost_by_distance, :boost_by_recency, :boost_where, :conversions, :conversions_term, :conversions_factor,
:debug, :emoji, :exclude, :explain, :fields, :highlight, :includes, :index_name, :indices_boost, :limit, :load,
:match, :misspellings, :models, :model_includes, :offset, :operator, :order, :padding, :page, :per_page, :profile,
:request_params, :routing, :scope_results, :scroll, :select, :similar, :smart_aggs, :suggest, :total_entries, :track, :type, :where]
raise ArgumentError, "unknown keywords: #{unknown_keywords.join(", ")}" if unknown_keywords.any?
Expand Down Expand Up @@ -626,6 +626,8 @@ def build_query(query, filters, should, must_not, custom_filters, multiply_filte

def set_conversions
conversions_fields = Array(options[:conversions] || searchkick_options[:conversions]).map(&:to_s)
conversions_factor = options[:conversions_factor] || searchkick_options[:conversions_factor]

if conversions_fields.present? && options[:conversions] != false
conversions_fields.map do |conversions_field|
{
Expand All @@ -641,7 +643,8 @@ def set_conversions
}
},
field_value_factor: {
field: "#{conversions_field}.count"
field: "#{conversions_field}.count",
factor: conversions_factor || 1
}
}
}
Expand Down
21 changes: 21 additions & 0 deletions test/conversions_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,25 @@ def test_conversions_weight
]
assert_order "product", ["Product Conversions", "Product Boost"], boost: "orders_count"
end

def test_conversions_factor
Product.reindex
store [
{name: "Tomato", conversions: {}},
{name: "TomatE", conversions: {"tomato" => 1}},
]
assert_order "tomato", ["TomatE", "Tomato"]
assert_order "tomato", ["Tomato", "TomatE"], conversions: false
end

def test_inline_conversions_factor
Speaker.reindex
store [
{name: "SpeakRE", conversions_a: {"speaker" => 1}},
{name: "Speaker"}
], Speaker

assert_order "speaker", ["Speaker", "SpeakRE"], {conversions: "conversions_a"}, Speaker
assert_order "speaker", ["SpeakRE", "Speaker"], {conversions: "conversions_a", conversions_factor: 100}, Speaker
end
end
1 change: 1 addition & 0 deletions test/models/product.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class Product
],
suggest: [:name, :color],
conversions: [:conversions],
conversions_factor: 100,
locations: [:location, :multiple_locations],
text_start: [:name],
text_middle: [:name],
Expand Down