indexes 0.0.1 → 4.0.0.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
  SHA1:
3
- metadata.gz: faa93cb564f7f71a3010f4916dc4d92f81fd594f
4
- data.tar.gz: 39befa425667065d4a45ce753f99ecce58258833
3
+ metadata.gz: b5563006cc938b7b0590e7979fc6c4ef5da6ef18
4
+ data.tar.gz: 64a3d9f1ced530ead478aae6354d4b374341bbfa
5
5
  SHA512:
6
- metadata.gz: ce9a43f8196973a30f58699bc301cad72335aea1d11f2b69ca1a8e6aceab80bd5654044ce2f081cea2ffcd2de4923abfcabbd730c25e8fdc21e77e059fc85aec
7
- data.tar.gz: f3ed34a51d459a4b49ca7848d422db677971e33cd7fb3fc4804c107bfc3a886cfaa8015d38ec5ac53c58c937e5b5eca0e36351de42059d2e712ca7996d7286cb
6
+ metadata.gz: fd39393556426f5ffcde4aa3281089dd681b5dfd6eb52ef34270a99ed7a2d12fea661caab391bd32a23f33605aa9fe11c29f5e3add2f34f54d7fadd5b673e0be
7
+ data.tar.gz: 2e8fb3183fe2713156897df745e5fc392b35f303890639a2112fe9abe35eedd7a47cfc89c0fdd9dddc18ec5c6c6c3c38d8b0c3d9a2c302db53133032ef9e1f5e
data/README.md CHANGED
@@ -38,7 +38,7 @@ NOTE: This gem is tested agains version 2.4.
38
38
 
39
39
  ## Configuration
40
40
 
41
- Run the install generator:
41
+ Generate the configuration file:
42
42
  ```
43
43
  $ bundle exec rails g indexes:install
44
44
  ```
@@ -70,43 +70,17 @@ Indexes.configure do |config|
70
70
  end
71
71
  end
72
72
 
73
- config.analysis do
74
- filter do
75
- ngram do
76
- type 'nGram'
77
- min_gram 2
78
- max_gram 20
79
- end
80
- end
81
- end
82
-
83
- config.suggestions do |name, term, options={}|
84
- type = name.to_s.singularize
85
- text (term || '')
86
- completion do
87
- field "#{type}_suggestions"
88
- end
89
- end
90
-
91
- config.add_computed_sort :price do |direction|
92
- _script do
93
- type 'number'
94
- script do
95
- inline "if (_source.currency == 'UYU') { doc['price'].value * 30 }"
96
- end
97
- order direction
98
- end
99
- end
100
-
101
73
  end
102
74
  ```
103
75
 
76
+ ### Definitions
77
+
104
78
  Generate an index:
105
79
  ```
106
- $ bundle exec rails g indexes:index products
80
+ $ bundle exec rails g index products
107
81
  ```
108
82
 
109
- Define the index:
83
+ Define the mappings, serialization and search in the index:
110
84
  ```ruby
111
85
  Indexes.define :products do
112
86
 
@@ -114,8 +88,8 @@ Indexes.define :products do
114
88
  properties :name, :category, :price, :product_suggestions
115
89
  end
116
90
 
117
- serializer do |record|
118
- set record, :name, :category, :price
91
+ serialization do |record|
92
+ extract record, :name, :category, :price
119
93
  product_suggestions do
120
94
  input [record.name, transliterate(record.name)].uniq
121
95
  output record.name
@@ -141,97 +115,143 @@ Indexes.define :products do
141
115
  end
142
116
  ```
143
117
 
144
- ## Usage
118
+ If you need to personalize the analysis, you have to add it to the configuration:
119
+
120
+ ```ruby
121
+ Indexes.configure do |config|
122
+
123
+ config.analysis do
124
+ filter do
125
+ ngram do
126
+ type 'nGram'
127
+ min_gram 2
128
+ max_gram 20
129
+ end
130
+ end
131
+ analyzer do
132
+ ngram do
133
+ type 'custom'
134
+ tokenizer 'standard'
135
+ filter %w(lowercase ngram)
136
+ end
137
+ end
138
+ end
139
+
140
+ end
141
+ ```
145
142
 
146
143
  ### Indexing
147
144
 
148
- Ocurrs everytime you create, update or destroy a record:
145
+ The index will be updated every time a record is created, updated or destroyed:
149
146
  ```ruby
150
147
  product = Product.create(name: 'Les Paul', category: 'Gibson')
