search_flip 2.1.0 → 2.2.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cda3eb59fdf7fabf986510c923cbded7f6a1219d734be60a406265d7ec685893
4
- data.tar.gz: a30be3c6195e1864b4a37899e079e096129692ec0bb5ac0f78a0cceaf15468a2
3
+ metadata.gz: b506132a3198cb96d7afad2e2a6b7b3eb3af73bdb18452459045379d4dde41bc
4
+ data.tar.gz: 31354cd6f2f715529351fb74e1577382f7c245e381d95f411bbbb1c0a0aeef1d
5
5
  SHA512:
6
- metadata.gz: df70d9f06aecbd84e7a5cb1ec16ffdd408a53da7a08f15fac4761a2e70b38b667ee4688abe7d81195eb6389e6decf2b591689a7002b75ca28cae16f8fa5bb88b
7
- data.tar.gz: f903399ac8baa4b4a41ebcf3d378b64fbae236a553dc975b90b3c13a9b50e39bdbc6508a6098884510205ae42a55bf057a94f2fa73a4906a5d053d4f86ac7ba8
6
+ metadata.gz: 6da9d91a867a2e50cd9ca3abb4784e41019a9980e3c78a6e55c1297190666a2e9bf6b7d0d43aa5431b1252eba5eb3de68d40491377788db4c09dc40579318ed2
7
+ data.tar.gz: e9be5d2dd82077f093eb07550cdf469d2aba1dfc8f205c26d96ae95e4cbe0be7d0e36b1bc44f9667a3151212cfb949761ef8fe8f8c5fd2a11cc7b10a8d29948e
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
- # SearchFlip
2
+ # search_flip
3
3
 
4
4
  **Full-Featured ElasticSearch Ruby Client with a Chainable DSL**
5
5
 
@@ -235,11 +235,17 @@ CommentIndex.where(username: "mrkamel").total_entries
235
235
  CommentIndex.aggregate(:username).aggregations(:username)
236
236
  # => {1=>#<SearchFlip::Result doc_count=37 ...>, 2=>... }
237
237
  ...
238
+ ```
239
+
240
+ Please note that you can check the request that will be send to Elasticsearch
241
+ by simply calling `#request` on the query:
238
242
 
243
+ ```ruby
239
244
  CommentIndex.search("hello world").sort(id: "desc").aggregate(:username).request
240
245
  # => {:query=>{:bool=>{:must=>[{:query_string=>{:query=>"hello world", :default_operator=>:AND}}]}}, ...}
241
246
  ```
242
247
 
248
+
243
249
  delete records:
244
250
 
245
251
  ```ruby
@@ -292,7 +298,7 @@ within `update_aliases`.
292
298
  Please note that `with_settings(index_name: '...')` returns an anonymous, i.e.
293
299
  temporary, class inherting from UserIndex and overwriting `index_name`.
294
300
 
295
- ## Advanced Usage
301
+ ## Chainable Methods
296
302
 
297
303
  SearchFlip supports even more advanced usages, like e.g. post filters, filtered
298
304
  aggregations or nested aggregations via simple to use API methods.
@@ -303,8 +309,7 @@ SearchFlip provides powerful methods to query/filter Elasticsearch:
303
309
 
304
310
  * `where`
305
311
 
306
- Feels like ActiveRecord's `where` and performs a bool filter clause
307
- to the request:
312
+ Feels like ActiveRecord's `where` and adds a bool filter clause to the request:
308
313
 
309
314
  ```ruby
310
315
  CommentIndex.where(reviewed: true)
@@ -371,13 +376,14 @@ CommentIndex.must_not(term: { state: "approved" })
371
376
 
372
377
  * `search`
373
378
 
374
- Adds a query string query, with AND as default filter:
379
+ Adds a query string query, with AND as default operator:
375
380
 
