repertoire-faceting 0.5.2 → 0.5.3

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.
@@ -21,13 +21,13 @@ module Repertoire
21
21
  module PostgreSQLAdapter #:nodoc:
22
22
 
23
23
  # Creates (or recreates) the packed id column on a given table
24
- def renumber_table(table_name, faceting_id='_packed_id')
25
- sql = "SELECT renumber_table('#{table_name}', '#{faceting_id}')"
24
+ def renumber_table(table_name, faceting_id, wastage)
25
+ sql = "SELECT renumber_table('#{table_name}', '#{faceting_id}', #{wastage})"
26
26
  execute(sql)
27
27
  end
28
28
 
29
29
  # Returns the scatter quotient of the given id column
30
- def signature_wastage(table_name, faceting_id='_packed_id')
30
+ def signature_wastage(table_name, faceting_id)
31
31
  sql = "SELECT signature_wastage('#{table_name}', '#{faceting_id}')"
32
32
  result = select_value(sql)
33
33
  Float(result)
@@ -88,15 +88,6 @@ module Repertoire
88
88
  "INNER JOIN members(#{exprs.join(' & ')}) AS _refinements_id ON (#{table_name}.#{faceting_id} = _refinements_id)"
89
89
  end
90
90
 
91
- private
92
-
93
- def ignoring_db_errors(&block)
94
- begin
95
- yield
96
- rescue
97
- end
98
- end
99
-
100
91
  end
101
92
  end
102
93
  end
@@ -2,10 +2,43 @@ module Repertoire
2
2
  module Faceting #:nodoc:
3
3
 
4
4
  # Include this mixin in your controller to add faceting webservices for use with the javascript
5
- # widgets. In general you will only need to over-ride base() to specify the model over which your
6
- # faceted browser searches.
5
+ # widgets. Implementors should over-ride base() to specify the model for the faceted browser.
6
+ #
7
+ # class PaintingsController
8
+ # include Repertoire::Faceting::Controller
9
+ # def base
10
+ # Painting
11
+ # end
12
+ # end
13
+ #
14
+ # By default two web services are defined, one for the facet value count widgets and another for
15
+ # the result widget. Each builds on the model returned by base():
16
+ #
17
+ # counts ==> base.refine(params[:filter]).count(params[:facet])
18
+ # results ==> base.refine(params[:filter]).to_a
19
+ #
20
+ # If desired, you can use the Model API to specify a query that limits the faceting context to
21
+ # a subset of the available items from the start:
22
+ #
23
+ # def base
24
+ # q = "#{params[:search]}%"
25
+ # Painting.where(["title like ?", q])
26
+ # end
27
+ #
28
+ # Finally, you are free to over-ride the counts() and results() webservices. Here we
29
+ # reorder the facet value counts depending on another webservice param:
30
+ #
31
+ # def counts
32
+ # facet = params[:facet]
33
+ # filter = params[:filter] || {}
34
+ # sorting = case params[:order]
35
+ # when 'alphanumeric' then ["#{facet} ASC"]
36
+ # when 'count' then ["count DESC", "#{facet} ASC"]
37
+ # end
38
+ # @counts = base.refine(filter).order(sorting).count(facet)
39
+ # render :json => @counts.to_a
40
+ # end
7
41
  #
8
- # However, for more complex behavior you can over-ride counts() and results() as well.
9
42
  module Controller
10
43
 
11
44
  # Web-service to return value, count pairs for a given facet, given existing filter refinements
@@ -3,6 +3,10 @@ module Repertoire
3
3
  module Model #:nodoc:
4
4
  extend ActiveSupport::Concern
5
5
 
6
+ SIGNATURE_WASTAGE_THRESHOLD = 0.15
7
+ DEFAULT_SIGNATURE_COLUMN = 'id'
8
+ PACKED_SIGNATURE_COLUMN = '_packed_id'
9
+
6
10
  included do |base|
7
11
  base.singleton_class.delegate :refine, :minimum, :nils, :reorder, :to_sql, :to => :scoped
8
12
  end
@@ -29,8 +33,8 @@ module Repertoire
29
33
  #
30
34
  # facet :discipline, group(:discipline)
31
35
  #
32
- # and the grouping on degree could be left out. You can use this to construct a facet from differently-
33
- # named columns:
36
+ # and the grouping on degree could be left out. You can use this behavior to construct a facet
37
+ # from differently-named columns:
34
38
  #
35
39
  # facet :balloon_color, group(:color)
36
40
  #
@@ -42,13 +46,13 @@ module Repertoire
42
46
  #
43
47
  # == Nested facets
44
48
  #
45
- # Facets can be constructed into a nested hierarchy of values by providing multiple group columns. In this
49
+ # Facets can be built from a nested hierarchy of values by providing multiple group columns. In this
46
50
  # case, value counts are aggregated at each level in turn.
47
51
  #
48
52
  # facet :birth_place, group(:birth_country, :birth_state, :birth_city)
49
53
  #
50
- # As for basic facets, nested facets can be constructed from SQL expressions. This is particularly useful in
51
- # faceting over data in more complex types such as dates or geographical regions.
54
+ # As for basic facets, nested facets may consist of SQL expressions. This is particularly useful in
55
+ # faceting over data in more complex types such as dates or geographical regions:
52
56
  #
53
57
  # facet :birth_date, group('EXTRACT(year FROM birthdate)', 'EXTRACT(month FROM birthdate)', 'EXTRACT(day FROM birthdate)')
54
58
  #
@@ -137,27 +141,45 @@ module Repertoire
137
141
  facets.keys
138
142
  end
139
143
 