151
148
  ```
152
149
 
153
- You can force it manually by:
150
+ You can force this actions manually with:
154
151
  ```ruby
155
152
  product.index
156
153
  product.reindex
157
154
  product.unindex
158
155
  ```
159
156
 
160
- At any time you can force a full rebuild:
161
- ```
162
- $ bundle exec rake indexes:rebuild
163
- ```
157
+ ### Rake tasks
164
158
 
165
- Or if you need just a build:
159
+ At any time you can build/rebuild your indexes using:
166
160
  ```
167
161
  $ bundle exec rake indexes:build
162
+ $ bundle exec rake indexes:rebuild
168
163
  ```
169
164
 
170
165
  ### Search
171
166
 
172
- The search parameters are sent to previous configured block:
167
+ Use the included search method in the model:
173
168
  ```ruby
174
- products = Product.search(name: 'Test')
169
+ products = Product.search('Les Paul')
175
170
  ```
176
171
 
177
- You can use the returned value as a collection in views:
172
+ The result can be used as a collection in views:
178
173
  ```erb
179
174
  <%= render products %>
180
175
  ```
181
176
 
182
177
  ### Includes
183
178
 
184
- Same as using activerecord relations:
179
+ Similar to using activerecod:
185
180
  ```ruby
186
- Product.search(includes: :shop)
181
+ Product.search.includes(:shop)
187
182
  ```
188
183
 
189
184
  ### With / Without
190
185
 
191
186
  You can force a record to be part of the results by id:
192
187
  ```ruby
193
- Product.search(with: 4)
188
+ Products.search.with(4)
194
189
  ```
195
190
 
196
191
  Or the opposite:
197
192
  ```ruby
198
- Product.search(without: 4)
193
+ Products.search.without(4)
199
194
  ```
200
195
 
201
196
  ### Pagination
202
197
 
203
198
  Works the same as [pagers gem](https://github.com/mmontossi/pagers):
204
199
  ```ruby
205
- products.page 1, padding: 4, length: 30
200
+ Products.search.page(1, padding: 4, length: 30)
206
201
  ```
207
202
 
208
- And you can send the collection directly to the helper in views:
203
+ And you can send the collection directly to the view helper:
209
204
  ```erb
210
205
  <%= paginate products %>
211
206
  ```
212
207
 
213
208
  ### Order
214
209
 
215
- Works the same as in relations:
210
+ Same as using activerecord:
216
211
  ```ruby
217
- products.order(name: :asc)
212
+ Product.search.order(name: :asc)
218
213
  ```
219
214
 
220
- To use a computed_sort:
215
+ You can use a computed sort by declare it in the configuration:
221
216
  ```ruby
222
- products.order(price: :asc)
223
- ```
217
+ Indexes.configure do |config|
224
218
 
225
- NOTE: To sort by a string column, you must declare the mapping raw.
219
+ config.computed_sort :price do |direction|
220
+ _script do
221
+ type 'number'
222
+ script do
223
+ inline "if (_source.currency == 'UYU') { doc['price'].value * 30 }"
224
+ end
225
+ order direction
226
+ end
227
+ end
228
+
229
+ end
230
+ ```
226
231
 
227
232
  ### Suggestions
228
233
 
229
- The suggestion parameters are sent to previous configured block:
234
+ You need to first define the logic in the configuration:
235
+ ```ruby
236
+ Indexes.configure do |config|
237
+
238
+ config.suggestions do |name, term, options={}|
239
+ type = name.to_s.singularize
240
+ text (term || '')
241
+ completion do
242
+ field "#{type}_suggestions"
243
+ end
244
+ end
245
+
246
+ end
247
+ ```
248
+
249
+ Then you can get suggestions using the suggest method:
230
250
  ```ruby
231
251
  Indexes.suggest :products, 'gibson'
232
252
  ```
233
253
 
234
- Returns array of hashes with a text property:
254
+ The result is an array of hashes with a text property:
235
255
  ```ruby
236
256
  [{ text: 'Les Paul' }, ...]
237
257
  ```
@@ -2,7 +2,7 @@ require 'rails/generators'
2
2
 
3
3
  module Indexes
4
4
  module Generators
5
- class IndexGenerator < Rails::Generators::NamedBase
5
+ class IndexGenerator < ::Rails::Generators::NamedBase
6
6
 
7
7
  source_root File.expand_path('../templates', __FILE__)
8
8
 