376
381
  ```ruby
377
- CommentIndex.search("harry potter")
382
+ CommentIndex.search("hello world")
378
383
  CommentIndex.search("state:approved")
379
384
  CommentIndex.search("username:a*")
380
385
  CommentIndex.search("state:approved OR state:rejected")
386
+ CommentIndex.search("hello world", default_operator: "OR")
381
387
  ```
382
388
 
383
389
  * `exists`
@@ -430,9 +436,9 @@ query = OrderIndex.aggregate(:username, order: { revenue: "desc" }) do |aggregat
430
436
  end
431
437
  ```
432
438
 
433
- Generally, aggregation results returned by ElasticSearch are wrapped in a
434
- `SearchFlip::Result`, which wraps a `Hashie::Mash`such that you can access them
435
- via:
439
+ Generally, aggregation results returned by ElasticSearch are returned as a
440
+ `SearchFlip::Result`, which basically is `Hashie::Mash`such that you can access
441
+ them via:
436
442
 
437
443
  ```ruby
438
444
  query.aggregations(:username)["mrkamel"].revenue.value
@@ -488,8 +494,8 @@ query.results[0]._hit.highlight.title # => "<em>hello</em> world"
488
494
 
489
495
  ### Other Criteria Methods
490
496
 
491
- There are so many chainable criteria methods to make your life easier.
492
- For a full list, checkout the reference docs.
497
+ There are even more chainable criteria methods to make your life easier. For a
498
+ full list, checkout the reference docs.
493
499
 
494
500
  * `source`
495
501
 
@@ -512,21 +518,6 @@ CommentIndex.paginate(page: 3, per_page: 50)
512
518
  CommentIndex.page(3).per(50)
513
519
  ```
514
520
 
515
- * `scroll`
516
-
517
- You can as well use the underlying scroll API directly, ie. without using higher
518
- level pagination:
519
-
520
- ```ruby
521
- query = CommentIndex.scroll(timeout: "5m")
522
-
523
- until query.records.empty?
524
- # ...
525
-
526
- query = query.scroll(id: query.scroll_id, timeout: "5m")
527
- end
528
- ```
529
-
530
521
  * `profile`
531
522
 
532
523
  Use `#profile` to enable query profiling:
@@ -577,8 +568,8 @@ end
577
568
 
578
569
  * `find_results_in_batches`
579
570
 
580
- Used like `find_in_batches`, but yielding the raw results instead of database
581
- records. Again, the batch size and scroll API timeout can be specified.
571
+ Used like `find_in_batches`, but yielding the raw results (as
572
+ `SearchFlip::Result` objects) instead of database records.
582
573
 
583
574
  ```ruby
584
575
  CommentIndex.search("hello world").find_results_in_batches(batch_size: 100) do |batch|
@@ -588,8 +579,7 @@ end
588
579
 
589
580
  * `find_each`
590
581
 
591
- Like `#find_in_batches`, use `#find_each` to fetch records in batches, but yields
592
- one record at a time.
582
+ Like `#find_in_batches` but yielding one record at a time.
593
583
 
594
584
  ```ruby
595
585
  CommentIndex.search("hello world").find_each(batch_size: 100) do |record|
@@ -597,6 +587,31 @@ CommentIndex.search("hello world").find_each(batch_size: 100) do |record|
597
587
  end
598
588
  ```
599
589
 
590
+ * `find_each_result`
591
+
592
+ Like `#find_results_in_batches`, but yielding one record at a time.
593
+
594
+ ```ruby
595
+ CommentIndex.search("hello world").find_each_result(batch_size: 100) do |batch|
596
+ # ...
597
+ end
598
+ ```
599
+
600
+ * `scroll`
601
+
602
+ You can as well use the underlying scroll API directly, ie. without using higher
603
+ level scrolling:
604
+
605
+ ```ruby
606
+ query = CommentIndex.scroll(timeout: "5m")
607
+
608
+ until query.records.empty?
609
+ # ...
610
+
611
+ query = query.scroll(id: query.scroll_id, timeout: "5m")
612
+ end
613
+ ```
614
+
600
615
  * `failsafe`
