repertoire-faceting 0.5.1 → 0.5.2
Sign up to get free protection for your applications and to get access to all the features.
- data/FAQ +15 -0
- data/INSTALL +110 -85
- data/README +40 -142
- data/TODO +11 -2
- data/ext/README.signature +2 -2
- data/ext/signature.sql.IN +10 -6
- data/lib/repertoire-faceting/adapters/postgresql_adapter.rb +21 -0
- data/lib/repertoire-faceting/model.rb +1 -2
- data/lib/repertoire-faceting/rails/relation.rb +1 -1
- data/lib/repertoire-faceting/railtie.rb +2 -1
- data/lib/repertoire-faceting/tasks/all.rake +12 -0
- data/lib/repertoire-faceting/tasks/client.rake +12 -0
- data/lib/repertoire-faceting/version.rb +1 -1
- data/lib/repertoire-faceting.rb +2 -0
- metadata +6 -5
- data/lib/repertoire-faceting/tasks.rake +0 -29
data/FAQ
CHANGED
@@ -1,5 +1,14 @@
|
|
1
1
|
= Repertoire Faceting FAQ =
|
2
2
|
|
3
|
+
= Related questions
|
4
|
+
|
5
|
+
Q. Rails 3 refuses to update schema.rb because with my fulltext index columns.
|
6
|
+
|
7
|
+
A. Put the following line in environment.rb:
|
8
|
+
|
9
|
+
config.active_record.schema_format = :sql
|
10
|
+
|
11
|
+
|
3
12
|
= About facet indexing and the signature SQL type =
|
4
13
|
|
5
14
|
Q. What's the scalability of this thing?
|
@@ -18,6 +27,12 @@ A. Did you remember to call expand_nesting(<facet index table>, <facet name>) af
|
|
18
27
|
|
19
28
|
= About the ajax faceting widgets =
|
20
29
|
|
30
|
+
Q. A web page from the default Rails app refuses to load the faceting widgets.
|
31
|
+
|
32
|
+
A. Repertoire Faceting widgets are based on JQuery, which is incompatible with Prototype. You should remove
|
33
|
+
prototype.js and rails.js from the javascripts directory, and delete the <%= javascript_include_tag :defaults %>
|
34
|
+
line from application.html.erb.
|
35
|
+
|
21
36
|
Q. How do I send page-specific data (for example, a search field) to the webservice with the facet widgets' data?
|
22
37
|
|
23
38
|
A. If you provide a function to the facet_context plugin, it will merge the params you return before dispatching to
|
data/INSTALL
CHANGED
@@ -7,53 +7,55 @@
|
|
7
7
|
|
8
8
|
{ install native bitset extensions }
|
9
9
|
$ bundle install
|
10
|
-
$ rake faceting:
|
11
|
-
$
|
12
|
-
$ psql -f $(pg_config --sharedir)/contrib/signature.sql -U<username> <database>
|
10
|
+
$ rake db:faceting:build { provide sudo your password }
|
11
|
+
$ rake db:faceting:load
|
13
12
|
|
14
13
|
{ in ./app/models/some_model.rb }
|
15
14
|
class SomeModel
|
16
|
-
include Repertoire::Faceting::Model
|
17
|
-
facet :some_column
|
15
|
+
include Repertoire::Faceting::Model // 2
|
16
|
+
facet :some_column // 3
|
18
17
|
end
|
19
18
|
|
20
19
|
{ in ./app/controllers/some_controller]
|
21
20
|
class SomeController
|
22
|
-
include Repertoire::Faceting::Controller
|
23
|
-
def base; return SomeModel; end
|
21
|
+
include Repertoire::Faceting::Controller // 4
|
22
|
+
def base; return SomeModel; end // 5
|
24
23
|
end
|
25
24
|
|
26
25
|
{ in ./config/routes.rb }
|
27
26
|
SomeApp::Application.routes.draw do
|
28
|
-
faceting_for :some_model
|
27
|
+
faceting_for :some_model // 6
|
29
28
|
end
|
30
29
|
|
31
30
|
{ in ./public/javascripts/application.js }
|
32
|
-
//= require <rep.faceting>
|
31
|
+
//= require <rep.faceting> // 7
|
33
32
|
|
34
33
|
{ in ./app/views/some_controller/index.html.erb }
|
35
34
|
<script language="javascript">
|
36
35
|
$().ready(function() {
|
37
|
-
$('#paintings').facet_context(
|
38
|
-
$('.facet').facet();
|
39
|
-
$('#results').results();
|
36
|
+
$('#paintings').facet_context(); // 8
|
37
|
+
$('.facet').facet(); // 9
|
38
|
+
$('#results').results(); // 10
|
40
39
|
});
|
41
40
|
</script>
|
42
|
-
<div id='paintings'>
|
43
|
-
<div id='genre' class='facet'></div>
|
44
|
-
<div id='results'></div>
|
41
|
+
<div id='paintings'> // 11
|
42
|
+
<div id='genre' class='facet'></div> // 12
|
43
|
+
<div id='results'></div> // 13
|
45
44
|
</div>
|
46
45
|
|
47
|
-
... that's a complete faceted browser in only
|
46
|
+
... that's a complete faceted browser in only 13 new lines of code in your app!
|
48
47
|
|
49
|
-
In production, you will want to
|
48
|
+
In production, you will want to compress the javascript facet widgets:
|
50
49
|
|
51
50
|
{ in ./config/environments/production.rb }
|
52
51
|
config.repertoire_assets.compress = true
|
53
52
|
|
54
|
-
|
53
|
+
Additionally, you may wish to index the facets. At the console or in a migration:
|
55
54
|
|
56
|
-
|
55
|
+
SomeModel.update_indexed_facets([:some_column])
|
56
|
+
|
57
|
+
The faceting subsystem automatically detects available facet indices and uses
|
58
|
+
them when appropriate.
|
57
59
|
|
58
60
|
|
59
61
|
== Detailed version.
|
@@ -64,7 +66,8 @@ Start with a working Rails 3 application with a PostgreSQL database.
|
|
64
66
|
|
65
67
|
gem 'repertoire-faceting'
|
66
68
|
|
67
|
-
* Make sure you use Rails version 3.0.2+, which adopted Arel 2.0.1. If necessary
|
69
|
+
* Make sure you use Rails version 3.0.2+, which adopted Arel 2.0.1. If necessary
|
70
|
+
you can pull rails, arel, and rack from git.
|
68
71
|
|
69
72
|
gem 'rails', :git => 'git://github.com/rails/rails.git'
|
70
73
|
gem 'arel', :git => 'git://github.com/rails/arel.git'
|
@@ -74,29 +77,31 @@ Start with a working Rails 3 application with a PostgreSQL database.
|
|
74
77
|
|
75
78
|
$ bundle install
|
76
79
|
|
77
|
-
* From your application root, build and install the repertoire-faceting native
|
78
|
-
a bitwise signature type used to
|
80
|
+
* From your application root, build and install the repertoire-faceting native
|
81
|
+
extensions to PostgreSQL. These provide a bitwise signature type used to
|
82
|
+
index and count facets.
|
79
83
|
|
80
|
-
$ rake faceting:
|
84
|
+
$ rake db:faceting:build { sudo will prompt you for your password }
|
81
85
|
|
82
|
-
* Load the extension into application database.
|
86
|
+
* Load the extension into your local application database. This ensures the
|
87
|
+
plpgsql language is installed, and loads (or re-loads) the new bitset signature
|
88
|
+
type.
|
83
89
|
|
84
|
-
$
|
85
|
-
$ psql -f $(pg_config --sharedir)/contrib/signature.sql -U<username> <database>
|
90
|
+
$ rake db:faceting:load
|
86
91
|
|
87
|
-
You can confirm the module installed as follows.
|
92
|
+
You can confirm the module is installed as follows.
|
88
93
|
|
89
94
|
$ psql -c "SELECT count('101010101'::signature);" -U<username> <database>
|
90
|
-
|
91
|
-
If the module installed correctly, psql will respond with "5".
|
92
95
|
|
93
|
-
* Install the faceting mixin in your Rails model and declare a facet on an
|
94
|
-
|
96
|
+
* Install the faceting mixin in your Rails model and declare a facet on an
|
97
|
+
existing database column. (See the README for complete configuration options
|
98
|
+
for facets.)
|
95
99
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
+
{ ./app/models/painting.rb }
|
101
|
+
class Painting
|
102
|
+
include Repertoire::Faceting::Model
|
103
|
+
facet :genre
|
104
|
+
end
|
100
105
|
|
101
106
|
* Test doing facet count and result queries:
|
102
107
|
|
@@ -112,60 +117,71 @@ Start with a working Rails 3 application with a PostgreSQL database.
|
|
112
117
|
> Painting.where(["title like ?", 'Moon%']).count(:genre)
|
113
118
|
=> {"Impressionist"=>1}
|
114
119
|
|
115
|
-
* Add faceting webservices to your controller and define base() to indicate which model to base queries on
|
120
|
+
* Add faceting webservices to your controller and define base() to indicate which model to base queries on
|
116
121
|
|
117
|
-
|
118
|
-
|
122
|
+
{ ./app/controllers/paintings_controller }
|
123
|
+
class PaintingsController
|
124
|
+
include Repertoire::Faceting::Controller
|
119
125
|
|
120
|
-
|
121
|
-
|
122
|
-
|
126
|
+
def base
|
127
|
+
search = "%#{params[:search]}%"
|
128
|
+
Painting.where(["title like ?", search])
|
129
|
+
end
|
123
130
|
end
|
124
|
-
end
|
125
131
|
|
126
|
-
* Add faceting routes to your application.
|
132
|
+
* Add faceting routes to your application.
|
127
133
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
134
|
+
{ ./config/routes.rb }
|
135
|
+
|
136
|
+
PaintingsApp::Application.routes.draw do
|
137
|
+
faceting_for :paintings # NB must be BEFORE any resources!
|
138
|
+
...
|
139
|
+
end
|
132
140
|
|
133
141
|
Confirm they load:
|
134
142
|
|
135
143
|
$ rake routes
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
144
|
+
...
|
145
|
+
/paintings/counts/:facet(.:format) {:controller=>"paintings", :action=>"counts"}
|
146
|
+
paintings_results /paintings/results(.:format) {:controller=>"paintings", :action=>"results"}
|
147
|
+
...
|
140
148
|
|
141
|
-
* Load the javascript facet widgets in your main javascript file. The
|
142
|
-
|
149
|
+
* Load the javascript facet widgets in your main javascript file. The
|
150
|
+
repertoire-assets subsystem will locate the widgets in your application's
|
151
|
+
rubygems, and load them as appropriate.
|
143
152
|
|
144
|
-
|
153
|
+
{ ./public/javascripts/application.js }
|
145
154
|
...
|
146
155
|
//= require <rep.faceting>
|
147
156
|
...
|
148
157
|
|
149
|
-
|
150
|
-
|
158
|
+
N.B. Repertoire Faceting widgets are based on JQuery, which is incompatible
|
159
|
+
with Prototype. If you have not already done so, you should remove
|
160
|
+
prototype.js and rails.js from the javascripts directory, and delete the
|
161
|
+
"<%= javascript_include_tag :defaults %>" line from application.html.erb.
|
151
162
|
|
152
|
-
|
163
|
+
* Add facet count and result widgets to your HTML page. The facet context div
|
164
|
+
collects widgets that affect the same query together. (For complete options,
|
165
|
+
see the README )
|
153
166
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
167
|
+
{ ./app/views/paintings/index.html.erb }
|
168
|
+
|
169
|
+
<script language="javascript">
|
170
|
+
$().ready(function() {
|
171
|
+
$('#paintings').facet_context();
|
172
|
+
$('.facet').facet();
|
173
|
+
$('#results').results();
|
159
174
|
});
|
160
175
|
</script>
|
161
176
|
<div id='paintings'>
|
162
|
-
|
163
|
-
|
164
|
-
|
177
|
+
<div id='genre' class='facet'></div>
|
178
|
+
<div id='results'></div>
|
179
|
+
</div>
|
165
180
|
|
166
|
-
* If you don't already have one, create a partial for displaying your model in
|
181
|
+
* If you don't already have one, create a partial for displaying your model in
|
182
|
+
results lists.
|
167
183
|
|
168
|
-
|
184
|
+
{ ./app/views/paintings/_painting.html.erb }
|
169
185
|
|
170
186
|
<div class='painting' style='width:235px; margin-bottom:5px; padding:2px; border:dotted 1px;'>
|
171
187
|
<div>Title: <%= painting.title %></div>
|
@@ -173,29 +189,38 @@ Start with a working Rails 3 application with a PostgreSQL database.
|
|
173
189
|
<div>Genre: <%= painting.genre %></div>
|
174
190
|
</div>
|
175
191
|
|
176
|
-
* Configure the repertoire-assets module that loads the javascript
|
177
|
-
|
192
|
+
* [ Optional ] Configure the repertoire-assets module that loads the javascript
|
193
|
+
faceting widgets to compress the widget code in production.
|
178
194
|
|
179
|
-
|
180
|
-
...
|
181
|
-
config.repertoire_assets.compress = true
|
182
|
-
...
|
183
|
-
end
|
195
|
+
{ ./config/environments/production.rb }
|
184
196
|
|
185
|
-
|
186
|
-
|
197
|
+
PaintingsApp::Application.configure do
|
198
|
+
...
|
199
|
+
config.repertoire_assets.compress = true
|
200
|
+
...
|
201
|
+
end
|
187
202
|
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
203
|
+
* [ Optional ] Add bitset indexes to some facets on your model. The module will
|
204
|
+
automatically use facet indexes when they are available. Facet indexes scale
|
205
|
+
out of the box to over a million model items, and require no additional
|
206
|
+
configuration.
|
207
|
+
|
208
|
+
$ rails generate migration AddFacetIndex
|
209
|
+
|
210
|
+
{ ./db/migrate/<your date>add_facet_index.rb }
|
211
|
+
class AddFacetIndex < ActiveRecord::Migration
|
212
|
+
def self.up
|
213
|
+
Painting.update_indexed_facets([:genre])
|
214
|
+
end
|
215
|
+
|
216
|
+
def self.down
|
217
|
+
Painting.update_indexed_facets
|
218
|
+
end
|
219
|
+
end
|
192
220
|
|
193
|
-
|
194
|
-
Painting.update_indexed_facets
|
195
|
-
end
|
196
|
-
end
|
221
|
+
* [ Optional ] Periodically update indexes via a crontab task.
|
197
222
|
|
198
|
-
|
223
|
+
{ ./lib/tasks/update_facets.rake }
|
199
224
|
|
200
225
|
task :reindex_facets => :environment do
|
201
226
|
Painting.update_indexed_facets
|
data/README
CHANGED
@@ -1,3 +1,30 @@
|
|
1
|
+
== Deployment
|
2
|
+
|
3
|
+
* repertoire-assets compression
|
4
|
+
|
5
|
+
* deploying native extensions to server
|
6
|
+
|
7
|
+
* sub-uris
|
8
|
+
|
9
|
+
* do NOT use schema.rb with repertoire-faceting
|
10
|
+
|
11
|
+
|
12
|
+
== Running unit tests
|
13
|
+
|
14
|
+
You can run the unit tests from the module's root directory. You will need a
|
15
|
+
local PostgreSQL superuser role with your unix username (use 'createuser -Upostgres').
|
16
|
+
|
17
|
+
$ bundle install
|
18
|
+
$ rake db:faceting:build { sudo will prompt for your password }
|
19
|
+
$ rake db:create
|
20
|
+
$ rake test
|
21
|
+
|
22
|
+
|
23
|
+
== Known issues
|
24
|
+
|
25
|
+
- Running the unit tests issues warnings about a circular require. These can be ignored.
|
26
|
+
|
27
|
+
|
1
28
|
== Updating Indices
|
2
29
|
|
3
30
|
Depending on how frequently you need to update facet indices, there are several options.
|
@@ -11,7 +38,7 @@ Depending on how frequently you need to update facet indices, there are several
|
|
11
38
|
Nobelist.update_indexed_facets([:degree, :discipline])
|
12
39
|
end
|
13
40
|
|
14
|
-
|
41
|
+
Then configure your system-level crontab task to run 'rake reindex' at the required interval.
|
15
42
|
|
16
43
|
(2) Using Repertoire's postgresql-crontab functionality
|
17
44
|
|
@@ -37,7 +64,17 @@ Depending on how frequently you need to update facet indices, there are several
|
|
37
64
|
create a migration with the same calls as the rake task.
|
38
65
|
|
39
66
|
|
40
|
-
|
67
|
+
|
68
|
+
== Deployment
|
69
|
+
|
70
|
+
Because repertoire-faceting depends on a native shared library loaded by the
|
71
|
+
PostgreSQL server, the first time you deploy you will need to build and install
|
72
|
+
the extension.
|
73
|
+
|
74
|
+
<server>$ bundle install --deployment
|
75
|
+
<server>$ export RAILS_ENV=production
|
76
|
+
<server>$ rake db:facetinginstall
|
77
|
+
<server>$ rake db:facetingload
|
41
78
|
|
42
79
|
|
43
80
|
|
@@ -46,7 +83,7 @@ Rails3 documentation revisions
|
|
46
83
|
|
47
84
|
- requires ruby 1.9.2 (ordered hashes)
|
48
85
|
- include_root_in_json = false
|
49
|
-
- rake
|
86
|
+
- rake db:facetingpostgres:install, :load
|
50
87
|
|
51
88
|
To cover in the README:
|
52
89
|
|
@@ -89,145 +126,6 @@ API for faceted browsing within PostgreSQL, with extensions for Merb and jquery
|
|
89
126
|
- nested facet values kept as arrays
|
90
127
|
- update facet index (a) explicitly, (b) using Repertoire's crontab sweeper, or (c) both
|
91
128
|
|
92
|
-
|
93
|
-
===== Installation =====
|
94
|
-
|
95
|
-
-Proviso-. You must already have PostgreSQL installed, and pg_config should display the correct values for the version of postgres you intend to use.
|
96
|
-
|
97
|
-
1. Install the repertoire-faceting gem from source
|
98
|
-
[ once it's released open-source, this will be possible from github or rubyforge ]
|
99
|
-
|
100
|
-
2. Install Repertoire crontab support
|
101
|
-
[ see documentation for the repertoire-devtools gem for this ]
|
102
|
-
|
103
|
-
3. Load the faceting sql extensions into your project's database
|
104
|
-
|
105
|
-
- If your project shares the database with others (as in Repertoire), it's best to install by hand.
|
106
|
-
|
107
|
-
psql -Upostgres <your database> -f /opt/local/share/postgresql84/contrib/signature.sql
|
108
|
-
|
109
|
-
Note that the sql extensions are global to your entire database, since they land in the public schema.
|
110
|
-
|
111
|
-
- If your project owns the entire database, you can use a migration:
|
112
|
-
|
113
|
-
migration 1, :install_signature do
|
114
|
-
sharedir = /SHAREDIR = (.*)/.match(`pg_config`)[1] # e.g. "/opt/local/share/postgresql84"
|
115
|
-
|
116
|
-
up do
|
117
|
-
execute File.read("#{sharedir}/contrib/signature.sql")
|
118
|
-
end
|
119
|
-
down do
|
120
|
-
execute File.read("#{sharedir}/contrib/uninstall_signature.sql")
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
|
125
|
-
===== DataMapper extensions =====
|
126
|
-
|
127
|
-
*Setup*
|
128
|
-
|
129
|
-
-Proviso-. The faceting library does not yet support automigration. The best approach is to maintain your facet indices using
|
130
|
-
explicit migrations as your datamapper models change.
|
131
|
-
|
132
|
-
Make sure the columns you wish to facet over are indexed. For a complete description, see the section "PostgreSQL extensions." Simple example for use in a datamapper migration:
|
133
|
-
|
134
|
-
migration 5, :add_facet_indices do
|
135
|
-
up do
|
136
|
-
execute <<-SQL.compress_lines
|
137
|
-
INSERT INTO crontab(notice, role, task, interval)
|
138
|
-
VALUES ('Update Project facets', NULL, $$
|
139
|
-
SELECT renumber_table('project', '_packed_id');
|
140
|
-
SELECT recreate_table('_project_status_facet', 'SELECT status, signature(_packed_id) FROM project GROUP BY status');
|
141
|
-
$$, '5 minutes');
|
142
|
-
SQL
|
143
|
-
end
|
144
|
-
down do
|
145
|
-
execute <<-SQL.compress_lines
|
146
|
-
DELETE FROM crontab WHERE notice = 'Update Project facets';
|
147
|
-
SQL
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
A later version of this package may include generator macros to ease the task of defining new facet indices. However, this will
|
152
|
-
have to wait until DataMapper can reliably transform expressions like Project.all(:field => 'science').status into a single SQL join query (currently it issues two queries in turn). Until then, the SQL expressions must be produced by hand.
|
153
|
-
|
154
|
-
*In your model*
|
155
|
-
|
156
|
-
= declaring facets:
|
157
|
-
|
158
|
-
class Project
|
159
|
-
is :faceted, :genre,
|
160
|
-
:published => :nested, # default :logic for this facet
|
161
|
-
:birthdate => :nested
|
162
|
-
[ etc. ]
|
163
|
-
end
|
164
|
-
|
165
|
-
[ N.B. your facets don't have to be DataMapper properties! they can be any SQL computed value. this merely names the facets -
|
166
|
-
definitions belong in a database migration. ]
|
167
|
-
|
168
|
-
*In your controller*
|
169
|
-
|
170
|
-
= to do a facet value count [ facet indices are used automatically where available ]
|
171
|
-
|
172
|
-
Film.facet_count(:location, :genre => 'tragedy', :published => [2008, 11], :title.like => '%Death%', :order => [:location, :count.desc] )
|
173
|
-
|
174
|
-
# provides facet to count, facet filter selections, a base query, and order for the facet value counts. you can also specify
|
175
|
-
# :minimum, :offset, :limit, :type, and :nullable. see the specs for usage
|
176
|
-
|
177
|
-
= to do a facet results query [ facet indices are used automatically where available ]
|
178
|
-
|
179
|
-
Film.facet_results(:genre => 'tragedy', :published => [2008, 11], :title.like => '%Death%', :order => [:title, :author], :offset => 0, :limit => 20)
|
180
|
-
|
181
|
-
# to alter the way that a facet is refined, provide :logic (options are :or, :and, :nested; default is :and)
|
182
|
-
Film.facet_results(:genre => ['tragedy', 'comedy'], :published => [2008, 11],
|
183
|
-
:logic => { :genre => :or, :published => :nested })
|
184
|
-
|
185
|
-
|
186
|
-
===== Merb extensions =====
|
187
|
-
|
188
|
-
in controller...
|
189
|
-
|
190
|
-
def counts(facet, search, filter={})
|
191
|
-
provides :js
|
192
|
-
counts = Project.facet_count(facet, :refinements => filter, :conditions => ["_fulltext @@ to_tsquery(?)", search])
|
193
|
-
display counts
|
194
|
-
end
|
195
|
-
|
196
|
-
def results(search, filter={})
|
197
|
-
provides :html
|
198
|
-
results = Project.facet_result(:refinements => filter, :conditions => ["_fulltext @@ to_tsquery(?)", search])
|
199
|
-
display results
|
200
|
-
end
|
201
|
-
|
202
|
-
in routes...
|
203
|
-
|
204
|
-
match('/:controller/counts/:facet').to(:action => 'counts')
|
205
|
-
match('/:controller/results').to(:action => 'results')
|
206
|
-
|
207
|
-
in view.... (index.html.erb): (make sure to load rep.faceting.js in your header)
|
208
|
-
|
209
|
-
<script language='javascript'>
|
210
|
-
$().ready(function() {
|
211
|
-
$('#plays').facet_context();
|
212
|
-
$('.facet').facet();
|
213
|
-
$('.nested_facet').nested_facet();
|
214
|
-
$('#results').results();
|
215
|
-
});
|
216
|
-
</script>
|
217
|
-
...
|
218
|
-
<div id='plays'>
|
219
|
-
<div id='genre' class='facet'></div>
|
220
|
-
<div id='published' class='nested_facet'></div>
|
221
|
-
<div id='results' class='facet'></div>
|
222
|
-
</div>
|
223
|
-
|
224
|
-
The facet count data is served via JSON from the URL defined by the routes and method signatures above. The webservice URL
|
225
|
-
is derived from the element ids (e.g. '/plays/counts/genre' above), or set via the 'url' option.
|
226
|
-
|
227
|
-
For a complete description of how to use the ajax widgets, their options, and how to write new widgets that extend the base
|
228
|
-
functionality, see the in-line documentation in rep.faceting.js and its associated FAQ.
|
229
|
-
|
230
|
-
|
231
129
|
===== PostgreSQL extensions =====
|
232
130
|
|
233
131
|
= The following code leads you through an example of the SQL calls to set up and execute
|
data/TODO
CHANGED
@@ -1,7 +1,17 @@
|
|
1
1
|
TODO
|
2
2
|
|
3
|
+
- make rake tasks smarter about detecting whether to run NOT NECESSARY
|
4
|
+
- make rake tasks automatically choose task dep on db type NOT TO DO
|
5
|
+
|
6
|
+
- make sure example app can be set up and deployed via rake DONE
|
7
|
+
- fulltext indexing for citizens in migration
|
8
|
+
|
9
|
+
- facet index for citizens... migration or rake task?
|
10
|
+
- gender not getting generated right
|
11
|
+
|
3
12
|
- README
|
4
|
-
* recipe for running tests
|
13
|
+
* recipe for running tests DONE
|
14
|
+
* deployment
|
5
15
|
* recipe for adding facets to new app DONE
|
6
16
|
* declaring facets DONE
|
7
17
|
* faceting db api DONE
|
@@ -21,7 +31,6 @@ TODO
|
|
21
31
|
- get rid of annoying load warnings on test KNOWN ISSUE
|
22
32
|
- cannot refine on null values in facets KNOWN ISSUE
|
23
33
|
|
24
|
-
|
25
34
|
- integration with postgresql crontab
|
26
35
|
- push compiled gems to gemcutter DONE (EXCEPT FACETING)
|
27
36
|
|
data/ext/README.signature
CHANGED
@@ -25,8 +25,8 @@
|
|
25
25
|
-- Installation
|
26
26
|
--
|
27
27
|
-- (1) gem install repertoire-faceting
|
28
|
-
-- (2) rake faceting:
|
29
|
-
-- (3) rake faceting:
|
28
|
+
-- (2) rake db:faceting:install
|
29
|
+
-- (3) rake db:faceting:load
|
30
30
|
--
|
31
31
|
-- The bitset PostgreSQL extension follows standards for C-language extensions:
|
32
32
|
-- http://www.postgresql.org/docs/current/static/xfunc-c.html
|
data/ext/signature.sql.IN
CHANGED
@@ -265,16 +265,20 @@ END;
|
|
265
265
|
$$ LANGUAGE plpgsql;
|
266
266
|
|
267
267
|
|
268
|
-
-- Utility function to measure how many
|
269
|
-
--
|
268
|
+
-- Utility function to measure how many bits from a loosely-packed id column would be wasted,
|
269
|
+
-- if they were all collected into a bitset signature. Returns a float between 0 (no waste)
|
270
|
+
-- and 1.0 (all waste).
|
270
271
|
--
|
271
272
|
CREATE OR REPLACE FUNCTION signature_wastage(tbl TEXT, col TEXT) RETURNS REAL AS $$
|
272
273
|
DECLARE
|
273
|
-
|
274
|
+
max REAL;
|
275
|
+
count REAL;
|
274
276
|
BEGIN
|
275
|
-
EXECUTE 'SELECT
|
276
|
-
INTO
|
277
|
-
|
277
|
+
EXECUTE 'SELECT count(*) FROM ' || quote_ident(tbl)
|
278
|
+
INTO count;
|
279
|
+
EXECUTE 'SELECT max(' || quote_ident(col) || ') FROM ' || quote_ident(tbl)
|
280
|
+
INTO max;
|
281
|
+
RETURN 1.0 - (count / (COALESCE(max, 0) + 1));
|
278
282
|
END;
|
279
283
|
$$ LANGUAGE plpgsql;
|
280
284
|
|
@@ -39,6 +39,18 @@ module Repertoire
|
|
39
39
|
execute(sql)
|
40
40
|
end
|
41
41
|
|
42
|
+
# Load PostgreSQL native bitset type into current database
|
43
|
+
def load_faceting
|
44
|
+
sql = File.read(Repertoire::Faceting::MODULE_PATH + '/ext/signature.sql')
|
45
|
+
unload_faceting
|
46
|
+
execute(sql)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Unloads PostgreSQL native bitset type
|
50
|
+
def unload_faceting
|
51
|
+
execute("DROP TYPE IF EXISTS signature CASCADE")
|
52
|
+
end
|
53
|
+
|
42
54
|
# Expands nested faceting for the specified table (once)
|
43
55
|
def expand_nesting(table_name)
|
44
56
|
sql = "SELECT expand_nesting('#{table_name}')"
|
@@ -76,6 +88,15 @@ module Repertoire
|
|
76
88
|
"INNER JOIN members(#{exprs.join(' & ')}) AS _refinements_id ON (#{table_name}.#{faceting_id} = _refinements_id)"
|
77
89
|
end
|
78
90
|
|
91
|
+
private
|
92
|
+
|
93
|
+
def ignoring_db_errors(&block)
|
94
|
+
begin
|
95
|
+
yield
|
96
|
+
rescue
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
79
100
|
end
|
80
101
|
end
|
81
102
|
end
|
@@ -174,6 +174,7 @@ module Repertoire
|
|
174
174
|
|
175
175
|
# re-create the facet indices
|
176
176
|
facet_names.each do |name|
|
177
|
+
name = name.to_sym
|
177
178
|
raise "Unknown facet #{name}" unless facet?(name)
|
178
179
|
facets[name].create_index('_packed_id')
|
179
180
|
end
|
@@ -193,8 +194,6 @@ module Repertoire
|
|
193
194
|
connection.signature_wastage(table_name, col)
|
194
195
|
end
|
195
196
|
|
196
|
-
|
197
|
-
|
198
197
|
def should_unpack?
|
199
198
|
(faceting_id == '_packed_id') && (signature_wastage('id') < 0.15)
|
200
199
|
end
|
data/lib/repertoire-faceting.rb
CHANGED
@@ -5,6 +5,8 @@ require 'repertoire-assets'
|
|
5
5
|
module Repertoire
|
6
6
|
module Faceting
|
7
7
|
|
8
|
+
MODULE_PATH = File.expand_path('../../', __FILE__)
|
9
|
+
|
8
10
|
module Relation
|
9
11
|
autoload :SpawnMethods, 'repertoire-faceting/relation/spawn_methods'
|
10
12
|
autoload :QueryMethods, 'repertoire-faceting/relation/query_methods'
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 5
|
8
|
-
-
|
9
|
-
version: 0.5.
|
8
|
+
- 2
|
9
|
+
version: 0.5.2
|
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-
|
17
|
+
date: 2010-10-28 00:00:00 +01:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -124,7 +124,8 @@ files:
|
|
124
124
|
- lib/repertoire-faceting/relation/query_methods.rb
|
125
125
|
- lib/repertoire-faceting/relation/spawn_methods.rb
|
126
126
|
- lib/repertoire-faceting/routing.rb
|
127
|
-
- lib/repertoire-faceting/tasks.rake
|
127
|
+
- lib/repertoire-faceting/tasks/all.rake
|
128
|
+
- lib/repertoire-faceting/tasks/client.rake
|
128
129
|
- lib/repertoire-faceting/version.rb
|
129
130
|
- lib/repertoire-faceting.rb
|
130
131
|
- public/images/repertoire-faceting/proportional_symbol.png
|
@@ -149,7 +150,7 @@ has_rdoc: true
|
|
149
150
|
homepage: http://github.com/repertoire/repertoire-faceting
|
150
151
|
licenses: []
|
151
152
|
|
152
|
-
post_install_message: " ********************************************************************************\n If this is the first time you have installed Repertoire faceting, you need\n to build and install the native PostgreSQL extension:\n\n cd <my-rails-app>\n rake faceting:
|
153
|
+
post_install_message: " ********************************************************************************\n If this is the first time you have installed Repertoire faceting, you need\n to build and install the native PostgreSQL extension:\n\n cd <my-rails-app>\n rake db:faceting:build\n \n See the repertoire-faceting README for details.\n ********************************************************************************\n"
|
153
154
|
rdoc_options: []
|
154
155
|
|
155
156
|
require_paths:
|
@@ -1,29 +0,0 @@
|
|
1
|
-
require 'pathname'
|
2
|
-
|
3
|
-
namespace :faceting do
|
4
|
-
|
5
|
-
namespace :postgres do
|
6
|
-
dir = Pathname(__FILE__).dirname.expand_path + '../../ext'
|
7
|
-
|
8
|
-
desc "Load bitset functions into a specific database"
|
9
|
-
task :load => :install do
|
10
|
-
puts "\nDatabase name?"
|
11
|
-
db_name = $stdin.gets.chomp
|
12
|
-
sharedir = `pg_config --sharedir`.chomp
|
13
|
-
system "psql -Upostgres -f #{sharedir}/contrib/signature.sql #{db_name}"
|
14
|
-
end
|
15
|
-
|
16
|
-
desc "Build and install PostgreSQL native bitset type"
|
17
|
-
task :install => :build do
|
18
|
-
puts "Installing native extensions..."
|
19
|
-
system "cd #{dir}; sudo make install"
|
20
|
-
end
|
21
|
-
|
22
|
-
task :build do
|
23
|
-
puts "Building native extensions..."
|
24
|
-
system "cd #{dir}; sudo make"
|
25
|
-
end
|
26
|
-
|
27
|
-
end
|
28
|
-
|
29
|
-
end
|