@@ -3,7 +3,7 @@ Indexes.define :<%= table_name %> do
3
3
  mappings do
4
4
  end
5
5
 
6
- serializer do |record|
6
+ serialization do |record|
7
7
  end
8
8
 
9
9
  search do |*args|
@@ -2,7 +2,7 @@ require 'rails/generators'
2
2
 
3
3
  module Indexes
4
4
  module Generators
5
- class InstallGenerator < Rails::Generators::Base
5
+ class InstallGenerator < ::Rails::Generators::Base
6
6
 
7
7
  source_root File.expand_path('../templates', __FILE__)
8
8
 
@@ -1,16 +1,15 @@
1
- require 'generators/indexes/index_generator'
2
- require 'generators/indexes/install_generator'
3
1
  require 'indexes/dsl/api'
4
2
  require 'indexes/dsl/mappings'
5
3
  require 'indexes/dsl/search'
6
- require 'indexes/dsl/serializer'
4
+ require 'indexes/dsl/serialization'
5
+ require 'indexes/collection'
7
6
  require 'indexes/concern'
8
7
  require 'indexes/configuration'
8
+ require 'indexes/definitions'
9
9
  require 'indexes/index'
10
10
  require 'indexes/pagination'
11
11
  require 'indexes/proxy'
12
12
  require 'indexes/railtie'
13
- require 'indexes/collection'
14
13
  require 'indexes/version'
15
14
 
16
15
  module Indexes
@@ -41,22 +40,12 @@ module Indexes
41
40
  @configuration ||= Configuration.new
42
41
  end
43
42
 
44
- def define(*args, &block)
45
- Proxy.new *args, &block
46
- end
47
-
48
- def add(*args)
49
- index = Index.new(*args)
50
- registry[index.name] = index
43
+ def definitions
44
+ @definitions ||= Definitions.new
51
45
  end
52
46
 
53
- def find(name)
54
- registry[name]
55
- end
56
- alias_method :[], :find
57
-
58
- def each(&block)
59
- registry.values.sort.each &block
47
+ def define(*args, &block)
48
+ Proxy.new *args, &block
60
49
  end
61
50
 
62
51
  def build
@@ -66,11 +55,7 @@ module Indexes
66
55
  body: { settings: configuration.analysis }
67
56
  )
68
57
  end
69
- each &:build
70
- end
71
-
72
- def exist?(type)
73
- client.indices.exists? index: namespace, type: type
58
+ definitions.each &:build
74
59
  end
75
60
 
76
61
  def rebuild
@@ -78,6 +63,10 @@ module Indexes
78
63
  build
79
64
  end
80
65
 
66
+ def exist?(type)
67
+ client.indices.exists? index: namespace, type: type
68
+ end
69
+
81
70
  def destroy
82
71
  if client.indices.exists?(index: namespace)
83
72
  client.indices.delete index: namespace
@@ -92,11 +81,5 @@ module Indexes
92
81
  response['suggestions'].first['options'].map &:symbolize_keys
93
82
  end
94
83
 
95
- private
96
-
97
- def registry
98
- @registry ||= {}
99
- end
100
-
101
84
  end
102
85
  end
@@ -8,17 +8,29 @@ module Indexes
8
8
 
9
9
  alias_method :to_ary, :to_a
10
10
 
11
- def initialize(index, *args, &block)
11
+ def initialize(index, args=[], options={}, &block)
12
12
  @loaded = false
13
13
  @index = index
14
- @options = args.extract_options!
15
14
  @args = args
15
+ @options = options
16
16
  @block = block
17
17
  end
18
18
 
19
+ def with(ids)
20
+ chain with: ids
21
+ end
22
+
23
+ def without(ids)
24
+ chain without: ids
25
+ end
26
+
27
+ def includes(*args)
28
+ chain includes: args
29
+ end
30
+
19
31
  def page(number, options={})
20
- length = (fetch_option(options, :length) || 10)
21
- padding = (fetch_option(options, :padding) || 0)
32
+ length = page_option(options, :length, 10)
33
+ padding = page_option(options, :padding, 0)
22
34
  current_page = [number.to_i, 1].max
23
35
  values = Module.new do
24
36
  define_method :page_length do
@@ -31,32 +43,28 @@ module Indexes
31
43
  current_page
32
44
  end
33
45
  end