601
616
 
602
617
  Use `#failsafe` to prevent any exceptions from being raised for query string
@@ -622,14 +637,6 @@ CommentIndex.where(approved: true).merge(CommentIndex.search("hello"))
622
637
  # equivalent to: CommentIndex.where(approved: true).search("hello")
623
638
  ```
624
639
 
625
- * `unscope`
626
-
627
- You can even remove certain already added scopes via `#unscope`:
628
-
629
- ```ruby
630
- CommentIndex.aggregate(:username).search("hello world").unscope(:search, :aggregate)
631
- ```
632
-
633
640
  * `timeout`
634
641
 
635
642
  Specify a timeout to limit query processing time:
@@ -649,6 +656,33 @@ CommentIndex.terminate_after(10).execute
649
656
 
650
657
  For further details and a full list of methods, check out the reference docs.
651
658
 
659
+ * `custom`
660
+
661
+ You can add a custom clause to the request via `custom`
662
+
663
+ ```ruby
664
+ CommentIndex.custom(custom_clause: '...')
665
+ ```
666
+
667
+ This can be useful for Elasticsearch features not yet supported via criteria
668
+ methods by SearchFlip, custom plugin clauses, etc.
669
+
670
+ ### Custom Criteria Methods
671
+
672
+ To add custom criteria methods, you can add class methods to your index class.
673
+
674
+ ```ruby
675
+ class HotelIndex
676
+ # ...
677
+
678
+ def self.where_geo(lat:, lon:, distance:)
679
+ filter(geo_distance: { distance: distance, location: { lat: lat, lon: lon } })
680
+ end
681
+ end
682
+
683
+ HotelIndex.search("bed and breakfast").where_geo(lat: 53.57532, lon: 10.01534, distance: '50km').aggregate(:rating)
684
+ ```
685
+
652
686
  ## Using multiple Elasticsearch clusters
653
687
 
654
688
  To use multiple Elasticsearch clusters, specify a connection within your
@@ -669,6 +703,26 @@ end
669
703
  This allows to use different clusters per index e.g. when migrating indices to
670
704
  new versions of Elasticsearch.
671
705
 
706
+ You can specify basic auth, additional headers, etc via:
707
+
708
+ ```ruby
709
+ http_client = SearchFlip::HTTPClient.new
710
+
711
+ # Basic Auth
712
+ http_client = http_client.basic_auth(user: "username", pass: "password")
713
+
714
+ # Raw Auth Header
715
+ http_client = http_client.auth("Bearer VGhlIEhUVFAgR2VtLCBST0NLUw")
716
+
717
+ # Proxy Settings
718
+ http_client = http_client.via("proxy.host", 8080)
719
+
720
+ # Custom headers
721
+ http_client = http_client.headers(key: "value")
722
+
723
+ SearchFlip::Connection.new(base_url: "...", http_client: http_client)
724
+ ```
725
+
672
726
  ## Routing and other index-time options
673
727
 
674
728
  Override `index_options` in case you want to use routing or pass other
@@ -712,8 +766,9 @@ class MyIndex
712
766
  end
713
767
  ```
714
768
 
715
- Thus, simply add your custom implementation of those methods that work with
716
- whatever ORM you use.
769
+ Thus, if your ORM supports `.find_each`, `#id` and `#where` you are already
770
+ good to go. Otherwise, simply add your custom implementation of those methods
771
+ that work with whatever ORM you use.
717
772
 
718
773
  ## Date and Timestamps in JSON
719
774
 
@@ -764,10 +819,11 @@ require "search_flip/to_json"
764
819
 
765
820
  ## Feature Support
766
821
 
767
- * `#post_search` and `#profile` are only supported from up to ElasticSearch
822
+ * `#post_search` and `#profile` are only supported from up to Elasticsearch
768
823
  version >= 2.