140
- # Drops any unused facet indices, updates its packed ids, then recreates indices
141
- # for the facets with the provided names. If no names are provided, then the existing
142
- # facet indices are refreshed. For example:
144
+ # Drops any unused facet indices, updates its packed ids, then recreates
145
+ # indices for the facets with the provided names. If no names are provided,
146
+ # then the existing facet indices are refreshed.
147
+ #
148
+ # If a signature id column name is provided, it will be used to build the
149
+ # bitset indices. Otherwise the indexer will add or remove a new packed
150
+ # id column as appropriate.
151
+ #
152
+ # Examples:
143
153
  #
144
154
  # === Refresh existing facet indices
145
155
  #
146
156
  # Nobelist.update_indexed_facets
147
157
  #
148
- # === Drop all facet indices
158
+ # === Adjust which facets are indexed
159
+ #
160
+ # Nobelist.update_indexed_facets([:degree, :nobel_year])
161
+ #
162
+ # === Drop all facet indices, but add/remove packed id as necessary
149
163
  #
150
164
  # Nobelist.update_indexed_facets([])
151
165
  #
152
- # === Adjust which facets are indexed
166
+ # === Drop absolutely everything, force manual faceting using 'id'
167
+ # column
153
168
  #
154
- # Nobelist.update_indexed_facets([:degree, :nobel_year])
169
+ # Nobelist.udpate_indexed_facets([], 'id')
155
170
  #
156
- def update_indexed_facets(facet_names=nil)
171
+ def update_indexed_facets(facet_names=nil, signature_column=nil)
157
172
  # default: update existing facets
158
173
  indexed_facets = connection.indexed_facets(table_name)
159
174
  facet_names ||= indexed_facets
160
175
 
176
+ # determine best column for signature bitsets, unless set manually
177
+ signature_column ||= if signature_wastage('id') < SIGNATURE_WASTAGE_THRESHOLD
178
+ DEFAULT_SIGNATURE_COLUMN
179
+ else
180
+ PACKED_SIGNATURE_COLUMN
181
+ end
182
+
161
183
  connection.transaction do
162
184
  # drop old facet indices
163
185
  indexed_facets.each do |name|
@@ -165,18 +187,14 @@ module Repertoire
165
187
  connection.drop_table(table)
166
188
  end
167
189
 
168
- # update or drop the model packed id column
169
- if (facet_names.empty? && should_unpack?)
170
- connection.remove_column(table_name, '_packed_id')
171
- else
172
- connection.renumber_table(table_name, '_packed_id')
173
- end
190
+ # create or remove packed signature column as necessary
191
+ ensure_numbering(signature_column)
174
192
 
175
193
  # re-create the facet indices
176
194
  facet_names.each do |name|
177
195
  name = name.to_sym
178
196
  raise "Unknown facet #{name}" unless facet?(name)
179
- facets[name].create_index('_packed_id')
197
+ facets[name].create_index(signature_column)
180
198
  end
181
199
  end
182
200
 
@@ -186,7 +204,7 @@ module Repertoire
186
204
  # Returns the name of the id column to use for constructing bitset signatures
187
205
  # over this model.
188
206
  def faceting_id
189
- ['_packed_id', 'id'].detect { |c| column_names.include?(c) }
207
+ [PACKED_SIGNATURE_COLUMN, DEFAULT_SIGNATURE_COLUMN].detect { |c| column_names.include?(c) }
190
208
  end
191
209
 
192
210
  def signature_wastage(col=nil)
@@ -194,9 +212,14 @@ module Repertoire
194
212
  connection.signature_wastage(table_name, col)
195
213
  end
196
214
 
197
- def should_unpack?
198
- (faceting_id == '_packed_id') && (signature_wastage('id') < 0.15)
215
+ def ensure_numbering(signature_column)
216
+ if signature_column == DEFAULT_SIGNATURE_COLUMN
217
+ connection.remove_column(table_name, PACKED_SIGNATURE_COLUMN) if column_names.include?(PACKED_SIGNATURE_COLUMN)
218
+ else
219
+ connection.renumber_table(table_name, PACKED_SIGNATURE_COLUMN, SIGNATURE_WASTAGE_THRESHOLD)
220
+ end
199
221
  end
222
+
200
223
  end
201
224
  end
202
225
  end
@@ -1,16 +1,19 @@
1
1
  module Repertoire
2
2
  module Faceting #:nodoc:
3
+ #
4
+ # Standard routing extensions for Repertoire Faceting webservices.
5
+ #
6
+ # Example::Application.routes.draw do
7
+ # faceting_for :paintings
8
+ # end
9
+ #
10
+ # N.B. Include faceting routes before any resources!
11
+ #
3
12
  module Routing
4
13
 
5
14
  #
6
15
  # Add routes for the faceting webservices provided by the Controller mixin.
7
16
  #
8
- # Example::Application.routes.draw do
9
- # faceting_for :nobelists
10
- # end
11
- #
12
- # N.B. Include faceting routes before any resources!
13
- #
14
17
  def faceting_for(*controllers)
15
18
  options = controllers.extract_options!
16
19
 
@@ -25,4 +28,3 @@ module Repertoire
25
28
  end
26
29
  end
27
30
  end
28
-
@@ -1,5 +1,5 @@
1
1
  module Repertoire
2
2
  module Faceting #:nodoc:
3
- VERSION = "0.5.2"
3
+ VERSION = "0.5.3"
4
4
  end
5
5
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 5
8
- - 2
9
- version: 0.5.2
8
+ - 3
9
+ version: 0.5.3
10
10
  platform: ruby
11
11
  authors:
12
12
  - Christopher York
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-10-28 00:00:00 +01:00
17
+ date: 2010-11-03 00:00:00 +00:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency