diff --git a/CHANGELOG.md b/CHANGELOG.md index 86d787c..ff0d3cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,9 @@ ## 1.2.1 [unreleased] +- Added `multi_search` method - Added support for routing for Elasticsearch 2 - Added support for `search_document_id` and `search_document_type` in models +- Fixed instrumentation for bulk updates ## 1.2.0 diff --git a/README.md b/README.md index c60a53d..b9799cc 100644 --- a/README.md +++ b/README.md @@ -1092,6 +1092,18 @@ products = end ``` +### Multi Search [master] + +To batch search requests for performance, use: + +```ruby +fresh_products = Product.search("fresh", execute: false) +frozen_products = Product.search("frozen", execute: false) +Searchkick.multi_search([fresh_products, frozen_products]) +``` + +Then use `fresh_products` and `frozen_products` as typical results. + ## Reference Reindex one record diff --git a/lib/searchkick.rb b/lib/searchkick.rb index fdf4ddc..5018fff 100644 --- a/lib/searchkick.rb +++ b/lib/searchkick.rb @@ -143,10 +143,10 @@ module Searchkick if queries.any? responses = client.msearch(body: queries.flat_map { |q| [q.params.except(:body), q.body] })["responses"] queries.each_with_index do |query, i| - query.send(:handle_response, responses[i]) + query.handle_response(responses[i]) end end - true + nil end end diff --git a/lib/searchkick/logging.rb b/lib/searchkick/logging.rb index 713efa4..b23b99d 100644 --- a/lib/searchkick/logging.rb +++ b/lib/searchkick/logging.rb @@ -19,8 +19,12 @@ module Searchkick name: "#{record.searchkick_klass.name} Store", id: search_id(record) } - ActiveSupport::Notifications.instrument("request.searchkick", event) do - super(record) + if Searchkick.callbacks_value == :bulk + super + else + ActiveSupport::Notifications.instrument("request.searchkick", event) do + super + end end end @@ -29,8 +33,12 @@ module Searchkick name: "#{record.searchkick_klass.name} Remove", id: search_id(record) } - ActiveSupport::Notifications.instrument("request.searchkick", event) do - super(record) + if Searchkick.callbacks_value == :bulk + super + else + ActiveSupport::Notifications.instrument("request.searchkick", event) do + super + end end end @@ -47,6 +55,32 @@ module Searchkick end end + module SearchkickWithInstrumentation + def multi_search(searches) + event = { + name: "Multi Search", + count: searches.size + } + ActiveSupport::Notifications.instrument("request.searchkick", event) do + super + end + end + + def perform_items(items) + if callbacks_value == :bulk + event = { + name: "Bulk", + count: items.size + } + ActiveSupport::Notifications.instrument("request.searchkick", event) do + super + end + else + super + end + end + end + # https://github.com/rails/rails/blob/master/activerecord/lib/active_record/log_subscriber.rb class LogSubscriber < ActiveSupport::LogSubscriber def self.runtime=(value) @@ -129,6 +163,7 @@ module Searchkick end Searchkick::Query.send(:prepend, Searchkick::QueryWithInstrumentation) Searchkick::Index.send(:prepend, Searchkick::IndexWithInstrumentation) +Searchkick.singleton_class.send(:prepend, Searchkick::SearchkickWithInstrumentation) Searchkick::LogSubscriber.attach_to :searchkick ActiveSupport.on_load(:action_controller) do include Searchkick::ControllerRuntime diff --git a/lib/searchkick/query.rb b/lib/searchkick/query.rb index c00ed70..c90b2e0 100644 --- a/lib/searchkick/query.rb +++ b/lib/searchkick/query.rb @@ -5,7 +5,13 @@ module Searchkick attr_reader :klass, :term, :options attr_accessor :body - def_delegators :execute, :map, :each, :any?, :empty?, :size, :length, :slice, :[], :to_ary + def_delegators :execute, :map, :each, :any?, :empty?, :size, :length, :slice, :[], :to_ary, + :records, :results, :suggestions, :each_with_hit, :with_details, :facets, :aggregations, :aggs, + :took, :error, :model_name, :entry_name, :total_count, :total_entries, + :current_page, :per_page, :limit_value, :padding, :total_pages, :num_pages, + :offset_value, :offset, :previous_page, :prev_page, :next_page, :first_page?, :last_page?, + :out_of_range?, :hits + def initialize(klass, term, options = {}) if term.is_a?(Hash) @@ -84,6 +90,29 @@ module Searchkick "curl #{host[:protocol]}://#{credentials}#{host[:host]}:#{host[:port]}/#{CGI.escape(index)}#{type ? "/#{type.map { |t| CGI.escape(t) }.join(',')}" : ''}/_search?pretty -d '#{query[:body].to_json}'" end + def handle_response(response) + # apply facet limit in client due to + # https://github.com/elasticsearch/elasticsearch/issues/1305 + @facet_limits.each do |field, limit| + field = field.to_s + facet = response["facets"][field] + response["facets"][field]["terms"] = facet["terms"].first(limit) + response["facets"][field]["other"] = facet["total"] - facet["terms"].sum { |term| term["count"] } + end + + opts = { + page: @page, + per_page: @per_page, + padding: @padding, + load: @load, + includes: options[:include] || options[:includes], + json: !options[:json].nil?, + match_suffix: @match_suffix, + highlighted_fields: @highlighted_fields || [] + } + @execute = Searchkick::Results.new(searchkick_klass, response, opts) + end + private def handle_error(e) @@ -109,29 +138,6 @@ module Searchkick end end - def handle_response(response) - # apply facet limit in client due to - # https://github.com/elasticsearch/elasticsearch/issues/1305 - @facet_limits.each do |field, limit| - field = field.to_s - facet = response["facets"][field] - response["facets"][field]["terms"] = facet["terms"].first(limit) - response["facets"][field]["other"] = facet["total"] - facet["terms"].sum { |term| term["count"] } - end - - opts = { - page: @page, - per_page: @per_page, - padding: @padding, - load: @load, - includes: options[:include] || options[:includes], - json: !options[:json].nil?, - match_suffix: @match_suffix, - highlighted_fields: @highlighted_fields || [] - } - @execute = Searchkick::Results.new(searchkick_klass, response, opts) - end - def reindex_command searchkick_klass ? "#{searchkick_klass.name}.reindex" : "reindex" end diff --git a/lib/searchkick/results.rb b/lib/searchkick/results.rb index b4a8659..135cfb6 100644 --- a/lib/searchkick/results.rb +++ b/lib/searchkick/results.rb @@ -108,6 +108,10 @@ module Searchkick response["took"] end + def error + response["error"] + end + def model_name klass.model_name end diff --git a/test/multi_search_test.rb b/test/multi_search_test.rb index b46cfbb..1f89d24 100644 --- a/test/multi_search_test.rb +++ b/test/multi_search_test.rb @@ -10,4 +10,13 @@ class MultiSearchTest < Minitest::Test assert_equal ["Product A"], products.map(&:name) assert_equal ["Store A"], stores.map(&:name) end + + def test_error + store_names ["Product A"] + products = Product.search("*", execute: false) + stores = Store.search("*", order: [:bad_field], execute: false) + Searchkick.multi_search([products, stores]) + assert !products.error + assert stores.error + end end -- libgit2 0.21.0