meilisearch-rails 0.11.1 → 0.13.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +1 -1
- data/README.md +55 -1
- data/lib/meilisearch/rails/multi_search/result.rb +84 -0
- data/lib/meilisearch/rails/multi_search.rb +49 -0
- data/lib/meilisearch/rails/utilities.rb +8 -0
- data/lib/meilisearch/rails/version.rb +1 -1
- data/lib/meilisearch-rails.rb +8 -6
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6f0751c88921f9665ac4a8d2f74d401c99eff1e1a82e16831196044725e8b01a
|
4
|
+
data.tar.gz: 4566fa5403529656cb21262456472fc4ec4d4c103ae750d2b48fc9076ff9c03c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b1302ec85a68c7774c2d31304738fbaec99845dd5993bfa2d414ac74e1647e833ffa624411670432cce4fb8335766bcfd684d04be4065397ef9d593692f0f080
|
7
|
+
data.tar.gz: 8b45f8cdd06fcf7b75f6d5d5dbffc1266650e69c8a30e49e018ca42f51bf7445b2ef8b357280691bea526628dfc7b0a40f0704f48c9545ba4e2933908e152d3f
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -38,6 +38,7 @@
|
|
38
38
|
- [Compatibility](#-compatibility)
|
39
39
|
- [⚙️ Settings](#️-settings)
|
40
40
|
- [🔍 Custom search](#-custom-search)
|
41
|
+
- [🔍🔍 Multi search](#-multi-search)
|
41
42
|
- [🪛 Options](#-options)
|
42
43
|
- [Meilisearch configuration & environment](#meilisearch-configuration--environment)
|
43
44
|
- [Pagination with `kaminari` or `will_paginate`](#backend-pagination-with-kaminari-or-will_paginate-)
|
@@ -206,6 +207,7 @@ class Book < ApplicationRecord
|
|
206
207
|
crop_length 10
|
207
208
|
faceting max_values_per_facet: 2000
|
208
209
|
pagination max_total_hits: 1000
|
210
|
+
proximity_precision 'byWord'
|
209
211
|
end
|
210
212
|
end
|
211
213
|
```
|
@@ -229,7 +231,7 @@ harry_book.formatted # => {"id"=>"1", "name"=>"<em>Harry</em> Potter", "descript
|
|
229
231
|
👉 Don't forget that `attributes_to_highlight`, `attributes_to_crop`, and
|
230
232
|
`crop_length` can be set up in the `meilisearch` block of your model.
|
231
233
|
|
232
|
-
|
234
|
+
### 🔍 Sorted search
|
233
235
|
|
234
236
|
As an example of how to use the sort option, here is how you could achieve
|
235
237
|
returning all books sorted by title in ascending order:
|
@@ -240,6 +242,58 @@ Book.search('*', sort: ['title:asc'])
|
|
240
242
|
|
241
243
|
👉 Don't forget to set up the `sortable_attributes` option in the `meilisearch` block of your model.
|
242
244
|
|
245
|
+
## 🔍🔍 Multi search
|
246
|
+
|
247
|
+
Meilisearch supports searching multiple models at the same time (see [🔍 Custom search](#-custom-search) for search options):
|
248
|
+
|
249
|
+
```ruby
|
250
|
+
multi_search_results = MeiliSearch::Rails.multi_search(
|
251
|
+
Book => { q: 'Harry' },
|
252
|
+
Manga => { q: 'Attack' }
|
253
|
+
)
|
254
|
+
```
|
255
|
+
|
256
|
+
You can iterate through the results with `.each` or `.each_result`:
|
257
|
+
|
258
|
+
```erb
|
259
|
+
<% multi_search_results.each do |record| %>
|
260
|
+
<p><%= record.title %></p>
|
261
|
+
<p><%= record.author %></p>
|
262
|
+
<% end %>
|
263
|
+
|
264
|
+
<p>Harry Potter and the Philosopher's Stone</p>
|
265
|
+
<p>J. K. Rowling</p>
|
266
|
+
<p>Harry Potter and the Chamber of Secrets</p>
|
267
|
+
<p>J. K. Rowling</p>
|
268
|
+
<p>Attack on Titan</p>
|
269
|
+
<p>Iseyama</p>
|
270
|
+
```
|
271
|
+
|
272
|
+
```erb
|
273
|
+
<% multi_search_results.each_result do |klass, results| %>
|
274
|
+
<p><%= klass.name.pluralize %></p>
|
275
|
+
|
276
|
+
<ul>
|
277
|
+
<% results.each do |record| %>
|
278
|
+
<li><%= record.title %></li>
|
279
|
+
<% end %>
|
280
|
+
</ul>
|
281
|
+
<% end %>
|
282
|
+
|
283
|
+
|
284
|
+
<p>Books</p>
|
285
|
+
<ul>
|
286
|
+
<li>Harry Potter and the Philosopher's Stone</li>
|
287
|
+
<li>Harry Potter and the Chamber of Secrets</li>
|
288
|
+
</ul>
|
289
|
+
<p>Mangas</p>
|
290
|
+
<ul>
|
291
|
+
<li>Attack on Titan</li>
|
292
|
+
</ul>
|
293
|
+
```
|
294
|
+
|
295
|
+
See the [official multi search documentation](https://www.meilisearch.com/docs/reference/api/multi_search).
|
296
|
+
|
243
297
|
## 🪛 Options
|
244
298
|
|
245
299
|
### Meilisearch configuration & environment
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module MeiliSearch
|
2
|
+
module Rails
|
3
|
+
class MultiSearchResult
|
4
|
+
attr_reader :metadata
|
5
|
+
|
6
|
+
def initialize(searches, raw_results)
|
7
|
+
@results = {}
|
8
|
+
@metadata = {}
|
9
|
+
|
10
|
+
searches.zip(raw_results['results']).each do |(index_target, search_options), result|
|
11
|
+
index_target = search_options[:class_name].constantize if search_options[:class_name]
|
12
|
+
|
13
|
+
@results[index_target] = case index_target
|
14
|
+
when String, Symbol
|
15
|
+
result['hits']
|
16
|
+
else
|
17
|
+
load_results(index_target, result)
|
18
|
+
end
|
19
|
+
|
20
|
+
@metadata[index_target] = result.except('hits')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
include Enumerable
|
25
|
+
|
26
|
+
def each_hit(&block)
|
27
|
+
@results.each do |_index_target, results|
|
28
|
+
results.each(&block)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
alias each each_hit
|
32
|
+
|
33
|
+
def each_result
|
34
|
+
@results.each
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_a
|
38
|
+
@results.values.flatten(1)
|
39
|
+
end
|
40
|
+
alias to_ary to_a
|
41
|
+
|
42
|
+
def to_h
|
43
|
+
@results
|
44
|
+
end
|
45
|
+
alias to_hash to_h
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def load_results(klass, result)
|
50
|
+
pk_method = klass.ms_primary_key_method
|
51
|
+
pk_method = pk_method.in if Utilities.mongo_model?(klass)
|
52
|
+
|
53
|
+
condition_key = pk_is_virtual?(klass, pk_method) ? klass.primary_key : pk_method
|
54
|
+
|
55
|
+
hits_by_id =
|
56
|
+
result['hits'].index_by { |hit| hit[condition_key.to_s] }
|
57
|
+
|
58
|
+
records = klass.where(condition_key => hits_by_id.keys)
|
59
|
+
|
60
|
+
if records.respond_to? :in_order_of
|
61
|
+
records.in_order_of(condition_key, hits_by_id.keys).each do |record|
|
62
|
+
record.formatted = hits_by_id[record.send(condition_key).to_s]['_formatted']
|
63
|
+
end
|
64
|
+
else
|
65
|
+
results_by_id = records.index_by do |hit|
|
66
|
+
hit.send(condition_key).to_s
|
67
|
+
end
|
68
|
+
|
69
|
+
result['hits'].filter_map do |hit|
|
70
|
+
record = results_by_id[hit[condition_key.to_s].to_s]
|
71
|
+
record&.formatted = hit['_formatted']
|
72
|
+
record
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def pk_is_virtual?(model_class, pk_method)
|
78
|
+
model_class.columns
|
79
|
+
.map(&(Utilities.sequel_model?(model_class) ? :to_s : :name))
|
80
|
+
.exclude?(pk_method.to_s)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require_relative 'multi_search/result'
|
2
|
+
|
3
|
+
module MeiliSearch
|
4
|
+
module Rails
|
5
|
+
class << self
|
6
|
+
def multi_search(searches)
|
7
|
+
search_parameters = searches.map do |(index_target, options)|
|
8
|
+
paginate(options) if pagination_enabled?
|
9
|
+
normalize(options, index_target)
|
10
|
+
end
|
11
|
+
|
12
|
+
MultiSearchResult.new(searches, client.multi_search(search_parameters))
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def normalize(options, index_target)
|
18
|
+
options
|
19
|
+
.except(:class_name)
|
20
|
+
.merge!(index_uid: index_uid_from_target(index_target))
|
21
|
+
end
|
22
|
+
|
23
|
+
def index_uid_from_target(index_target)
|
24
|
+
case index_target
|
25
|
+
when String, Symbol
|
26
|
+
index_target
|
27
|
+
else
|
28
|
+
index_target.index.uid
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def paginate(options)
|
33
|
+
%w[page hitsPerPage hits_per_page].each do |key|
|
34
|
+
# Deletes hitsPerPage to avoid passing along a meilisearch-ruby warning/exception
|
35
|
+
value = options.delete(key) || options.delete(key.to_sym)
|
36
|
+
options[key.underscore.to_sym] = value.to_i if value
|
37
|
+
end
|
38
|
+
|
39
|
+
# It is required to activate the finite pagination in Meilisearch v0.30 (or newer),
|
40
|
+
# to have at least `hits_per_page` defined or `page` in the search request.
|
41
|
+
options[:page] ||= 1
|
42
|
+
end
|
43
|
+
|
44
|
+
def pagination_enabled?
|
45
|
+
MeiliSearch::Rails.configuration[:pagination_backend]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -48,6 +48,14 @@ module MeiliSearch
|
|
48
48
|
true
|
49
49
|
end
|
50
50
|
|
51
|
+
def mongo_model?(model_class)
|
52
|
+
defined?(::Mongoid::Document) && model_class.include?(::Mongoid::Document)
|
53
|
+
end
|
54
|
+
|
55
|
+
def sequel_model?(model_class)
|
56
|
+
defined?(::Sequel::Model) && model_class < Sequel::Model
|
57
|
+
end
|
58
|
+
|
51
59
|
private
|
52
60
|
|
53
61
|
def constraint_passes?(record, constraint)
|
data/lib/meilisearch-rails.rb
CHANGED
@@ -3,6 +3,7 @@ require 'meilisearch/rails/null_object'
|
|
3
3
|
require 'meilisearch/rails/version'
|
4
4
|
require 'meilisearch/rails/utilities'
|
5
5
|
require 'meilisearch/rails/errors'
|
6
|
+
require 'meilisearch/rails/multi_search'
|
6
7
|
|
7
8
|
if defined? Rails
|
8
9
|
begin
|
@@ -66,6 +67,7 @@ module MeiliSearch
|
|
66
67
|
pagination
|
67
68
|
faceting
|
68
69
|
typo_tolerance
|
70
|
+
proximity_precision
|
69
71
|
].freeze
|
70
72
|
|
71
73
|
CAMELIZE_OPTIONS = %i[pagination faceting typo_tolerance].freeze
|
@@ -575,7 +577,7 @@ module MeiliSearch
|
|
575
577
|
ms_configurations.filter_map do |options, settings|
|
576
578
|
{
|
577
579
|
synchronous: synchronous || options[:synchronous],
|
578
|
-
index_uid: options
|
580
|
+
index_uid: ms_index_uid(options),
|
579
581
|
primary_key: primary_key
|
580
582
|
}.with_indifferent_access unless ms_indexing_disabled?(options)
|
581
583
|
end
|
@@ -760,6 +762,11 @@ module MeiliSearch
|
|
760
762
|
false
|
761
763
|
end
|
762
764
|
|
765
|
+
def ms_primary_key_method(options = nil)
|
766
|
+
options ||= meilisearch_options
|
767
|
+
options[:primary_key] || options[:id] || :id
|
768
|
+
end
|
769
|
+
|
763
770
|
protected
|
764
771
|
|
765
772
|
def ms_ensure_init(options = meilisearch_options, settings = meilisearch_settings, user_configuration = settings.to_settings)
|
@@ -814,11 +821,6 @@ module MeiliSearch
|
|
814
821
|
@configurations
|
815
822
|
end
|
816
823
|
|
817
|
-
def ms_primary_key_method(options = nil)
|
818
|
-
options ||= meilisearch_options
|
819
|
-
options[:primary_key] || options[:id] || :id
|
820
|
-
end
|
821
|
-
|
822
824
|
def ms_primary_key_of(doc, options = nil)
|
823
825
|
doc.send(ms_primary_key_method(options)).to_s
|
824
826
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: meilisearch-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.13.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Meili
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-05-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: meilisearch
|
@@ -42,6 +42,8 @@ files:
|
|
42
42
|
- lib/meilisearch/rails/errors.rb
|
43
43
|
- lib/meilisearch/rails/ms_clean_up_job.rb
|
44
44
|
- lib/meilisearch/rails/ms_job.rb
|
45
|
+
- lib/meilisearch/rails/multi_search.rb
|
46
|
+
- lib/meilisearch/rails/multi_search/result.rb
|
45
47
|
- lib/meilisearch/rails/null_object.rb
|
46
48
|
- lib/meilisearch/rails/pagination.rb
|
47
49
|
- lib/meilisearch/rails/pagination/kaminari.rb
|