769
- * for ElasticSearch 2.x, the delete-by-query plugin is required to delete
824
+ * for Elasticsearch 2.x, the delete-by-query plugin is required to delete
770
825
  records via queries
826
+ * `#track_total_hits` is only available with Elasticsearch >= 7
771
827
 
772
828
  ## Keeping your Models and Indices in Sync
773
829
 
data/UPDATING.md CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  ## Update 1.x to 2.x
5
5
 
6
- * **[BREAKING]** No longer include the mapping in `SearchFlip::Index.mapping`
6
+ * **[BREAKING]** No longer include the `type_name` in `SearchFlip::Index.mapping`
7
7
 
8
8
  1.x:
9
9
 
@@ -22,7 +22,7 @@ module SearchFlip
22
22
  attr_accessor :target, :profile_value, :source_value, :sort_values, :highlight_values, :suggest_values,
23
23
  :offset_value, :limit_value, :includes_values, :eager_load_values, :preload_values, :failsafe_value,
24
24
  :scroll_args, :custom_value, :terminate_after_value, :timeout_value, :preference_value,
25
- :search_type_value, :routing_value
25
+ :search_type_value, :routing_value, :track_total_hits_value
26
26
 
27
27
  # Creates a new criteria while merging the attributes (constraints,
28
28
  # settings, etc) of the current criteria with the attributes of another one
@@ -51,6 +51,7 @@ module SearchFlip
51
51
  criteria.preference_value = other.preference_value if other.preference_value
52
52
  criteria.search_type_value = other.search_type_value if other.search_type_value
53
53
  criteria.routing_value = other.routing_value if other.routing_value
54
+ criteria.track_total_hits_value = other.track_total_hits_value unless other.track_total_hits_value.nil?
54
55
 
55
56
  criteria.sort_values = (criteria.sort_values || []) + other.sort_values if other.sort_values
56
57
  criteria.includes_values = (criteria.includes_values || []) + other.includes_values if other.includes_values
@@ -74,6 +75,23 @@ module SearchFlip
74
75
  end
75
76
  end
76
77
 
78
+ # Specifies if or how many hits should be counted/tracked. Check out the
79
+ # elasticsearch docs for futher details.
80
+ #
81
+ # @example
82
+ # CommentIndex.track_total_hits(true)
83
+ # CommentIndex.track_total_hits(10_000)
84
+ #
85
+ # @param value The value for track_total_hits
86
+ #
87
+ # @return [SearchFlip::Criteria] A newly created extended criteria
88
+
89
+ def track_total_hits(value)
90
+ fresh.tap do |criteria|
91
+ criteria.track_total_hits_value = value
92
+ end
93
+ end
94
+
77
95
  # Specifies a preference value for the request. Check out the elasticsearch
78
96
  # docs for further details.
79
97
  #
@@ -167,6 +185,8 @@ module SearchFlip
167
185
  # @return [SearchFlip::Criteria] A newly created extended criteria
168
186
 
169
187
  def unscope(*scopes)
188
+ warn "[DEPRECATION] unscope is deprecated"
189
+
170
190
  unknown = scopes - [:search, :post_search, :sort, :highlight, :suggest, :custom, :aggregate]
171
191
 
172
192
  raise(ArgumentError, "Can't unscope #{unknown.join(", ")}") if unknown.size > 0
@@ -260,6 +280,7 @@ module SearchFlip
260
280
 
261
281
  res.update from: offset_value_with_default, size: limit_value_with_default
262
282
 
283
+ res[:track_total_hits] = track_total_hits_value unless track_total_hits_value.nil?
263
284
  res[:timeout] = timeout_value if timeout_value
264
285
  res[:terminate_after] = terminate_after_value if terminate_after_value
265
286
  res[:highlight] = highlight_values if highlight_values
@@ -254,7 +254,8 @@ module SearchFlip
254
254
  :includes, :eager_load, :preload, :sort, :resort, :order, :reorder, :offset, :limit, :paginate,
