indexes 0.0.1 → 4.0.0.0

Sign up to get free protection for your applications and to get access to all the features.
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