34
- overrides = {
46
+ chain(
47
+ Pagination,
48
+ values,
35
49
  from: ((length * (current_page - 1)) + padding),
36
50
  size: length
37
- }
38
- %i(with without).each do |name|
39
- if options.has_key?(name)
40
- overrides[name] = options[name]
41
- end
42
- end
43
- chain Pagination, values, overrides
51
+ )
44
52
  end
45
53
 
46
54
  def order(options)
47
55
  mappings = Indexes.configuration.mappings
48
- sort = []
56
+ values = []
49
57
  options.each do |property, direction|
50
58
  if block = Indexes.configuration.computed_sorts[property]
51
- sort << Dsl::Api.new(direction, &block).to_h
59
+ values << Dsl::Api.new(direction, &block).to_h
52
60
  elsif property == :id
53
- sort << { _uid: { order: direction } }
61
+ values << { _uid: { order: direction } }
54
62
  elsif mappings.has_key?(property) && mappings[property][:type] == 'string'
55
- sort << { "#{property}.raw" => { order: direction } }
63
+ values << { "#{property}.raw" => { order: direction } }
56
64
  end
57
65
  end
58
- if sort.any?
59
- chain sort: sort
66
+ if values.any?
67
+ chain sort: values
60
68
  else
61
69
  chain
62
70
  end
@@ -75,7 +83,7 @@ module Indexes
75
83
  @query ||= begin
76
84
  pagination = options.slice(:from, :size, :sort)
77
85
  without_ids = fetch_ids(options[:without])
78
- body = Dsl::Search.new(args.append(options), &block).to_h[:query]
86
+ body = Dsl::Search.new(args, &block).to_h[:query]
79
87
  request = Dsl::Search.new do
80
88
  if without_ids.any?
81
89
  query do
@@ -97,9 +105,9 @@ module Indexes
97
105
  else
98
106
  query body
99
107
  end
100
- %i(from size).each do |option|
101
- if pagination.has_key?(option)
102
- send option, pagination[option]
108
+ %i(from size).each do |name|
109
+ if pagination.has_key?(name)
110
+ send name, pagination[name]
103
111
  end
104
112
  end
105
113
  if pagination.has_key?(:sort)
@@ -122,47 +130,30 @@ module Indexes
122
130
 
123
131
  def records
124
132
  @records ||= begin
133
+ hit_ids = response['hits']['hits'].map{ |hit| hit['_id'].to_i }
134
+ missing_ids = (fetch_ids(options[:with]) - hit_ids)
125
135
  if missing_ids.any?
126
136
  last_index = -(missing_ids.length + 1)
127
137
  ids = (missing_ids.sort.reverse + hit_ids.to(last_index))
128
138
  else
129
139
  ids = hit_ids
130
140
  end
141
+ includes = options.fetch(:includes, [])
131
142
  index.model.includes(includes).where(id: ids).sort do |a,b|
132
143
  ids.index(a.id) <=> ids.index(b.id)
133
144
  end
134
145
  end
135
146
  end
136
147
 
137
- def with_ids
138
- @with_ids ||= fetch_ids(options[:with])
139
- end
140
-
141
- def hit_ids
142
- @hit_ids ||= response['hits']['hits'].map{ |hit| hit['_id'].to_i }
143
- end
144
-
145
- def missing_ids
146
- @missing_ids ||= (with_ids - hit_ids)
147
- end
148
-
149
- def includes
150
- @inclues ||= begin
151
- if options.has_key?(:includes)
152
- Array options[:includes]
153
- else
154
- []
155
- end
156
- end
157
- end
158
-
159
- def fetch_option(options, name)
160
- options[name] || begin
148
+ def page_option(source, name, default)
149
+ source[name] || begin
161
150
  if Rails.configuration.cache_classes == false
162
151
  Rails.application.eager_load!
163
152
  end
164
153
  if defined?(Pagers)
165
- Pagers.config[name]
154
+ Pagers.configuration.send name
155
+ else
156
+ default
166
157
  end
167
158
  end
168
159
  end
@@ -184,11 +175,11 @@ module Indexes
184
175
 
185
176
  def chain(*extensions)
186
177
  overrides = extensions.extract_options!
187
- Collection.new(index, *args.append(options.merge(overrides)), &block).tap do |collection|
188
- extensions.each do |extension|
189
- collection.extend extension
190
- end
178
+ collection = Collection.new(index, args, options.merge(overrides), &block)
179
+ extensions.each do |extension|
180
+ collection.extend extension
191
181
  end
182
+ collection
192
183
  end
193
184
 
194
185
  end