255
255
  :page, :per, :search, :highlight, :suggest, :custom, :find_in_batches, :find_results_in_batches,
256
256
  :find_each, :find_each_result, :failsafe, :total_entries, :total_count, :timeout, :terminate_after,
257
- :records, :results, :should, :should_not, :must, :must_not, :preference, :search_type, :routing
257
+ :records, :results, :should, :should_not, :must, :must_not, :preference, :search_type, :routing,
258
+ :track_total_hits
258
259
 
259
260
  # Override to specify the type name used within ElasticSearch. Recap,
260
261
  # this gem uses an individual index for each index class, because
@@ -1,5 +1,5 @@
1
1
 
2
2
  module SearchFlip
3
- VERSION = "2.1.0"
3
+ VERSION = "2.2.0"
4
4
  end
5
5
 
data/logo.svg ADDED
@@ -0,0 +1,96 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <!-- Generated by IcoMoon.io -->
3
+
4
+ <svg
5
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
6
+ xmlns:cc="http://creativecommons.org/ns#"
7
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
8
+ xmlns:svg="http://www.w3.org/2000/svg"
9
+ xmlns="http://www.w3.org/2000/svg"
10
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
11
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
12
+ version="1.1"
13
+ width="300"
14
+ height="50"
15
+ viewBox="0 0 299.99998 50"
16
+ id="svg4869"
17
+ sodipodi:docname="logo.svg"
18
+ inkscape:export-filename="/home/hkf/projects/search_flip/logo.png"
19
+ inkscape:export-xdpi="299.34824"
20
+ inkscape:export-ydpi="299.34824"
21
+ inkscape:version="0.92.1 r15371">
22
+ <metadata
23
+ id="metadata4875">
24
+ <rdf:RDF>
25
+ <cc:Work
26
+ rdf:about="">
27
+ <dc:format>image/svg+xml</dc:format>
28
+ <dc:type
29
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
30
+ <dc:title>arrow-long-up</dc:title>
31
+ </cc:Work>
32
+ </rdf:RDF>
33
+ </metadata>
34
+ <defs
35
+ id="defs4873" />
36
+ <sodipodi:namedview
37
+ pagecolor="#ffffff"
38
+ bordercolor="#666666"
39
+ borderopacity="1"
40
+ objecttolerance="10"
41
+ gridtolerance="10"
42
+ guidetolerance="10"
43
+ inkscape:pageopacity="0"
44
+ inkscape:pageshadow="2"
45
+ inkscape:window-width="1920"
46
+ inkscape:window-height="971"
47
+ id="namedview4871"
48
+ showgrid="false"
49
+ fit-margin-top="0"
50
+ fit-margin-left="0"
51
+ fit-margin-right="0"
52
+ fit-margin-bottom="0"
53
+ inkscape:zoom="2.085965"
54
+ inkscape:cx="91.987216"
55
+ inkscape:cy="-41.606043"
56
+ inkscape:window-x="0"
57
+ inkscape:window-y="31"
58
+ inkscape:window-maximized="1"
59
+ inkscape:current-layer="svg4869" />
60
+ <title
61
+ id="title4865">arrow-long-up</title>
62
+ <path
63
+ d="M 39.922489,4.151999 36.230955,18.361869 32.37339,14.504302 10.209748,36.667943 7.4576271,33.915823 29.621268,11.75218 25.712619,7.843531 Z"
64
+ id="path4867"
65
+ inkscape:connector-curvature="0"
66
+ style="stroke-width:1.80568123"
67
+ inkscape:export-xdpi="325.4834"
68
+ inkscape:export-ydpi="325.4834"
69
+ sodipodi:nodetypes="cccccccc"
70
+ inkscape:export-filename="/home/hkf/projects/search_flip/text4908.png" />
71
+ <path
72
+ d="M 17.625202,45.376517 31.473864,41.323778 27.948317,37.696072 50.111962,15.532428 47.418207,12.940838 25.254566,35.10448 21.677941,31.527854 Z"
73
+ id="path4867-7"
74
+ inkscape:connector-curvature="0"
75
+ style="stroke-width:1.74257004"
76
+ inkscape:export-xdpi="325.4834"
77
+ inkscape:export-ydpi="325.4834"
78
+ sodipodi:nodetypes="cccccccc"
79
+ inkscape:export-filename="/home/hkf/projects/search_flip/text4908.png" />
80
+ <text
81
+ xml:space="preserve"
82
+ style="font-style:normal;font-weight:normal;font-size:96.44345093px;line-height:1.25;font-family:sans-serif;letter-spacing:-0.65099335px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.41108632"
83
+ x="59.037937"
84
+ y="37.501484"
85
+ id="text4908"
86
+ inkscape:export-filename="/home/hkf/projects/search_flip/text4908.png"
87
+ inkscape:export-xdpi="325.4834"
88
+ inkscape:export-ydpi="325.4834"
89
+ inkscape:transform-center-x="-2.0432889"
90
+ inkscape:transform-center-y="-9.8078108"><tspan
91
+ sodipodi:role="line"
92
+ id="tspan4906"
93
+ x="59.037937"
94
+ y="37.501484"
95
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:51.43650818px;line-height:6;font-family:'times new roman';-inkscape-font-specification:'times new roman, ';letter-spacing:0px;word-spacing:-19.48158455px;stroke-width:2.41108632">search_flip</tspan></text>
96
+ </svg>
@@ -36,7 +36,7 @@ RSpec.describe SearchFlip::Criteria do
36
36
  methods = [
37
37
  :profile_value, :failsafe_value, :terminate_after_value, :timeout_value,
38
38
  :offset_value, :limit_value, :scroll_args, :source_value, :preference_value,
39
- :search_type_value, :routing_value
39
+ :search_type_value, :routing_value, :track_total_hits_value
40
40
  ]
