tiny-quick-gem 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/searchkick-6.1.2/CHANGELOG.md +919 -0
- data/searchkick-6.1.2/LICENSE.txt +22 -0
- data/searchkick-6.1.2/README.md +2348 -0
- data/searchkick-6.1.2/lib/searchkick/bulk_reindex_job.rb +19 -0
- data/searchkick-6.1.2/lib/searchkick/controller_runtime.rb +40 -0
- data/searchkick-6.1.2/lib/searchkick/hash_wrapper.rb +41 -0
- data/searchkick-6.1.2/lib/searchkick/index.rb +480 -0
- data/searchkick-6.1.2/lib/searchkick/index_cache.rb +30 -0
- data/searchkick-6.1.2/lib/searchkick/index_options.rb +652 -0
- data/searchkick-6.1.2/lib/searchkick/indexer.rb +43 -0
- data/searchkick-6.1.2/lib/searchkick/log_subscriber.rb +57 -0
- data/searchkick-6.1.2/lib/searchkick/middleware.rb +19 -0
- data/searchkick-6.1.2/lib/searchkick/model.rb +120 -0
- data/searchkick-6.1.2/lib/searchkick/multi_search.rb +46 -0
- data/searchkick-6.1.2/lib/searchkick/process_batch_job.rb +20 -0
- data/searchkick-6.1.2/lib/searchkick/process_queue_job.rb +33 -0
- data/searchkick-6.1.2/lib/searchkick/query.rb +1372 -0
- data/searchkick-6.1.2/lib/searchkick/railtie.rb +7 -0
- data/searchkick-6.1.2/lib/searchkick/record_data.rb +147 -0
- data/searchkick-6.1.2/lib/searchkick/record_indexer.rb +174 -0
- data/searchkick-6.1.2/lib/searchkick/reindex_queue.rb +57 -0
- data/searchkick-6.1.2/lib/searchkick/reindex_v2_job.rb +17 -0
- data/searchkick-6.1.2/lib/searchkick/relation.rb +728 -0
- data/searchkick-6.1.2/lib/searchkick/relation_indexer.rb +184 -0
- data/searchkick-6.1.2/lib/searchkick/reranking.rb +28 -0
- data/searchkick-6.1.2/lib/searchkick/results.rb +359 -0
- data/searchkick-6.1.2/lib/searchkick/script.rb +11 -0
- data/searchkick-6.1.2/lib/searchkick/version.rb +3 -0
- data/searchkick-6.1.2/lib/searchkick/where.rb +11 -0
- data/searchkick-6.1.2/lib/searchkick.rb +388 -0
- data/searchkick-6.1.2/lib/tasks/searchkick.rake +37 -0
- data/tiny-quick-gem.gemspec +12 -0
- metadata +73 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# based on https://gist.github.com/mnutt/566725
|
|
2
|
+
module Searchkick
|
|
3
|
+
class LogSubscriber < ActiveSupport::LogSubscriber
|
|
4
|
+
def self.runtime=(value)
|
|
5
|
+
Thread.current[:searchkick_runtime] = value
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def self.runtime
|
|
9
|
+
Thread.current[:searchkick_runtime] ||= 0
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.reset_runtime
|
|
13
|
+
rt = runtime
|
|
14
|
+
self.runtime = 0
|
|
15
|
+
rt
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def search(event)
|
|
19
|
+
self.class.runtime += event.duration
|
|
20
|
+
return unless logger.debug?
|
|
21
|
+
|
|
22
|
+
payload = event.payload
|
|
23
|
+
name = "#{payload[:name]} (#{event.duration.round(1)}ms)"
|
|
24
|
+
|
|
25
|
+
index = payload[:query][:index].is_a?(Array) ? payload[:query][:index].join(",") : payload[:query][:index]
|
|
26
|
+
type = payload[:query][:type]
|
|
27
|
+
request_params = payload[:query].except(:index, :type, :body, :opaque_id)
|
|
28
|
+
|
|
29
|
+
params = []
|
|
30
|
+
request_params.each do |k, v|
|
|
31
|
+
params << "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
debug " #{color(name, YELLOW, bold: true)} #{index}#{type ? "/#{type.join(',')}" : ''}/_search#{params.any? ? '?' + params.join('&') : nil} #{payload[:query][:body].to_json}"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def request(event)
|
|
38
|
+
self.class.runtime += event.duration
|
|
39
|
+
return unless logger.debug?
|
|
40
|
+
|
|
41
|
+
payload = event.payload
|
|
42
|
+
name = "#{payload[:name]} (#{event.duration.round(1)}ms)"
|
|
43
|
+
|
|
44
|
+
debug " #{color(name, YELLOW, bold: true)} #{payload.except(:name).to_json}"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def multi_search(event)
|
|
48
|
+
self.class.runtime += event.duration
|
|
49
|
+
return unless logger.debug?
|
|
50
|
+
|
|
51
|
+
payload = event.payload
|
|
52
|
+
name = "#{payload[:name]} (#{event.duration.round(1)}ms)"
|
|
53
|
+
|
|
54
|
+
debug " #{color(name, YELLOW, bold: true)} _msearch #{payload[:body]}"
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
require "faraday"
|
|
2
|
+
|
|
3
|
+
module Searchkick
|
|
4
|
+
class Middleware < Faraday::Middleware
|
|
5
|
+
def call(env)
|
|
6
|
+
path = env[:url].path.to_s
|
|
7
|
+
if path.end_with?("/_search")
|
|
8
|
+
env[:request][:timeout] = Searchkick.search_timeout
|
|
9
|
+
elsif path.end_with?("/_msearch")
|
|
10
|
+
# assume no concurrent searches for timeout for now
|
|
11
|
+
searches = env[:request_body].count("\n") / 2
|
|
12
|
+
# do not allow timeout to exceed Searchkick.timeout
|
|
13
|
+
timeout = [Searchkick.search_timeout * searches, Searchkick.timeout].min
|
|
14
|
+
env[:request][:timeout] = timeout
|
|
15
|
+
end
|
|
16
|
+
@app.call(env)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
module Searchkick
|
|
2
|
+
module Model
|
|
3
|
+
def searchkick(**options)
|
|
4
|
+
options = Searchkick.model_options.deep_merge(options)
|
|
5
|
+
|
|
6
|
+
if options[:conversions]
|
|
7
|
+
Searchkick.warn("The `conversions` option is deprecated in favor of `conversions_v2`, which provides much better search performance. Upgrade to `conversions_v2` or rename `conversions` to `conversions_v1`")
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
if options.key?(:conversions_v1)
|
|
11
|
+
options[:conversions] = options.delete(:conversions_v1)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
unknown_keywords = options.keys - [:_all, :_type, :batch_size, :callbacks, :callback_options, :case_sensitive, :conversions, :conversions_v2, :deep_paging, :default_fields,
|
|
15
|
+
:filterable, :geo_shape, :highlight, :ignore_above, :index_name, :index_prefix, :inheritance, :job_options, :knn, :language,
|
|
16
|
+
:locations, :mappings, :match, :max_result_window, :merge_mappings, :routing, :searchable, :search_synonyms, :settings, :similarity,
|
|
17
|
+
:special_characters, :stem, :stemmer, :stem_conversions, :stem_exclusion, :stemmer_override, :suggest, :synonyms, :text_end,
|
|
18
|
+
:text_middle, :text_start, :unscope, :word, :word_end, :word_middle, :word_start]
|
|
19
|
+
raise ArgumentError, "unknown keywords: #{unknown_keywords.join(", ")}" if unknown_keywords.any?
|
|
20
|
+
|
|
21
|
+
raise "Only call searchkick once per model" if respond_to?(:searchkick_index)
|
|
22
|
+
|
|
23
|
+
Searchkick.models << self
|
|
24
|
+
|
|
25
|
+
options[:_type] ||= -> { searchkick_index.klass_document_type(self, true) }
|
|
26
|
+
options[:class_name] = model_name.name
|
|
27
|
+
|
|
28
|
+
callbacks = options.key?(:callbacks) ? options[:callbacks] : :inline
|
|
29
|
+
unless [:inline, true, false, :async, :queue].include?(callbacks)
|
|
30
|
+
raise ArgumentError, "Invalid value for callbacks"
|
|
31
|
+
end
|
|
32
|
+
callback_options = (options[:callback_options] || {}).dup
|
|
33
|
+
callback_options[:if] = [-> { Searchkick.callbacks?(default: callbacks) }, callback_options[:if]].compact.flatten(1)
|
|
34
|
+
|
|
35
|
+
base = self
|
|
36
|
+
|
|
37
|
+
mod = Module.new
|
|
38
|
+
include(mod)
|
|
39
|
+
mod.module_eval do
|
|
40
|
+
def reindex(method_name = nil, mode: nil, refresh: false, ignore_missing: nil, job_options: nil)
|
|
41
|
+
self.class.searchkick_index.reindex([self], method_name: method_name, mode: mode, refresh: refresh, ignore_missing: ignore_missing, job_options: job_options, single: true)
|
|
42
|
+
end unless base.method_defined?(:reindex)
|
|
43
|
+
|
|
44
|
+
def similar(**options)
|
|
45
|
+
self.class.searchkick_index.similar_record(self, **options)
|
|
46
|
+
end unless base.method_defined?(:similar)
|
|
47
|
+
|
|
48
|
+
def search_data
|
|
49
|
+
data = respond_to?(:to_hash) ? to_hash : serializable_hash
|
|
50
|
+
data.delete("id")
|
|
51
|
+
data.delete("_id")
|
|
52
|
+
data.delete("_type")
|
|
53
|
+
data
|
|
54
|
+
end unless base.method_defined?(:search_data)
|
|
55
|
+
|
|
56
|
+
def should_index?
|
|
57
|
+
true
|
|
58
|
+
end unless base.method_defined?(:should_index?)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
class_eval do
|
|
62
|
+
cattr_reader :searchkick_options, :searchkick_klass, instance_reader: false
|
|
63
|
+
|
|
64
|
+
class_variable_set :@@searchkick_options, options.dup
|
|
65
|
+
class_variable_set :@@searchkick_klass, self
|
|
66
|
+
class_variable_set :@@searchkick_index_cache, Searchkick::IndexCache.new
|
|
67
|
+
|
|
68
|
+
class << self
|
|
69
|
+
def searchkick_search(term = "*", **options, &block)
|
|
70
|
+
if Searchkick.relation?(self)
|
|
71
|
+
raise Searchkick::Error, "search must be called on model, not relation"
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
Searchkick.search(term, model: self, **options, &block)
|
|
75
|
+
end
|
|
76
|
+
alias_method Searchkick.search_method_name, :searchkick_search if Searchkick.search_method_name
|
|
77
|
+
|
|
78
|
+
def searchkick_index(name: nil)
|
|
79
|
+
index_name = name || searchkick_klass.searchkick_index_name
|
|
80
|
+
index_name = index_name.call if index_name.respond_to?(:call)
|
|
81
|
+
index_cache = class_variable_get(:@@searchkick_index_cache)
|
|
82
|
+
index_cache.fetch(index_name) { Searchkick::Index.new(index_name, searchkick_options) }
|
|
83
|
+
end
|
|
84
|
+
alias_method :search_index, :searchkick_index unless method_defined?(:search_index)
|
|
85
|
+
|
|
86
|
+
def searchkick_reindex(method_name = nil, **options)
|
|
87
|
+
searchkick_index.reindex(self, method_name: method_name, **options)
|
|
88
|
+
end
|
|
89
|
+
alias_method :reindex, :searchkick_reindex unless method_defined?(:reindex)
|
|
90
|
+
|
|
91
|
+
def searchkick_index_options
|
|
92
|
+
searchkick_index.index_options
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def searchkick_index_name
|
|
96
|
+
@searchkick_index_name ||= begin
|
|
97
|
+
options = class_variable_get(:@@searchkick_options)
|
|
98
|
+
if options[:index_name]
|
|
99
|
+
options[:index_name]
|
|
100
|
+
elsif options[:index_prefix].respond_to?(:call)
|
|
101
|
+
-> { [options[:index_prefix].call, model_name.plural, Searchkick.env, Searchkick.index_suffix].compact.join("_") }
|
|
102
|
+
else
|
|
103
|
+
[options.key?(:index_prefix) ? options[:index_prefix] : Searchkick.index_prefix, model_name.plural, Searchkick.env, Searchkick.index_suffix].compact.join("_")
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# always add callbacks, even when callbacks is false
|
|
110
|
+
# so Model.callbacks block can be used
|
|
111
|
+
if respond_to?(:after_commit)
|
|
112
|
+
after_commit :reindex, **callback_options
|
|
113
|
+
elsif respond_to?(:after_save)
|
|
114
|
+
after_save :reindex, **callback_options
|
|
115
|
+
after_destroy :reindex, **callback_options
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
module Searchkick
|
|
2
|
+
class MultiSearch
|
|
3
|
+
attr_reader :queries
|
|
4
|
+
|
|
5
|
+
def initialize(queries, opaque_id: nil)
|
|
6
|
+
@queries = queries
|
|
7
|
+
@opaque_id = opaque_id
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def perform
|
|
11
|
+
if queries.any?
|
|
12
|
+
perform_search(queries)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def perform_search(search_queries, perform_retry: true)
|
|
19
|
+
params = {
|
|
20
|
+
body: search_queries.flat_map { |q| [q.params.except(:body), q.body] }
|
|
21
|
+
}
|
|
22
|
+
params[:opaque_id] = @opaque_id if @opaque_id
|
|
23
|
+
responses = client.msearch(params)["responses"]
|
|
24
|
+
|
|
25
|
+
retry_queries = []
|
|
26
|
+
search_queries.each_with_index do |query, i|
|
|
27
|
+
if perform_retry && query.retry_misspellings?(responses[i])
|
|
28
|
+
query.send(:prepare) # okay, since we don't want to expose this method outside Searchkick
|
|
29
|
+
retry_queries << query
|
|
30
|
+
else
|
|
31
|
+
query.handle_response(responses[i])
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
if retry_queries.any?
|
|
36
|
+
perform_search(retry_queries, perform_retry: false)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
search_queries
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def client
|
|
43
|
+
Searchkick.client
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module Searchkick
|
|
2
|
+
class ProcessBatchJob < Searchkick.parent_job.constantize
|
|
3
|
+
queue_as { Searchkick.queue_name }
|
|
4
|
+
|
|
5
|
+
def perform(class_name:, record_ids:, index_name: nil)
|
|
6
|
+
model = Searchkick.load_model(class_name)
|
|
7
|
+
index = model.searchkick_index(name: index_name)
|
|
8
|
+
|
|
9
|
+
items =
|
|
10
|
+
record_ids.map do |r|
|
|
11
|
+
parts = r.split(/(?<!\|)\|(?!\|)/, 2)
|
|
12
|
+
.map { |v| v.gsub("||", "|") }
|
|
13
|
+
{id: parts[0], routing: parts[1]}
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
relation = Searchkick.scope(model)
|
|
17
|
+
RecordIndexer.new(index).reindex_items(relation, items, method_name: nil, ignore_missing: nil)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module Searchkick
|
|
2
|
+
class ProcessQueueJob < Searchkick.parent_job.constantize
|
|
3
|
+
queue_as { Searchkick.queue_name }
|
|
4
|
+
|
|
5
|
+
def perform(class_name:, index_name: nil, inline: false, job_options: nil)
|
|
6
|
+
model = Searchkick.load_model(class_name)
|
|
7
|
+
index = model.searchkick_index(name: index_name)
|
|
8
|
+
limit = model.searchkick_options[:batch_size] || 1000
|
|
9
|
+
job_options = (model.searchkick_options[:job_options] || {}).merge(job_options || {})
|
|
10
|
+
|
|
11
|
+
loop do
|
|
12
|
+
record_ids = index.reindex_queue.reserve(limit: limit)
|
|
13
|
+
if record_ids.any?
|
|
14
|
+
batch_options = {
|
|
15
|
+
class_name: class_name,
|
|
16
|
+
record_ids: record_ids.uniq,
|
|
17
|
+
index_name: index_name
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if inline
|
|
21
|
+
# use new.perform to avoid excessive logging
|
|
22
|
+
Searchkick::ProcessBatchJob.new.perform(**batch_options)
|
|
23
|
+
else
|
|
24
|
+
Searchkick::ProcessBatchJob.set(job_options).perform_later(**batch_options)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# TODO when moving to reliable queuing, mark as complete
|
|
28
|
+
end
|
|
29
|
+
break unless record_ids.size == limit
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|