search_flip 3.0.0.beta4 → 3.0.0.beta5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1 -0
- data/README.md +25 -1
- data/lib/search_flip/aggregation.rb +2 -1
- data/lib/search_flip/config.rb +2 -1
- data/lib/search_flip/criteria.rb +72 -59
- data/lib/search_flip/null_instrumenter.rb +21 -0
- data/lib/search_flip/version.rb +1 -1
- data/lib/search_flip.rb +1 -0
- data/spec/search_flip/criteria_spec.rb +42 -0
- data/spec/search_flip/null_instrumenter_spec.rb +43 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4fae82bf67967306afbb6bfb0f2f321b8993fa364710b24dc7b3860f2bb6ace0
|
4
|
+
data.tar.gz: a060faa2ea3b06233dc132b65df0e4c2bc18ab51ea5cfe92eadd96aaa7c8ddbf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 15aa25cab455dfadead099deb59594580f9c09f71476818f28d483a7d7e8cb3decfd7c4126ecfaf438b92ed19ded8edfe01566d4cffcd1a03394608b66db9ebb
|
7
|
+
data.tar.gz: 3a57bc2cecc98641c32f33c688576c7c808482bde3e3f9901590c7241102ef8a01d22f1dd875bd56d60c32fc9d38d4f97fd95e2f54249ccb2699c1ddc35a1e06
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -274,7 +274,7 @@ CommentIndex.create(Comment.first, { bulk_max_mb: 100 }, routing: "routing_key")
|
|
274
274
|
CommentIndex.update(Comment.first, ...)
|
275
275
|
```
|
276
276
|
|
277
|
-
Checkout the
|
277
|
+
Checkout the Elasticsearch [Bulk API] docs for more info as well as
|
278
278
|
[SearchFlip::Bulk](http://www.rubydoc.info/github/mrkamel/search_flip/SearchFlip/Bulk)
|
279
279
|
for a complete list of available options to control the bulk indexing of
|
280
280
|
SearchFlip.
|
@@ -790,6 +790,30 @@ end
|
|
790
790
|
|
791
791
|
These options will be passed whenever records get indexed, deleted, etc.
|
792
792
|
|
793
|
+
## Instrumentation
|
794
|
+
|
795
|
+
SearchFlip supports instrumentation for request execution via
|
796
|
+
`ActiveSupport::Notifications` compatible instrumenters to e.g. allow global
|
797
|
+
performance tracing, etc.
|
798
|
+
|
799
|
+
To use instrumentation, configure the instrumenter:
|
800
|
+
|
801
|
+
```ruby
|
802
|
+
SearchFlip::Config[:instrumenter] = ActiveSupport::Notifications.notifier
|
803
|
+
```
|
804
|
+
|
805
|
+
Subsequently, you can subscribe to notifcations for `request.search_flip`:
|
806
|
+
|
807
|
+
```ruby
|
808
|
+
ActiveSupport::Notifications.subscribe("request.search_flip") do |name, start, finish, id, payload|
|
809
|
+
payload[:index] # the index class
|
810
|
+
payload[:request] # the request hash sent to Elasticsearch
|
811
|
+
payload[:response] # the SearchFlip::Response object or nil in case of errors
|
812
|
+
end
|
813
|
+
```
|
814
|
+
|
815
|
+
A notification will be send for every request that is sent to Elasticsearch.
|
816
|
+
|
793
817
|
## Non-ActiveRecord models
|
794
818
|
|
795
819
|
SearchFlip ships with built-in support for ActiveRecord models, but using
|
@@ -73,7 +73,8 @@ module SearchFlip
|
|
73
73
|
unsupported_methods = [
|
74
74
|
:profile_value, :failsafe_value, :terminate_after_value, :timeout_value, :scroll_args,
|
75
75
|
:suggest_values, :includes_values, :preload_values, :eager_load_values, :post_must_values,
|
76
|
-
:post_must_not_values, :post_filter_values, :preference_value, :search_type_value,
|
76
|
+
:post_must_not_values, :post_filter_values, :preference_value, :search_type_value,
|
77
|
+
:routing_value
|
77
78
|
]
|
78
79
|
|
79
80
|
unsupported_methods.each do |unsupported_method|
|
data/lib/search_flip/config.rb
CHANGED
data/lib/search_flip/criteria.rb
CHANGED
@@ -219,45 +219,47 @@ module SearchFlip
|
|
219
219
|
# @return [Hash] The generated request object
|
220
220
|
|
221
221
|
def request
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
222
|
+
@request ||= begin
|
223
|
+
res = {}
|
224
|
+
|
225
|
+
if must_values || must_not_values || filter_values
|
226
|
+
res[:query] = {
|
227
|
+
bool: {
|
228
|
+
must: must_values.to_a,
|
229
|
+
must_not: must_not_values.to_a,
|
230
|
+
filter: filter_values.to_a
|
231
|
+
}.reject { |_, value| value.empty? }
|
232
|
+
}
|
233
|
+
end
|
233
234
|
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
235
|
+
res.update(from: offset_value_with_default, size: limit_value_with_default)
|
236
|
+
|
237
|
+
res[:track_total_hits] = track_total_hits_value unless track_total_hits_value.nil?
|
238
|
+
res[:explain] = explain_value unless explain_value.nil?
|
239
|
+
res[:timeout] = timeout_value if timeout_value
|
240
|
+
res[:terminate_after] = terminate_after_value if terminate_after_value
|
241
|
+
res[:highlight] = highlight_values if highlight_values
|
242
|
+
res[:suggest] = suggest_values if suggest_values
|
243
|
+
res[:sort] = sort_values if sort_values
|
244
|
+
res[:aggregations] = aggregation_values if aggregation_values
|
245
|
+
|
246
|
+
if post_must_values || post_must_not_values || post_filter_values
|
247
|
+
res[:post_filter] = {
|
248
|
+
bool: {
|
249
|
+
must: post_must_values.to_a,
|
250
|
+
must_not: post_must_not_values.to_a,
|
251
|
+
filter: post_filter_values.to_a
|
252
|
+
}.reject { |_, value| value.empty? }
|
253
|
+
}
|
254
|
+
end
|
254
255
|
|
255
|
-
|
256
|
-
|
256
|
+
res[:_source] = source_value unless source_value.nil?
|
257
|
+
res[:profile] = true if profile_value
|
257
258
|
|
258
|
-
|
259
|
+
res.update(custom_value) if custom_value
|
259
260
|
|
260
|
-
|
261
|
+
res
|
262
|
+
end
|
261
263
|
end
|
262
264
|
|
263
265
|
# Adds a suggestion section with the given name to the request.
|
@@ -520,30 +522,13 @@ module SearchFlip
|
|
520
522
|
|
521
523
|
def execute
|
522
524
|
@response ||= begin
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
json: { scroll: scroll_args[:timeout], scroll_id: scroll_args[:id] }
|
531
|
-
)
|
532
|
-
elsif scroll_args
|
533
|
-
http_request.post(
|
534
|
-
"#{target.type_url}/_search",
|
535
|
-
params: request_params.merge(scroll: scroll_args[:timeout]),
|
536
|
-
json: request
|
537
|
-
)
|
538
|
-
else
|
539
|
-
http_request.post("#{target.type_url}/_search", params: request_params, json: request)
|
540
|
-
end
|
541
|
-
|
542
|
-
SearchFlip::Response.new(self, http_response.parse)
|
543
|
-
rescue SearchFlip::ConnectionError, SearchFlip::ResponseError => e
|
544
|
-
raise e unless failsafe_value
|
545
|
-
|
546
|
-
SearchFlip::Response.new(self, "took" => 0, "hits" => { "total" => 0, "hits" => [] })
|
525
|
+
Config[:instrumenter].instrument("request.search_flip", index: target, request: request) do |payload|
|
526
|
+
response = execute!
|
527
|
+
|
528
|
+
payload[:response] = response
|
529
|
+
|
530
|
+
response
|
531
|
+
end
|
547
532
|
end
|
548
533
|
end
|
549
534
|
|
@@ -585,6 +570,7 @@ module SearchFlip
|
|
585
570
|
|
586
571
|
def fresh
|
587
572
|
dup.tap do |criteria|
|
573
|
+
criteria.instance_variable_set(:@request, nil)
|
588
574
|
criteria.instance_variable_set(:@response, nil)
|
589
575
|
end
|
590
576
|
end
|
@@ -610,6 +596,33 @@ module SearchFlip
|
|
610
596
|
|
611
597
|
private
|
612
598
|
|
599
|
+
def execute!
|
600
|
+
http_request = connection.http_client.headers(accept: "application/json")
|
601
|
+
|
602
|
+
http_response =
|
603
|
+
if scroll_args && scroll_args[:id]
|
604
|
+
http_request.post(
|
605
|
+
"#{connection.base_url}/_search/scroll",
|
606
|
+
params: request_params,
|
607
|
+
json: { scroll: scroll_args[:timeout], scroll_id: scroll_args[:id] }
|
608
|
+
)
|
609
|
+
elsif scroll_args
|
610
|
+
http_request.post(
|
611
|
+
"#{target.type_url}/_search",
|
612
|
+
params: request_params.merge(scroll: scroll_args[:timeout]),
|
613
|
+
json: request
|
614
|
+
)
|
615
|
+
else
|
616
|
+
http_request.post("#{target.type_url}/_search", params: request_params, json: request)
|
617
|
+
end
|
618
|
+
|
619
|
+
SearchFlip::Response.new(self, http_response.parse)
|
620
|
+
rescue SearchFlip::ConnectionError, SearchFlip::ResponseError => e
|
621
|
+
raise e unless failsafe_value
|
622
|
+
|
623
|
+
SearchFlip::Response.new(self, "took" => 0, "hits" => { "total" => 0, "hits" => [] })
|
624
|
+
end
|
625
|
+
|
613
626
|
def yield_in_batches(options = {})
|
614
627
|
return enum_for(:yield_in_batches, options) unless block_given?
|
615
628
|
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module SearchFlip
|
2
|
+
class NullInstrumenter
|
3
|
+
def instrument(name, payload = {})
|
4
|
+
start(name, payload)
|
5
|
+
|
6
|
+
begin
|
7
|
+
yield(payload) if block_given?
|
8
|
+
ensure
|
9
|
+
finish(name, payload)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def start(_name, _payload)
|
14
|
+
true
|
15
|
+
end
|
16
|
+
|
17
|
+
def finish(_name, _payload)
|
18
|
+
true
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/search_flip/version.rb
CHANGED
data/lib/search_flip.rb
CHANGED
@@ -1198,9 +1198,12 @@ RSpec.describe SearchFlip::Criteria do
|
|
1198
1198
|
|
1199
1199
|
query = ProductIndex.criteria.tap(&:records)
|
1200
1200
|
|
1201
|
+
expect(query.instance_variable_get(:@request)).not_to be_nil
|
1201
1202
|
expect(query.instance_variable_get(:@response)).not_to be_nil
|
1202
1203
|
|
1203
1204
|
expect(query.object_id).not_to eq(query.fresh.object_id)
|
1205
|
+
|
1206
|
+
expect(query.fresh.instance_variable_get(:@request)).to be_nil
|
1204
1207
|
expect(query.fresh.instance_variable_get(:@response)).to be_nil
|
1205
1208
|
end
|
1206
1209
|
end
|
@@ -1234,10 +1237,49 @@ RSpec.describe SearchFlip::Criteria do
|
|
1234
1237
|
end
|
1235
1238
|
end
|
1236
1239
|
|
1240
|
+
describe "#execute" do
|
1241
|
+
around do |example|
|
1242
|
+
default_instrumenter = SearchFlip::Config[:instrumenter]
|
1243
|
+
|
1244
|
+
SearchFlip::Config[:instrumenter] = ActiveSupport::Notifications.instrumenter
|
1245
|
+
|
1246
|
+
begin
|
1247
|
+
example.run
|
1248
|
+
ensure
|
1249
|
+
SearchFlip::Config[:instrumenter] = default_instrumenter
|
1250
|
+
end
|
1251
|
+
end
|
1252
|
+
|
1253
|
+
let(:notifications) { [] }
|
1254
|
+
|
1255
|
+
let!(:subscriber) do
|
1256
|
+
ActiveSupport::Notifications.subscribe("request.search_flip") do |*args|
|
1257
|
+
notifications << args
|
1258
|
+
end
|
1259
|
+
end
|
1260
|
+
|
1261
|
+
after { ActiveSupport::Notifications.unsubscribe(subscriber) }
|
1262
|
+
|
1263
|
+
it "instruments the request" do
|
1264
|
+
ProductIndex.match_all.execute
|
1265
|
+
|
1266
|
+
expect(notifications).to be_present
|
1267
|
+
end
|
1268
|
+
|
1269
|
+
it "passes the index, request and response" do
|
1270
|
+
ProductIndex.match_all.execute
|
1271
|
+
|
1272
|
+
expect(notifications.first[4][:index]).to eq(ProductIndex)
|
1273
|
+
expect(notifications.first[4][:request]).to be_present
|
1274
|
+
expect(notifications.first[4][:response]).to be_present
|
1275
|
+
end
|
1276
|
+
end
|
1277
|
+
|
1237
1278
|
describe "#track_total_hits" do
|
1238
1279
|
it "is added to the request" do
|
1239
1280
|
if ProductIndex.connection.version.to_i >= 7
|
1240
1281
|
query = ProductIndex.track_total_hits(false)
|
1282
|
+
|
1241
1283
|
expect(query.request[:track_total_hits]).to eq(false)
|
1242
1284
|
expect { query.execute }.not_to raise_error
|
1243
1285
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require File.expand_path("../spec_helper", __dir__)
|
2
|
+
|
3
|
+
RSpec.describe SearchFlip::NullInstrumenter do
|
4
|
+
subject { described_class.new }
|
5
|
+
|
6
|
+
describe "#instrument" do
|
7
|
+
it "calls start" do
|
8
|
+
allow(subject).to receive(:start)
|
9
|
+
|
10
|
+
subject.instrument("name", { key: "value" }) {}
|
11
|
+
|
12
|
+
expect(subject).to have_received(:start)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "calls finish" do
|
16
|
+
allow(subject).to receive(:finish)
|
17
|
+
|
18
|
+
subject.instrument("name", { key: "value" }) {}
|
19
|
+
|
20
|
+
expect(subject).to have_received(:finish)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "yields and passes the payload" do
|
24
|
+
yielded_payload = nil
|
25
|
+
|
26
|
+
subject.instrument("name", { key: "value" }) { |payload| yielded_payload = payload }
|
27
|
+
|
28
|
+
expect(yielded_payload).to eq(key: "value")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "#start" do
|
33
|
+
it "returns true" do
|
34
|
+
expect(subject.start("name", { key: "value" })).to eq(true)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "#finish" do
|
39
|
+
it "returns true" do
|
40
|
+
expect(subject.finish("name", { key: "value" })).to eq(true)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: search_flip
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.0.0.
|
4
|
+
version: 3.0.0.beta5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Benjamin Vetter
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-05-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -212,6 +212,7 @@ files:
|
|
212
212
|
- lib/search_flip/index.rb
|
213
213
|
- lib/search_flip/json.rb
|
214
214
|
- lib/search_flip/model.rb
|
215
|
+
- lib/search_flip/null_instrumenter.rb
|
215
216
|
- lib/search_flip/paginatable.rb
|
216
217
|
- lib/search_flip/post_filterable.rb
|
217
218
|
- lib/search_flip/response.rb
|
@@ -229,6 +230,7 @@ files:
|
|
229
230
|
- spec/search_flip/http_client_spec.rb
|
230
231
|
- spec/search_flip/index_spec.rb
|
231
232
|
- spec/search_flip/model_spec.rb
|
233
|
+
- spec/search_flip/null_instrumenter_spec.rb
|
232
234
|
- spec/search_flip/response_spec.rb
|
233
235
|
- spec/search_flip/result_spec.rb
|
234
236
|
- spec/search_flip/to_json_spec.rb
|
@@ -268,6 +270,7 @@ test_files:
|
|
268
270
|
- spec/search_flip/http_client_spec.rb
|
269
271
|
- spec/search_flip/index_spec.rb
|
270
272
|
- spec/search_flip/model_spec.rb
|
273
|
+
- spec/search_flip/null_instrumenter_spec.rb
|
271
274
|
- spec/search_flip/response_spec.rb
|
272
275
|
- spec/search_flip/result_spec.rb
|
273
276
|
- spec/search_flip/to_json_spec.rb
|