41
41
 
42
42
  methods.each do |method|
@@ -1025,6 +1025,16 @@ RSpec.describe SearchFlip::Criteria do
1025
1025
  end
1026
1026
  end
1027
1027
 
1028
+ describe "#track_total_hits" do
1029
+ it "is added to the request" do
1030
+ if ProductIndex.connection.version.to_i >= 7
1031
+ query = ProductIndex.track_total_hits(false)
1032
+ expect(query.request[:track_total_hits]).to eq(false)
1033
+ expect { query.execute }.not_to raise_error
1034
+ end
1035
+ end
1036
+ end
1037
+
1028
1038
  describe "#custom" do
1029
1039
  it "adds a custom entry to the request" do
1030
1040
  request = ProductIndex.custom(custom_key: "custom_value").request
@@ -14,7 +14,8 @@ RSpec.describe SearchFlip::Index do
14
14
  :find_in_batches, :highlight, :suggest, :custom, :find_each, :failsafe,
15
15
  :total_entries, :total_count, :terminate_after, :timeout, :records, :results,
16
16
  :should, :should_not, :must, :must_not, :find_each_result,
17
- :find_results_in_batches, :preference, :search_type, :routing
17
+ :find_results_in_batches, :preference, :search_type, :routing,
18
+ :track_total_hits
18
19
  ]
19
20
 
20
21
  methods.each do |method|
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: 2.1.0
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Benjamin Vetter
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-05-10 00:00:00.000000000 Z
11
+ date: 2019-05-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -199,6 +199,7 @@ files:
199
199
  - lib/search_flip/result.rb
200
200
  - lib/search_flip/to_json.rb
201
201
  - lib/search_flip/version.rb
202
+ - logo.svg
202
203
  - search_flip.gemspec
203
204
  - spec/delegate_matcher.rb
204
205
  - spec/search_flip/aggregation_spec.rb